https://github.com/joohaem/boilerplate-webpack-without-cra
Webpack이란?
JS 모듈을 파일 단위로 관리하다 보니, 자연스레 파일이 많아지게 된다
한 편, 브라우저에는 한 번에 보낼 수 있는 HTTP 요청 수의 제한이 있기 때문에,
이를 묶어 처리하는 번들러 라이브러리(Webpack, Parcel 등)가 필요해졌다
그 중 가장 인기 있는 모듈 번들러 중 Webpack 이 있고
이를 세팅하는 코드를 정리해놓았다
시작하기
$ yarn init -y
// All Yes
$ yarn add react react-dom
// npm으로 설치한 react와 react dom을 불러오게 되면
// CDN으로 파일(react, babel)을 불러오지 않아도 된다.
$ yarn add -D @babel/core babel-loader @babel/preset-env @babel/preset-react
// @babel/core: babel의 핵심 라이브러리로 es6를 es5로 컴파일
// babel-loader: babel과 webpack을 사용해서 자바스크립트 파일을 컴파일
// @babel/preset-env: es6, es7 버전을 지정안해도 babel이 자동 탐지
// @babel/preset-react: 리액트(JSX)를 js로 인식가능
$ yarn add -D webpack webpack-cli webpack-dev-server
// webpack-cli - 웹팩을 커맨드라인에서 실행할 수 있게 해 줌
// webpack-dev-server - 파일이 변화할 때마다 실시간으로 빌드하는 개발 서버 구동 (우리가 실행하는 dev 서버)
$ yarn add -D babel-loader css-loader style-loader
// babel-loader - jsx 파일과 최신 자바스크립트 문법을 변환(바벨과 연동)
// css-loader - css 파일을 해석(import or require)
// style-loader - css를 dom(style 태그로 head)에 삽입
$ yarn add html-webpack-plugin
// html-webpack-plugin - html 파일에 번들링 된 js 파일을 삽입
Webpack 및 Babel 설정
.babelrc 파일 생성
// 바벨에 대한 플러그인을 설정,
// presets(번들 파일)에 한번만 설정하면 플러그인들이 자동으로 설치
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
webpack.config.js 파일 생성
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const port = process.env.PORT || 3000;
module.exports = {
// development 모드는 개발자 경험에 초점이 맞춰진 모드
// production모드는 배포에 초점이 맞춰진 모드
mode: "development",
// filename의 [hash]는 어플리케이션이 수정되어
// 다시 컴파일될 때마다 Webpack(웹팩)에서 생성된 해시로 변경해 캐싱
// build 시 확인 가능
// entry가 하나여야, SPA 임
// entry:'./src/index.js', 설정 기본값
output: {
path: __dirname + "/dist",
filename: "bundle.[hash].js",
},
module: {
rules: [
// 첫 번째 룰
// .babelrc를 babel-loader를 이용해 규칙에 적용
{
test: /\\.(js)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
// 두 번째 룰
{
test: /\\.css$/,
use: ["style-loader", "css-loader"],
// 각 로더에 옵션 적용 가능
// 좌 <- 우 순서로 적용되기 때문에 위와 같은 순으로 작성해주어야 함
},
],
},
plugins: [
// HtmlWebpackPlugin은 html파일이나 favicon을 번들링과정에 포함
// 예를들어 번들된 파일 bundle.[hash].js를 index.html에 자동 삽입
new HtmlWebpackPlugin({
template: "public/index.html",
}),
],
// 개발 서버 정의
devServer: {
host: "localhost",
port: port,
// 서버 실행 시 자동으로 브라우저 열어주는 옵션
open: true,
// 브라우저에서 URL 변경하도록 도와주는 옵션
historyApiFallback: true,
},
};
- webpack.config.js, CRA의 다양한 옵션들
(참고 : https://berkbach.com/create-react-app-%EC%9D%98-webpack-config-js-%EB%93%A4%EC%97%AC%EB%8B%A4%EB%B3%B4%EA%B8%B0-78e40bf37313)- mode: webpack에게 현재 모드를 알려주는 옵션이다.
production은 최적화되어 빌드되고,
development는 (최적화 없이) 빠르게 빌드된다. - entry: 앱을 번들할 때 시작 경로를 정의한다.
배열로 받을 경우 시작시 모든 모듈이 하나의 파일로 합쳐 로드된다. - output: 번들을 완료한 파일을 설정한다.
이에 있는 정보를 통해 빌드 파일을 생성한다.
path 는 파일을 저장할 경로 입니다.
pathinfo 는 모듈에 관련된 내용을 주석으로 표시합니다.
production 일 때는 안하는 것이 좋습니다.
filename 은 번들을 완료한 파일의 이름을 정의합니다.
futureEmitAssets 는 webpack-5 에서 없어진다고 하니 중요하지 않아보여서 넘어 가겠습니다.
chunkFilename 은 청크 파일의 이름을 정의합니다.
publicPath 는 브라우저에서 참조될때 출력 파일의 공용 URL 주소를 지정합니다.
devtoolModuleFilenameTemplate 은 source-map의 소스 배열을 커스터마이징 합니다.
jsonpFunction 는 여러 개의 webpack이 작동할 때 충돌을 막기위해 설정합니다.
globalObject 는 전역변수를 설정하는 부분입니다.
기본 값은 window 입니다. - module: loader 를 설정하는 부분입니다.
strictExportPresence 는 경고 대신 에러를 보냅니다.
rules 로 loader를 설정합니다.
이는 번들링 과정에서 사용할 규칙을 설정합니다. - plugins: plugin을 설정합니다.
- devServer: 개발 서버를 정의하는 옵션입니다.
- resolve: 이 옵션은 모듈을 해석하는데 관여합니다.
모듈을 해석할 때 modules 로 먼저 탐색할 폴더를 지정할 수 있습니다.
extensions 로 .ts , .jsx 와 같은 확장자를 관리할 수 있습니다.
여기서는 paths.js/moduleFileExtensions 로 관리하고 있습니다.
alias 는 모듈에 별명을 주어서 간단하게 import , require 를 할 수 있습니다.
plugins 는 모듈 해석에 대한 plugin 입니다. - bail: True 일 경우 첫 번째 오류를 허용합니다.
여기서는 production 일 때만 허용합니다. - devtool: 어떤 source-map 을 사용할지 결정하는 부분입니다.
source-map 이란 원본 코드와 빌드된 코드를 매핑 해주는 방법입니다.
CRA 에서는 production 일 때는 source-map , development 일 때는 cheap-module-source-map 을 사용하는군요.
근데 source-map 를 넣었을 때 원본 코드가 드러나는 경우가 있어서 source map 을 안쓰는 사람도 있습니다.
또 쓰더라도 source-map 의 성능이 안 좋아서 source-map 대신 cheap-module-source-map 를 사용하는 경우도 있습니다. - optimization: webpack 4 부터 mode 에 따라서 설정이 가능해졌습니다.
minimize 는 TerserPlugin 이나 minimizer 에 따로 정의된 plugin 을 사용해서 번들한 파일을 최소화 할지 결정합니다.
minimizer 는 TerserPlugin 을 커스터마이징 하거나 기본 값으로 minimize 에 사용될 minimizer 를 설정합니다.
여기서는 TerserPlugin 커스터마이징과 OptimizeCSSAssetsPlugin 을 추가해서 사용했네요.
splitChunks 는 청크 파일에서 중복되는 모듈을 모으는 역할을 합니다.
runtimeChunk 를 true 나 설정을 하면 런타임만 포함하는 각 진입점에 청크가 추가됩니다. - resolveLoader: resolve 와 같은 속성을 갖지만 resolveLoader는 loader 모듈만 해석합니다.
- node: 노드 객체를 설정합니다.
true, false, empty, mock 값으로 객체를 설정할 수 있습니다.
true 는 polyfill 을 제공합니다.
false 는 어떤 것도 반환하지 않습니다.
empty 는 빈 객체, mock 은 mock 객체를 반환합니다.
- mode: webpack에게 현재 모드를 알려주는 옵션이다.
index, App 파일 생성
src/index.js
// import React from "react";
// import ReactDom from "react-dom";
// import App from "./App";
const React = require("react");
const ReactDom = require("react-dom");
const { default: App } = require("./App");
ReactDom.render(<App />, document.querySelector("#root"));
src/App.js
import React from "react";
import "./App.css";
export default function App() {
return (
<div className="main_wrapper">
Hello, World !!
</div>
);
}
src/App.css
.main_wrapper {
color: rgb(224, 75, 113);
}
에러 짚기
Module not found: Error: Can't resolve './src/index.js'
Module not found: Error: Can't resolve './App’
: jsx 를 js 로 변환해주지 못하기 때문에, ./src/index.js / App.js로 명명해야 한다
이는 파일명을 수정하거나, 다음 코드를 추가하여 해결할 수 있다
resolve: {
extensions: ['.js', '.jsx'],
},
Uncaught ReferenceError: main_wrapper is not defined
: style-loader 와 css-loader 가 적용되지 않는 것 같았다,
다음과 같이 해결하였다
(공식 문서: https://webpack.js.org/loaders/style-loader/)
// webpack.config.js
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
// CSS Module, CamelCase 사용
modules: true,
camelCase: true,
},
},
],
// 위 코드를 아래와 같이 수정
use: ["style-loader", "css-loader"],
react-hot-loader
코드가 변경되었을 때 페이지를 새로고침 하지 않고
바뀐 부분만 빠르게 교체해주는 라이브러리
$ yarn add -D react-hot-loader
// .babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["react-hot-loader/babel"]
}
// webpack.config.js
...
module.exports = {
...
output: {
...
publicPath: '/'
// Hot reloading은 중첩된 경로에서 동작하지 않아
// 설정해주지 않을 경우 Hot reloading이 작동이 안 됨
},
};
// App.js
import { hot } from 'react-hot-loader';
...
export default hot(module)(App);
글을 줄이며
위 본문은 정말 기본적인 사항들만 있지만, 웹팩 설정은 정말 무궁무진하다
동료와 이야기를 나누며
CRA의 웹팩 설정을 살펴보기(참고 : https://maxkim-j.github.io/posts/cra-webpack-config) ...
에서 멈출 것이 아니라 이를 custom 하는 방향이 필요하겠다 싶었다
CRA 정말 간단하고 좋지만 그만큼 무게도 상당하기에!
CRA의 custom을 위한 키워드는 다음과 같다
- CRA yarn eject
(숨겨져 있던 모든 설정들과 패키지들의 의존성들을 볼 수 있다,
그러나 이전 상태로 돌아갈 수 없고 config들을 직접 유지보수 해야하게 된다) - customize-cra / react-app-rewired
(eject 없이 custom 할 수 있도록 하는 라이브러리) - typescript custom / terserplugin / ...
차차 공부해보도록 하자
참고 문서
https://nukw0n-dev.tistory.com/25?category=979146
https://webpack.js.org/configuration/
https://github.com/ingong/react-boilerplate-session ( 커스텀 로더 / 에셋 모듈 )
'Web.d' 카테고리의 다른 글
[React][Context] Prop drilling 과 useContext (2/2) (1) | 2022.03.30 |
---|---|
[Javascript] React 와 불변성의 관계 요약정리 (1) | 2022.03.29 |
[React][css] 마우스 hover 시에 svg 보이기 (0) | 2022.03.13 |
[React][Javascript] 뒤로 가기 막기 / 창 닫기 막기 / 새로고침 막기 (2) | 2022.03.02 |
[React][비교] SWR vs React Query vs Recoil selector ? (0) | 2022.02.18 |