웹팩을 활용한 리액트 개발 환경 세팅 1
본 글에서 사용된 개발 도구들의 버전정보 입니다.
Initialization
가장 먼저 프로젝트 디렉토리를 생성하고 npm을 시작합니다. 그 후에 필요한 dependency를 설치해줍니다.
일단 웹팩 관련 패키지를 설치해보겠습니다.
웹팩은 개발 도중 빌드 단계에서 사용하며 완성된 웹페이지에선 아무런 기능을 하지 않기 때문에 --save-dev
옵션으로 설치합니다.
$ mkdir my-react-app && cd my-react-app
$ npm init -y
$ npm i -D webpack webpack-cli
webpack-cli
는 커맨드 라인 상으로 웹팩과 관련한 명령을 수행하는 패키지입니다.
webpack.config.js
와 같은 설정파일 없이도 webpack-cli
를 통해 빌드 시 옵션을 부여할 수 있습니다.
webpack v4 이후 버전을 사용하기 위해서는 webpack-cli
를 함께 설치해야 한다고 합니다.
설치된 웹팩을 실행하기 위해 package.json
에 script
를 추가합니다.
{
"name": "my-react-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.3.1",
"webpack-cli": "^4.1.0"
},
}
추가했다면 다음 커맨드로 빌드를 실행할 수 있습니다.
$ npm run build
또는 script
에 커맨드를 추가하지 않더라도 터미널에서 다음 커맨드를 입력하는 방법으로 웹팩을 실행하는 방법도 있습니다.
$ node_modules/.bin/webpack
## 혹은
$ npx webpack
Configuration
이제 설치한 웹팩의 설정을 해보겠습니다.
$ touch webpack.config.js
웹팩 설정 파일 이름의 기본값은 webpack.config.js
입니다.
webpack.config.js
에 다음과 같이 기본적인 옵션을 설정하겠습니다.
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: __dirname + "/dist"
}
};
entry
: 번들링의 시작이 되는 파일output
: 빌드된 번들의 저장 옵션
entry
entry
는 번들링의 시작이 되는 파일을 나타냅니다.
리액트 프로젝트의 경우에도 컴포넌트를 import
하는 상위 컴포넌트를 따라 올라가다보면 결국 virtual DOM과 root div를 연결해주는 index.js
로 수렴하게 되고, index.js
가 바로 빌드의 시작점, entry point가 되는 것입니다.
복수의 entry
를 지정하거나 entry
파일을 동적으로 지정하는 기능 등이 가능하며 자세한 내용은 다음 링크에서 확인할 수 있습니다.
output
output
은 빌드된 번들을 어디에, 무슨 이름으로 저장할지 지정해주는 옵션입니다.
output.filename
은 빌드된 파일의 이름을, output.path
는 파일이 저장되는 경로를 나타냅니다.
위에 코드에선 문자열을 직접 만들어서 경로를 지정해줬지만, 아래처럼 node의 path
모듈을 이용해서 경로를 지정할 수도 있습니다.
+ const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
- path: __dirname + "/dist"
+ path: path.resolve(__dirname, "dist")
}
};
multiple entry point를 설정했다면 당연히 복수의 output을 설정해줘야 할 것입니다.
웹팩은 output.filename
에 substitutions를 제공하며 이를 통해 자동적으로 unique한 이름의 파일을 생성할 수 있습니다.
output에 대한 자세한 설정은 다음을 참고하면 됩니다.
참고 사항
기본값
방금 설정한 entry
와 output
값들은 기본값이어서 webpack.config.js
에 따로 entry
와 output
을 지정하지 않아도 빌드 시 웹팩이 자동적으로 ./src/index.js
를 entry point로 삼아 ./dist/main.js
에 번들링 결과를 저장합니다.
config 파일 이름
다른 이름으로 된 config 파일을 사용할 수 있습니다.
다른 이름의 config 파일을 사용할 땐 웹팩을 실행할 때 --config
옵션으로 해당 파일 이름을 지정하여 빌드하면 됩니다.
{
"scripts": {
"build": "webpack --config prod.config.js"
},
}
$ npx webpack --config prod.config.js
config 파일 확장자
다른 확장자로 끝나는 config 파일을 사용할 수 있습니다.
.ts
, .coffee
가 가능하며 babel 설치 후 .js
파일에 jsx로 작성하는 것 또한 가능합니다.
https://webpack.js.org/configuration/configuration-languages/
config 파일 자동 생성
$ npx webpack-cli init
@webpack-cli/init
패키지가 설치돼 있어야지만 명령어가 실행되며, 설치되지 않았다면 설치 승인 여부를 묻고 설치를 진행합니다.
그 후에 몇 가지 질문들에 답하면 자동적으로 webpack.config.js
파일을 생성됩니다.
자세한 옵션은 아래 링크에서 확인 가능합니다.
Loaders
웹팩은 JavaScript와 JSON 밖에 이해하지 못합니다. 때문에 CSS나 이미지 파일 등 JS 이외의 파일들을 처리하기 위해 loader를 사용합니다. 웹팩은 각 파일 유형에 맞는 loader들을 제공하며 transpiling, testing, linting 등의 전처리 또한 수행합니다.
오늘은 웹팩이 리액트와 JSX를 처리하도록 해보겠습니다.
이를 위해 babel-loader
와 관련 패키지를 설치합니다.
babel-loader
를 잘 활용한다면, ES6+를 ES5로 변환한다던가, TypeScript를 JS로 변환한다던가, React, JSX를 JS로 변환하는 등 babel에서 제공하는 트랜스파일링 기능을 웹팩의 번들링과 연동할 수 있습니다.
$ npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react
@babel/core
는 코드 변환과 관련된 API를 지닌 패키지 입니다.@babel/preset-env
는 ES6+를 ES5로 변환해주는 plug-in의 모음입니다.@babel/preset-react
는 React, JSX를 JS로 변환해주는 plug-in의 모음입니다.
그러면 앞서 작성한 webpack.config.js
파일에 babel-loader
설정을 추가하겠습니다.
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: __dirname + "/dist"
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"]
}
}
]
}
]
}
};
loader 관련 설정은 module.rules
에서 다룹니다.
module.rules
에는 어떤 파일을 어떤 로더로 처리할지 등에 관한 규칙rule을 객체로 묶어서 저장합니다.
test
: 패턴에 해당하는 파일을 대상으로 rule을 적용exclude
: 패턴에 해당하는 파일을 대상에서 제외loader
: 적용할 로더와 로더의 개별 설정을 지정
test
test
는 정규표현식을 사용했습니다.
test
값은 /\.jsx?$/
라는 정규표현식인데, .js
혹은 .jsx
로 끝나는 이름을 가진 파일을 대상으로 한다는 의미입니다.
같은 패턴의 다른 표현으론 /\.(js|jsx)$/
이 있겠습니다.
exclude
exclude
또한 정규표현식을 사용했습니다.
패턴에 해당하는 파일은 빌드 시 로더를 적용시키지 않습니다.
위와 같이 exclude: /node_modules/
로 하였다면 설치된 dependency 중에서 ./src
에 있는 파일이 import 하는 모듈에겐 babel-loader
를 적용하지 않게 됩니다.
use
test
에서 지정한 파일에 적용할 로더와 로더의 개별 설정을 지정합니다.
use.loader
에선 사용할 로더를 나타내며 use.options
에선 해당 로더에 적용할 옵션을 의미합니다.
여기선 .js
, .jsx
파일에 @babel/preset-env
와 @babel/preset-react
를 사용하는 babel-loader
를 적용하게 되겠습니다.
babel-loader
의 경우, use.options
를 .babelrc
나 babel.config.js
와 같은 바벨 설정 파일로 대체할 수 있습니다.
babel-loader
의 옵션을 use.options
에 적느냐, .bablerc
에 적느냐에 차이는 바벨이 읽을 수 있느냐에 있습니다.
use.options
를 사용하면, 웹팩에서babel-loader
를 실행할 때 인식할 수 있지만, 바벨을 따로 돌릴 땐 인식할 수 없습니다..babelrc
나babel.config.js
를 사용하면, 웹팩에서babel-loader
를 실행할 때는 물론, 바벨을 따로 돌릴 때도 인식할 수 있습니다.
참고로 바벨의 preset은 선언한 역순으로 적용이 됩니다.
options.preset
을 ["@babel/preset-env", "@babel/preset-react"]
와 같이 설정한다면, 코드엔 preset-react
가 먼저 적용되고 그 결과에 preset-env
가 적용됩니다.
React 코드
-> Vanilla JS의 DOM 조작 코드
-> ES5 코드
처럼 말입니다.
그리고 복수의 로더를 사용할 때도 선언한 역순으로 적용됩니다. 로더 적용 순서에 대한 자세한 내용은 다음 링크에서 확인할 수 있습니다.
만약 하나의 로더만을 사용한다면 use.loader
를 loader
로, use.options
를 options
으로 간단히 표현할 수도 있습니다.
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: __dirname + "/dist"
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
+ loader: "babel-loader",
+ options: {
+ presets: ["@babel/preset-env", "@babel/preset-react"]
+ }
- use: [
- {
- loader: "babel-loader",
- options: {
- presets: ["@babel/preset-env", "@babel/preset-react"]
- }
- }
- ]
- }
]
}
};
이 외에도 웹팩은 다양한 옵션을 제공하지만, 워낙 수가 많아 하나하나 열거하긴 어려울 것 같습니다. 대신 공식문서에 잘 정리된 자료가 있어 공유하겠습니다.
React
이제 본격적인 리액트 코드를 작성해보겠습니다.
우선 리액트 관련 패키지를 설치하겠습니다.
$ npm i react react-dom
다음으론 entry
에 설정한 entry point에 맞추기 위해 src
란 디렉토리와 index.js
파일을 생성하겠습니다.
$ mkdir src
$ touch ./src/index.js
index.js
에 아래와 같이 작성합니다.
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
import
할 App
컴포넌트를 생성하고 아래 코드를 입력합니다.
$ touch ./src/App.js
import React from "react";
export default function App() {
return <div>Hello, world!</div>;
}
이대로 빌드한다면 output
에 적힌대로 ./dist
디렉토리의 main.js
에 결과가 저장될 것입니다.
이 main.js
파일을 읽어오는 html 파일을 만들고 아래와 같이 입력합니다.
$ mkdir dist
$ touch ./dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>my-react-app</title>
</head>
<body>
<div id=root></div>
<script src="./main.js"></script>
</body>
</html>
Build
이제 준비는 다 끝났습니다.
빌드 명령어를 입력합니다.
$ npm run build
./dist/main.js
가 생성된 것을 확인할 수 있습니다.
index.html
을 열어 리액트가 제대로 랜더링 되는지 확인하면 됩니다.
$ google-chrome ./dist/index.html
References
Initialization
Configuration
https://webpack.js.org/concepts/
Loaders
Back to top ↑https://webpack.js.org/concepts/
https://webpack.js.org/loaders/
https://babeljs.io/docs/en/core-packages
Leave a comment