개인 프로젝트는 CRA 없이 웹팩을 직접 설정해서 진행하기로 했습니다.
📍웹팩의 핵심 개념
- Entry: 웹팩을 실행할 대상 파일. 진입점
- Output: 웹팩의 결과물에 대한 정보를 입력하는 속성. 일반적으로 filename과 path를 정의
- Loader: CSS, 이미지와 같은 비 자바스크립트 파일을 웹팩이 인식할 수 있게 추가한다. 로더는 오른쪽에서 왼쪽 순으로 적용
- Plugin: 웹팩의 기본적인 동작에 추가적인 기능을 제공한다. 로더는 파일을 해석하고 변환하는 과정에 관여하는 반면, 플러그인은 해당 결과물의 형태를 바꾸는 역할을 한다.
- Resolve: 웹팩에서 모듈을 해석할 때 어떤 확장자를 사용할지를 설정한다. resolve 옵션을 설정하면, import나 require 등으로 모듈을 불러올 때 해당 확장자를 생략할 수 있다.
- Optimization: 웹팩에서 제공하는 최적화 설정 옵션. 이를 통해 웹팩 빌드 결과물의 파일 크기를 줄이고, 빌드 시간을 단축할 수 있다.
- DevServer: 옵션은 웹팩에서 제공하는 개발용 서버를 설정할 때 사용된다. 개발용 서버를 사용하면, 코드 수정 시 자동으로 빌드를 수행하고 브라우저를 새로고침하여 변경된 내용을 보여줄 수 있다.
📍webpack.config
다음과 같이 webpack.config.js 파일을 설정했는데 각 옵션별로 어떤 고민을 했는지 정리해보았습니다.
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const path = require("path");
const isDevelopment = process.env.NODE_ENV !== "production";
module.exports = {
mode: process.env.mode,
entry: path.join(__dirname, "src/index.tsx"),
output: {
path: path.resolve(__dirname, "dist"),
filename: "[hash].js",
publicPath: "/",
clean: true,
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
module: {
rules: [
{
test: /\.(ts|tsx)?$/,
loader: "esbuild-loader",
exclude: /node_modules/,
options: {
loader: "tsx",
target: "esnext",
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
isDevelopment &&
new ReactRefreshWebpackPlugin({
overlay: false,
}),
].filter(Boolean),
devServer: {
host: "localhost",
port: 3000,
hot: true,
open: true,
},
};
output 옵션
❓filename을 hash로 설정하는 이유
webpack에서는 파일 이름에 [hash] 값을 포함시킴으로써, 파일 내용이 변경될 때마다 파일 이름이 변경되도록 설정할 수 있습니다. 이를 이용하면 브라우저에서 정적 파일을 로드할 때 항상 최신 버전을 로드할 수 있어 캐시 문제를 해결할 수 있습니다.
❓ publicPath
webpack에서 빌드한 파일들이 서빙될 때 사용되는 경로를 설정하는 부분입니다. publicPath 옵션은 해당 프로젝트에서 사용하는 경로를 설정하며, 파일이 위치한 경로를 기준으로 상대 경로를 생성합니다.
서빙(serve)은 웹 서버를 실행하여 클라이언트에게 웹 페이지나 파일 등을 제공하는 것을 말합니다. 웹 페이지나 파일을 서빙하기 위해서는 웹 서버를 구축해야 합니다.
개발 환경에서는 webpack-dev-server와 같은 도구를 사용하여 서버를 띄우는 것이 편리합니다. webpack-dev-server는 개발용 서버를 띄워주는 도구로, 코드 수정 시 자동으로 빌드를 수행하고 브라우저를 새로고침하여 변경된 내용을 보여줍니다. 이를 통해 개발자는 수정된 코드를 쉽게 확인할 수 있습니다.
CRA에서 `npm start`를 하면 개발 서버가 열리는 원리가 이것입니다.
❓clean: true
output에 clean: true를 설정하면, webpack이 빌드할 때마다 output.path에 지정한 디렉토리를 자동으로 비워줍니다.
이 옵션을 사용하면 이전 빌드 결과물이 남아 있지 않아서, 새로운 빌드 결과물이 깨끗하게 생성됩니다. 이를 통해 파일 충돌이나 쓰기 권한 문제 등으로 인한 빌드 오류를 방지할 수 있습니다.
또한, clean-webpack-plugin 플러그인을 사용하여 직접 빌드 결과물을 지우는 것보다 이 옵션을 사용하는 것이 별도의 플러그인을 설치하지 않아도 되기 때문에 더욱 간편합니다.
resolve 옵션
❓resolve 옵션 작동 예시
resolve 옵션을 설정하면, import나 require 등으로 모듈을 불러올 때 해당 확장자를 생략할 수 있습니다. resolve 옵션에 설정한 확장자들을 우선하여 찾아보며, 해당 확장자로 끝나는 파일을 모듈로 사용합니다.
예를 들어, resolve 옵션에 아래와 같이 설정하면,
resolve: {
extensions: ['.js', '.jsx', '.json']
}
.js, .jsx, .json 확장자를 사용하여 모듈을 불러올 수 있습니다. 따라서, 다음과 같이 import 구문에서 해당 확장자를 생략하고 모듈을 불러올 수 있습니다.
import App from './components/App'
위와 같이 모듈을 불러올 때 파일 경로를 일일이 적지 않아도 되므로, 코드를 더욱 간결하게 작성할 수 있습니다.
module 옵션
❓esbuild-loader
esbuild는 Go 언어로 작성된 자바스크립트 번들러 및 컴파일러입니다. esbuild-loader는 기본적으로 TypeScript와 JSX를 지원해서 Babel 없이도 TypeScript와 JSX 문법을 컴파일하여 JavaScript로 변환할 수 있습니다.
속도가 빠른 Go로 작성되어서 기존에 babel-loader와 ts-loader를 사용하는 것보다 빠르게 빌드를 할 수 있습니다.
💡 css-in-js를 사용할 예정이라 style-loader와 css-loader는 설치하지 않았습니다.
plugins 옵션
❓HtmlWebpackPlugin
HtmlWebpackPlugin은 웹팩에서 HTML 파일을 생성하기 위한 플러그인으로, HTML 파일을 자동으로 생성하고, 번들링 된 CSS와 JavaScript 파일을 자동으로 추가해줍니다. 이를 통해 번들링된 파일들을 자동으로 로드할 수 있습니다.
위 설정에서는 template 옵션을 사용하여 웹팩에서 생성할 HTML 파일의 템플릿 경로를 설정하고 있습니다. 즉, HtmlWebpackPlugin은 해당 경로에 있는 템플릿 파일을 기반으로 HTML 파일을 생성하며, 번들링된 CSS와 JavaScript 파일도 자동으로 추가됩니다.
❓template 옵션이 없으면 어떻게 동작할까
template 옵션을 설정하지 않으면, HtmlWebpackPlugin은 기본 템플릿을 사용하여 빈 HTML 파일을 생성합니다. 이때 생성된 HTML 파일에는 번들링된 CSS와 JavaScript 파일이 자동으로 추가되며, 파일 이름에 대한 해시(hash) 값도 자동으로 추가됩니다.
따라서, template 옵션을 설정하지 않아도 webpack에서 생성한 번들링된 파일을 HTML 파일에 자동으로 추가할 수 있습니다. 다만, 기본 템플릿을 사용하기 때문에, 원하는 형식의 HTML 파일을 생성하기 위해서는 직접 HTML 파일을 작성하거나, template 옵션을 설정하여 원하는 템플릿 파일을 사용해야 합니다.
❓ReactRefreshWebpackPlugin을 사용하는 이유
ReactRefreshWebpackPlugin은 리액트 애플리케이션에서 더 나은 개발 경험을 제공하기 위한 웹팩 플러그인입니다. 이 플러그인은 빠르고 안정적인 코드 업데이트를 제공하며, 상태를 유지하는 동시에 컴포넌트를 업데이트할 수 있습니다. 이를 통해 상태를 잃지 않고 애플리케이션의 특정 부분을 새로고침 하여 변경 사항을 확인할 수 있습니다.
💡위 코드에서 isDevelopment가 true일 때만 ReactRefreshWebpackPlugin을 활성화하는 이유는 개발 모드에서만 핫 리로딩을 사용하기 때문입니다. 또 프로덕션 모드에서 불필요한 코드가 추가되는 것을 방지합니다.