react + webpack(직접설정) 을 사용하여 개발을 하고 있었고
react-router-dom을 통해 프론트에서의 라우터를 관리해주고 있었다.
다른 문서 작성을 위해 테스트 하던중에 이상한 점을 발견했다.
해당 url 접근시 페이지가 없을 경우 404 페이지를 띄워주고 싶었는데
cra + react-router-dom을 이용한 프로젝트에서는 문서대로 처리가 가능했고
직접 webpack을 세팅해준 프로젝트에서는 위와 같은 화면이 노출되고 있었다.
https://reactrouter.com/docs/en/v6/getting-started/overview#not-found-routes
정답은 webpack의 devServer 설정에 있었다.(정확히 말하면 index파일의 경로 설정을 잘못해주었다.....)
아래는 직접 설정했던 devServer의 설정이다. (이 코드에서 변경을 해주어야 위의 문제가 사라진다)
devServer: {
hot: true, // HMR(Hot Module Replacement가 가능하게 할건지)
open: true, // devServer가 켜지면서 브라우저창을 띄울것인지
port: 3000, // port 설정
static: { // 정적파일 접근 경로
directory: path.join(__dirname, 'src'),
},
historyApiFallback: { index: 'index.html' },
},
해결 과정을 먼저 살펴보자!!
해결을 위해서
1. cra에서 사용하는 webpack devServer의 세팅을 직접 눈으로 확인하였고
2. 1번에서의 코드를 문제가 있는 프로젝트에 적용해보니 이상이 없었다.
3. webpack에서의 devServer 문서를 확인하였다.
4. devServer에 대해 공부를 시작했고
5. webpack으로 공부범위를 확장했다.
하나씩 살펴보자
1. cra에서 사용하는 webpack devServer의 세팅을 직접 눈으로 확인하였고
// react-scripts/config/webpackDevServer.config.js
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
index: paths.publicUrlOrPath,
},
위의 코드는 cra에 설정되어 있는 webpackDevServer의 config file중 historyApiFallback에 관한 내용만 가져온 것이다.
내가 설정했던 내용과 다르다. 좀 더 살펴보도록 하자
2. 1번에서의 코드를 문제가 있는 프로젝트에 적용해보니 이상이 없었다.
위의 사진들은 cra의 historyapifallback 설정에서 index를 달리하고나서 서버를 실행했을때 콘솔에 찍힌 로그이다.
404s will fallback to 가 눈에 띄었다. 좀 더 살펴보도록 하자.
우선 위의 사진을 참고하여 기존 설정에서 index: 'index.html' -> index: '/index.html'로 해주니 원하는 동작대로 실행이 되었다.
3. webpack에서의 devServer문서를 확인하였다.
https://webpack.js.org/configuration/dev-server/#devserverhistoryapifallback
핵심만 짚어보자면
devserver의 historyApiFallback 옵션에서 index는 404가 발생했을때 이동시켜주는 페이지를 설정하는 옵션이다.
index가 undefinded로 설정되어있거나
historyApiFallback: true로 설정을 해주면 정적파일 접근 경로/index.html 로 자동으로 이동시켜준다.
경로의 기준은 static 파일 접근 경로에서 설정을 해준다.
static: { // 정적파일 접근 경로
directory: path.join(__dirname, 'src'),
},
공식문서 내에서도 다음과 같이 안내하고 있다.
html5의 history api를 사용할때 devServer.historyApiFallback을 true로 세팅해줌으로써 404 응답시 index.html을 응답해주도록 할수 있습니다.
module.exports = { //... devServer: { historyApiFallback: true, }, };
path에서 .(dot)을 사용하고 싶으면(Angular에서 흔한 경우) disableDotRule 옵션을 이용해야 할수도 있습니다.module.exports = { //... devServer: { historyApiFallback: { disableDotRule: true, }, }, };
* 여기서 한가지 의구심이 들었다. 404페이지로 이동시켜준 후에 경우에 따라 react-router-dom에서 설정한 경로의 404 페이지에 대한 처리가 되거나 되지 않았다. 왜 그럴까??
- webpack의 Entry에서 그 해답을 찾을 수 있었다.
https://webpack.js.org/configuration/entry-context/#entry
webpack의 entry 옵션은 webpack의 building process를 시작하는 곳을 알려준다.
entry: {
app: './src/index.tsx',
},
앞에 키값을 확인할 수 있는데 키값은 build파일에서 파일명의 앞에 붙는다.
404가 발생한 경우 404페이지로 webpack에서 이동을 시킬것이다.
404 페이지로 이동을 한 후에 entry에 있는 index.tsx 파일이 실행될 것이다.
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import './assets/styles/index.css';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
(browserrouter는 html5의 historyapi를 이용하여(replaceState, pushState) 현재 url과 ui를 맞추기 위해 사용하는 react-router-dom의 router 입니다.)
이때 404페이지에 root id를 가진 dom이 있다면 index.tsx파일이 정상적으로 실행이 될것이고 없으면 정상적인 동작이 불가능 할것이다.
테스트를 위해 root id를 가진 404페이지를 생성후 404페이지로 이동시켜보자.
1. 먼저 webpack의 plugins에서 404페이지를 추가해주자 (plugins에서 추가를 해주어야 404페이지에 접근이 가능하다)
devServer: {
hot: true,
open: true,
port: 3000,
static: {
directory: path.join(__dirname, 'src'),
},
historyApiFallback: { index: '/test.html' },
},
plugins: [
new HtmlWebpackPlugin({
filename: './index.html',
template: './src/index.html',
inject: true,
minify: false,
}),
new HtmlWebpackPlugin({ // 404 페이지
filename: './test.html',
template: './src/test.html',
inject: true,
minify: false,
}),
]
// 404 페이지
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
1231312312
<div id="root"></div>
</body>
</html>
404 페이지로 이동후 결과
1번 이미지는 404 페이지의 dom에 id root를 가진 객체가 존재하는 상황
2번 이미지는 404 페이지의 dom에 id root를 가진 객체가 존재하지 않는 상황
이로써 404페이지로 이동후에 webpack의 entry내의 파일이 재빌드 되어 실행되는 것을 확인해 보았다.(혹시 틀린 내용이 있으면 알려주세요!!)
4. devServer에 대해 공부를 시작했고
devServer는 개발시에 유용하게 쓰이는 도구입니다. 어떤 기능 때문에 개발시에 유용하게 쓰일까요?
* HMR(Hot Module Replacement)를 지원해 줍니다.
webpack-dev-server에서는 매번 빌드 파일을 생성하지 않고 빌드 결과를 메모리에 저장합니다.
웹팩의 빌드 대상 파일이 변경되면 매번 빌드 명령을 실행하지 않아도 웹팩으로 빌드한 후 브라우저를 새로고침 해줍니다.
매번 빌드 파일을 생성후에 해당 파일에 접근해야 하는 것보다. 메모리에 적재를 해놓고 접근을 하는것이 속도상의 이점이 매우 큽니다.
(메모리의 존재를 도마에 비유하겠습니다. 우리가 요리를 할때 매번 냉장고에서 재료를 꺼내와서 재료 손질을 해야한다면 냉장고에 다녀오는 시간이 포함되고 처리속도는 느려질수 밖에 없습니다. 요리 재료들을 도마위에 올려놓고 손질을 시작한다면 이동시간은 줄어들고 매번 냉장고에 갔다와서 처리를 하는 것보다는 비약적으로 빨라질것입니다.)
* 옵션을 통해 https, ws, proxy 설정등을 개발 환경에서 이용할 수 있습니다.
실행 과정
1. 서버가 실행되면 소스파일들을 번들링하여 메모리에 올립니다.
2. 소스파일중 일부가 변경되면 변경된 부분만 새로 번들 합니다.
3. 브라우저에서 변경된 부분을 reload 해줍니다.
궁금했던 proxy 설정만 간략히 알아보겠습니다.
proxy는 영어로 '대리의' 라는 뜻입니다. 무엇인가를 대신 해준다는 뜻입니다.
위 이미지의 경우 Cors(Cross Origin Resourse Sharing)이 발생하여 요청에 백엔드는 응답하지 않습니다.
Cors는 쉽게 말해 도메인이 다른 경우 js로 요청을 보낼수 없다는 것을 의미합니다.
Cors는 브라우저에 구현되어 있는 스펙입니다.
서버에서 응답을 주더라도 브라우저에서 다른 도메인이라고 판단하면 해당 응답에 cors에러를 노출시켜줍니다.
우선 제가 알고 있는 방법은
서버에서 응답 헤더의 Access-Control-Allow-Origin에 요청한 프론트에서의 도메인을 추가해주거나 wildcard를 추가해주면
브라우저에서 해당 value 값과 요청한 도메인을 비교하여 맞으면 통과 / 틀리면 cors를 뱉어냅니다.
webpack-dev-server의 proxy 설정을 통해 서버에서 서버로의 요청과 같이 우회할 수 있습니다.
module.exports = {
devServer: {
proxy: {
'/api': 'api.woobottle.com'
}
}
}
위의 설정을 통해 아래와 같은 흐름을 구현할 수 있습니다
1. 브라우저에서는 api.woobottle.com으로 요청을 보내지만
2. 실제 백엔드로 요청이 가지는 않고 개발 서버로 가게 됩니다.
3. 개발 서버에서는 백엔드로 요청을 보내고
4. 응답을 받은 개발서버는 이를 브라우저로 보내줍니다.
5. webpack으로 공부범위를 확장했다.
웹팩은 모듈 번들러 입니다.
bundle이란 묶음이란 뜻을 가지고 있습니다. 모듈들을 묶어주는 것이 웹팩이라고 할수 있겠네요.
html, css, js, image 등등 웹 페이지에 필요한 모든 것 을 모듈로 보고 이를 묶어줍니다. 하나의 결과물로 만들어주는 것이죠.
entry에 설정된 파일을 시작으로 필요한 파일들이 있으면 의존성이 형성되고 의존성을 가진 것들을 한개 이상의 번들로 생성해 줍니다.
웹팩에 대한 내용은 따로 포스팅 할 수 있도록 하겠습니다!
https://dkrnfls.tistory.com/181
https://joshua1988.github.io/webpack-guide/devtools/webpack-dev-server.html#webpack-dev-server
https://poiemaweb.com/devServer
'Frontend > React' 카테고리의 다른 글
제어 컴포넌트 vs 비제어 컴포넌트 (0) | 2022.03.03 |
---|---|
React twice render (0) | 2022.02.24 |
cra + typescript + jest (0) | 2022.02.23 |
넘블챌린지 [Square Select Game] (0) | 2022.02.10 |
cra typescript 초간단 세팅 (0) | 2022.01.17 |