안녕하세요! 저는 그동안 React 개발 환경을 구성하기 위해 CRA (create-react-app) 을 사용하거나, 회사에서는 다른 사람이 셋팅해줬던 개발 환경을 그대로 따라하기만 했었는데요!
그러다 보니까 번들링된 결과물은 어떻게 떨어지는지, 환경설정을 바꾸고 싶은데 어디서부터 바꿔야할지 도통 감이 잡히지 않았습니다...
그래서 저는 토이 프로젝트를 진행하며 CRA 를 쓰지 않고 Webpack, Babel 을 이용해 React + Typescript 개발 환경을 직접 설정해보자! 라는 결심을 하게 되었고!
기록으로 남길 겸, 여러분들에게 공유하고 피드백을 받고자 글로 작성하게 되었습니다 :)
npm init
을 통해 package.json 파일을 생성해주세요.npm i -D webpack webpack-cli
다음은 Babel을 설치하고, 설정해보겠습니다.
Babel은 리액트의 JSX, 타입스크립트와 같은 정적 타입 언어, 코드 압축, 제안(proposal) 문법 을 사용할 수 있게해줍니다.
npm i -D @babel/core @babel/plugin-proposal-class-properties @babel/preset-typescript @babel/preset-env @babel/preset-react babel-loader
//conf/babel.conf.js
module.exports = {
presets: ["@babel/preset-env", "@babel/preset-typescript","@babel/preset-react"]
};
설정 전에, 어떤 속성들을 설정할 수 있는지 알아보고 가겠습니다!
webpack 이 디펜던시 그래프를 생성하기 위해 사용해야하는 모듈, 즉 번들링의 시작점
module.exports = {
entry: './src/index.js'
}
src 폴더의 index.js
파일을 번들링을 시작하는 파일로 지정합니다.
생성된 번들을 내보낼 위치와 파일 이름 지정, 기본값 ./dist/main.js
const path = require("path");
module.exports = {
entry : "./src/index.js",
output: { // 번들링 결과물을 내보내는 방법과 관련된 옵션
path: path.resolve(__dirname,'dist'),
filename: "index.js",
}
}
path 와 filename 속성으로 번들의 이름을 index.js 로 설정하고, 내보낼 위치는 dist 폴더라고 알려주었습니다.
path 모듈은 파일 경로를 지정하기위해 사용되는 core Node.js 모듈입니다. path.resolve
는 절대경로 문자열을 반환해줍니다.
__dirname
은 현재 디렉토리를 의미합니다.
Webpack 은 Javascript 와 JSON 파일만 이해합니다. 로더를 사용하면 다른 유형의 파일을 웹팩이 이해하도록 할 수 있습니다.
const path = require("path");
module.exports = {
entry : "./src/index.js",
output: {
path: path.resolve(__dirname,'dist'),
filename: "index.js",
},
module: {
rules: [
{
test: /\.html$/,
use: 'html-loader'
}
]
}
}
test 속성은 변환이 필요한 파일을 식별하고, use 속성은 변환을 수행하는데 사용되는 로더를 가리킵니다.
플러그인의 역할은 번들 최적화, 애셋 관리, 환경 변수 주입 등과 같은 역할을 수행합니다.
require()
을 통해 플러그인을 요청하고, plugins 배열에 추가해야 사용할 수 있습니다.
const path = require("path");
module.exports = {
entry : "./src/index.js",
output: {
path: path.resolve(__dirname,'dist'),
filename: "index.js",
},
module: {
rules: [
{
test: /\.html$/,
use: 'html-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
]
}
위 코드에서 사용된 HTML 플러그인은 생성된 모든 번들을 자동으로 삽입해 HTML 파일을 생성하는 역할을 합니다.
Mode 속성으로 development
(기본값),production
,none
을 설정하여 환경별로 최적화할 수 있습니다.
webpack.config.js 파일 하나로 설정을 적용할 수 있지만, dev/prod mode 에 따라 다른 설정을 적용하고 싶었습니다.
그래서 저는 webpack.common.conf.js (공통), webpack.development.conf.js (개발용), webpack.production.conf.js (배포용) 세 파일로 설정을 관리할 것입니다!
conf
폴더로 세 파일을 이동시켜주겠습니다.
그리고 여러개로 나뉘어진 웹팩 설정 파일을 하나로 병합해주기 위해, webpack-merge
을 사용하도록 하겠습니다.
npm i -D webpack-merge
를 통해 webpack-merge 를 설치해주세요.
webpack.common.conf.js
에서는 엔트리, 아웃풋, 플러그인과 같이 실행 모드에 관계 없이 항상 들어가야 하는 코드를 넣겠습니다.
const path = require("path");
module.exports = {
entry : "./src/index.js", //webpack 번들링의 시작점
output: { // 번들링 결과물을 내보내는 방법과 관련된 옵션
path: path.resolve(__dirname,'..','dist'),
filename: "index.js",
},
module: { // 모듈 관련 설정
rules: [ // 모듈에 대한 규칙
{
test: /\.html$/, //어떤 파일이 transform 될지
use: [ // 어떤 로더가 transform 에 사용 될지
{
//...
}
]
}
]
}
}
여기서 path.resolve() 의 매개변수로 __dirname
,..
,dist
세 문자열을 전달해주었는데요, 현재 파일(./conf/webpack.common.conf.js
)이 위치한 폴더를 기준으로 루트경로까지의 절대 경로를 반환합니다. 따라서 conf 폴더 -> working directory 폴더 -> dist 폴더 로 경로를 지정해주었습니다.
저는 SCSS를 사용할 것인데요, 웹팩이 SCSS 로 작성된 파일을 읽을 수 있도록
npm i -D css-loader style-loader mini-css-extract-plugin sass-loader
로 관련 로더를 설치 후, 설정해주었습니다.
- css-loader
- style-loader : CSS를 DOM에 삽입합니다.
- mini-css-extract-plugin : CSS 파일을 별도 파일로 추출(extract) 합니다. CSS 코드가 포함된 JS 파일 별로 CSS 파일을 생성합니다.
- sass-loader : SASS/SCSS 파일을 CSS로 변환해줍니다.
webpack.development.conf.js
에서는 개발자 도구나 webpack dev server 설정을 하도록 하겠습니다.
const { merge } = require('webpack-merge');
const common = require('./webpack.common.conf.js');
module.exports = merge(common, {
mode: 'development',
devServer: {
port:9000,
hot: true, //HMR 기능 활성화
//compress : 모든 항목에 대해 gzip 압축 사용
//contentBase: 정적 파일 제공하려는 경우 필요
open:true
}
})
webpack-merge 가 제공하는 merge
API 를 사용하여 webpack.common.conf.js
의 설정과 webpack.development.conf.js
설정을 합칠 수 있습니다.
const { merge } = require('webpack-merge');
// Keys matching to the right take precedence:
const output = merge(
{ fruit: "apple", color: "red" },
{ fruit: "strawberries" }
);
console.log(output);
// { color: "red", fruit: "strawberries"}
const { merge } = require('webpack-merge');
const common = require('./webpack.common.conf.js');
module.exports = merge(common, {
mode: 'production',
})
//pakage.json
"scripts": {
"serve": "webpack serve --config ./conf/webpack.development.conf.js",
"build": "webpack --config ./conf/webpack.common.conf.js"
}
--config
플래그를 사용해 특정 상황에서 특정 설정 파일을 사용할 수 있도록 합니다!
이제 HTML 파일을 빌드해보겠습니다! public 폴더 안에 index.html 파일을 생성해주세요. Webpack loader
를 통해 은 자바스크립트가 아닌 파일도 모듈로 관리할 수 있습니다. html-loader
를 설치해, HTML 파일을 웹팩이 이해할 수 있도록 하겠습니다.
<!--public/index.html-->
<!DOCTYPE html>
<html lang="kr">
<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>
</body>
</html>
npm i -D react react-dom typescript @types/react @types/react-dom
참고