프로젝트를 세팅하면서 항상 골치 썩었던 webpack과 babel 설정을 해보면서 정리한 내용을 바탕으로 포스팅을 작성하였습니다.
이번 포스팅에서는 webpack에 좀더 초점을 두고 작성하였습니다.
프로젝트 스펙
node
: v20.10.0react
: 18.2.0typescript
: 4.9.5webpack
: 5.90.3babel
: 7.23.9
babel
이란 javascript compiler로 최신 버전(ES6)의 자바스크립트를 구형 버전(ES5)의 자바스크립트로 변환 시켜줍니다.
yarn -D @babel/core @babel/preset-env
@babel/preset-react @babel/preset-typescript
core
: babel의 기본적인 것들preset-env
: babel이 자동으로 최신 문법으로 변경해준다.preset-react
, preset-typescript
: 리액트, 타입스크립트를 자바스크립트로 지원프로젝트 상단에 babel.config.js
를 생성합니다.
touch babel.config.js
babel 설정 파일에 앞서 설치한 플러그인들을 넣어줍니다.
module.exports = {
presets: [
"@babel/preset-react",
"@babel/preset-env",
"@babel/preset-typescript",
],
};
웹팩은 모듈 번들러입니다.
모듈 번들러
는 웹 어플리케이션을 구성하는 자원(HTML, CSS, JavaScript, Image 등)을 모두 각각의 모듈로 보고 이를 조합해서 병합(번들링, bundling)하는 역할을 수행합니다.
yarn add -D webpack webpack-cli webpack-dev-server
webpack
: 번들 작업을 하는 웹팩 코어webpack-cli
: 웹팩 터미널 도구, 웹팩을 커맨드 라인에서 사용webpack-dev-server
: 웹팩을 메모리 상에 빌드하여 개발 서버 구동웹팩의 기본 설정 파일 명은 webpack.config.js
입니다. 루트 폴더에 웹팩 설정 파일 webpack.config.js
을 생성합니다.
# 설정 파일 생성
touch webpack.config.js
# webpack 플러그인 모듈 추가
yarn add -D html-webpack-plugin clean-webpack-plugin
# 로더(loader) 모듈 추가
yarn add -D babel-loader ts-loader file-loader style-loader css-loader
# process 모듈 추가
yarn add process
완성된 webpack.config.js
을 먼저 공개하자면 아래와 같습니다.
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const path = require("path");
const webpack = require("webpack");
module.exports = (env, argv) => {
const prod = argv.mode === "production";
return {
mode: prod ? "production" : "development",
devtool: prod ? "hidden-source-map" : "eval",
entry: {
main: path.resolve(__dirname, "src/index.tsx")
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
clean: true,
},
devServer: {
// 포트 번호 설정
port: 9000,
// 핫 모듈 교체(HMR) 활성화 설정
hot: true,
// gzip 압축 활성화
compress: true,
// History 라우팅 대체 사용 설정
historyApiFallback: true,
// 개발 서버 자동 실행 설정
open: true,
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx", "..."],
},
module: {
rules: [
{
test: /.(ts|js)x?$/,
exclude: /node_modules/,
use: ["babel-loader", "ts-loader"],
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.(jpg|png|gif|svg|ico)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name]_[hash].[ext]",
outputPath: "images",
},
},
],
},
],
},
plugins: [
new webpack.ProvidePlugin({
process: "process/browser.js",
}),
new webpack.ProvidePlugin({
React: "react",
}),
new HtmlWebpackPlugin({
template: "./template/index.html",
favicon: "./src/assets/images/favicon.png",
minify:
process.env.NODE_ENV === "production"
? {
collapseWhitespace: true, // 빈칸 제거
removeComments: true, // 주석 제거
}
: false,
}),
new CleanWebpackPlugin(),
],
};
};
mode
: 개발, 프로덕션 모드 확인devtool
: 모드에 따라 SourceMap 확인 여부entry
: 시작점 경로를 지정하는 옵션, 해당 파일부터 필요한 모듈 로딩 및 하나의 파일로 번들링output
: webpack이 번들링 결과물을 위치할 경로 및 이름devServer
: 개발 서버 포트(port) 및 실시간 여부(hot)resolve
: 배열 안 확장자에 따라서 처리module
: loader 설정 / babel-loader
, ts-loader
등plugins
: 부가 기능을 수행할 플러그인 추가먼저 애플리케이션 실행 옵션을 변경하기 위해 package.json
의 scripts
옵션을 수정해줍니다.
{
"scripts": {
"build": "webpack --mode=production --progress",
"start": "webpack serve --mode=development --open --hot --progress",
},
}
터미널을 켜고 아래 명령을 수행합니다.
npm run start
혹은
yarn start
웹팩은 번들러, 즉 컴파일 도구입니다. 이렇게 컴파일된 코드는 컴파일러 런타임에 의해 실행되어야됩니다.
따라서 웹팩을 쓰는 순간 빌드 및 실행은 웹팩에 위임하게 됩니다. 웹팩의 명령어에는 다음과 같습니다.
build
: (bundle
, b
): webpack 실행 (default command, 생략 가능)configtest
: (t
): webpack 설정 파일이 올바른지 테스트info
: (i
): 내 시스템 정보 확인serve
: (server
, s
): webpack 개발 서버를 실행하고, 서버가 실행하는 동안 소스파일 변화 감시version
: (v
): webpack과 관련된 모듈들의 버전을 보여준다. info
와 결과값 동일watch
: (w
): webpack을 실행하고, 실행하는 동안 소스파일 변화 감시웹팩의 주요 기능인 번들링(컴파일) 기능입니다.
아래와 같은 커맨드로 webpack을 실행할 수 있습니다.
> webpack
> webpack build
> webpack bundle
> webpack b
웹팩을 실행하면 번들링 결과를 얻을 수 있고, 번들링에 실패하면 에러가 발생합니다.
webpack 설정 파일이 올바른지 테스트합니다.
> webpack configtest
> webpack t
[webpack-cli] Validate 'D:\Git\hjkim1004.github.io\webpack.config.js'.
[webpack-cli] There are no validation errors in the given webpack configuration.
웹팩을 실행하는 런타임에 관련된 모든 정보를 보여줍니다.
> webpack info
> webpack version
> webpack i
> webpack v
웹팩 개발 서버를 실행합니다.
> webpack serve
> webpack server
> webpack s
webpack은 위의 명령어 및 설정 파일을 이해하면 쉽게 접근할 수 있습니다.
출저 - 하늘네트 블로그
mode
는 현재 프로젝트가 운영되는 환경을 정의합니다.
mode 값을 설정하지 않을 경우 default 값은 none
이나, 실제로 mode로 동작하지는 않습니다.
그 외에는 development
, production
의 상태를 갖을 수 있습니다. 각 모드에 따라 프로젝트 구동방식이 달라집니다.
development
: 소스 매핑을 쉽게 사용하여 오류를 찾아내고 원본 파일 추적이 쉬워짐.production
: 파일 축소, 최적화 우선module.exports = {
mode: "development", // or "production"
};
Entry에서는 애플리케이션의 진입점을 설정합니다.
단일 페이지 애플리케이션(SPA)의 경우 하나의 진입점이 있어야 하고, 다중 페이지 애플리케이션(MPA)의 경우 여러개의 진입점이 있어야 합니다.
const path = require("path");
module.exports = {
/* ... */
entry: {
main: path.resolve(__dirname, "src/index.js"),
},
};
마지막으로, 애플리케이션 번들링 프로세스가 완료된 후 번들된 리소스들을 출력할 위치를 선언합니다.
const path = require("path");
module.exports = {
/* ... */
output: {
path: path.resolve(__dirname, "dist"),
filename: "index.bundle.js", // using static name
// OR
// using the entry name, sets the name to main,
// as specific in the entry object.
filename: "[name].bundle.js",
},
};
기본적으로 webpack
은 JavaScript 및 JSON(JavaScript Object Notation) 을 이해하지만 이미지 파일이 무엇인지, HTML, CSS, SASS 또는 SVG 파일(다른 유형의 파일 포함)은 알 수 없습니다. 그것들을 처리하는 방법을 모릅니다.
그렇기에 여러가지 loader를 설치하여 다른 유형(typescript, css, file etc)의 파일을 Webpack 이 이해하고 처리가능한 모듈로 변환시킬 수 있습니다.
예를 들어, css를 처리하는 module을 추가하는 방법입니다.
yarn add -D style-loader css-loader
const path = require("path");
module.exports = {
/* ... */
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
]
}
};
개발 서버 실행과 관련된 옵션을 적어줍니다.
{
devServer: {
// 포트 번호 설정
port: 9000,
// 핫 모듈 교체(HMR) 활성화 설정
hot: true,
// gzip 압축 활성화
compress: true,
// History 라우팅 대체 사용 설정
historyApiFallback: true,
// 개발 서버 자동 실행 설정
open: true,
},
}
절대 경로
란 최상위 디렉토리가 반드시 포함 된 경로를 의미하며,
상대 경로
란 현재 디렉토리(비교 대상)를 기준으로 작성된 경로를 의미합니다.
절대 경로와 상대 경로의 예시입니다.
// 상대 경로로 아바타 컴포넌트 불러오기
import Avatar from '../../../components/user/Avatar'
// 절대 경로로 아바타 컴포넌트 불러오기
import Avatar from 'components/user/Avatar'
코드를 보면 절대 경로를 사용하면 깔끔하고 가독성 높은 코드를 사용할 수 있는 것을 볼 수 있습니다.
절대 경로 설정은 의외로 간단합니다.
tsconfig.json
파일에서 compilerOptions
아래의 baseUrl
속성을 추가해줍니다.
※ tsconfig.json 파일은 프로젝트를 컴파일하는데 필요한 루트 파일과 컴파일러 옵션을 지정하는데 사용합니다.
{
"compilerOptions": {
// 최상위 소스 디렉터리 경로
"baseUrl": "src",
}
}
Alias 설정을 하면 좀더 쉽게 경로를 찾을 수 있습니다.
// 상대 경로로 Header 컴포넌트 불러오기
import Header from '../../../components/layout/header'
// Alias 경로로 Header 컴포넌트 불러오기
import Header from '@Layout/header'
// Alias 경로로 Noto Sans css 불러오기
import "@Fonts/notosans.css";
우선, 번들링하는 webpack이 경로를 알아야하기 때문에 설정 파일인 webpack.config.js
파일을 수정해줍니다.
resolve 옵션을 통해 아래 설정한 확장자(extension)의 경로에 이름(alias)을 지정해줍니다.
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx", "..."],
alias: {
"@Components": path.resolve(__dirname, "src/components/"),
"@Layout": path.resolve(__dirname, "src/components/layout"),
"@Pages": path.resolve(__dirname, "src/pages/"),
"@Images": path.resolve(__dirname, "src/assets/images"),
"@Fonts": path.resolve(__dirname, "src/assets/fonts"),
"@Data": path.resolve(__dirname, "src/data"),
"@Context": path.resolve(__dirname, "src/context"),
},
},
typescript를 사용하면 타입을 검사 받기 때문에 컴파일 오류를 겪지 않으려면 tsconfig.json
파일에 타입에 관련된 설정을 추가해주어야 합니다.
paths
아래에 Alias로 설정한 것들을 같이 적어줍니다.
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"jsx": "react-jsx",
// 최상위 경로 설정
"baseUrl": "src",
// Alias 경로 설정
"paths": {
"~/*": ["~/*"],
"@Components/*": ["components/*"],
"@Layout/*": ["components/layout/*"],
"@Pages/*": ["pages/*"],
"@Images/*": ["assets/images/*"],
"@Fonts/*": ["assets/fonts/*"],
"@Data/*": ["data/*"],
"@Context/*": ["context/*"]
}
},
"include": ["src"],
"exclude": ["node_modules"]
}
매번 프로젝트 마다 설정해주니 새로 시작할 때마다 까먹어서 이리 정리하게 되었지만, 웹팩을 처음 접할 때보다는 상당히 수월하게 이해할 수 있게 되었습니다.
역시 반복 노출이 최고의 공부법인가 봅니다😁