[JS] React와 Webpack
Webpack이란?
웹팩은 자바스크립트 모듈 번들러의 한 종류이며 라이브러리의 형태입니다. 일반적으로 어떤 웹어플리케이션의 코드의 수가 많아지면 보통 협업 및 유지보수 등의 이유로 코드를 분할하여 관리합니다.
이렇게 되면 웹 어플리케이션에서 수 많은 자바스크립트 파일을 로딩하게 되고 이는 네트워크 비용을 증가시키게 됩니다. 따라서 자바스크립트 파일들을 모듈화 시켜서 관리하게 해주는 라이브러리가 웹팩입니다. 웹팩을 정적(static) 모듈 번들러라고 하는데 잠시 후에 이에 대해 더 알아보겠습니다.
webpack의 기본적인 개념으로는 자바스크립트 코드들을 모듈화하여 분할된 코드를 하나의 index를 통해 실행하게 하며 그 index로 다른 파일들을 모아주는 역할을 웹팩이 한다고 생각하시면 됩니다. 이렇게 웹팩과 비슷한 역할을 하는 모듈 번들러는 웹팩 이외에도 parcel, gulp, rollup, fusebox 등이 있습니다.
CRA란?
CRA는 create react app의 약자로 리액트를 현재 개발하고 있는 페이스북 팀에서 내놓은 공식 보일러 플레이트입니다. 기본적으로 webpack과 babel등을 이용하여 파일 로더, 빌드 툴, es6 문법 지원, eslint, jest(테스트) 등 기본적인 리액트를 이용한 프론트 엔드 개발을 바로 할 수 있도록 되어 있습니다.
npm i -g create-react-app
npx create-react-app <my-app>
npm을 통해 설치하여 npm 또는 yarn을 통해 실행할 수 있고 npx(npm의 최신 패키지 러너)를 통해 실행할 수 있습니다. npx를 이용하면 그때 그때 CRA를 설치하여 실행합니다. 이렇게 하면 일반적으로 -g 옵션으로 글로벌하게 설치된 react의 의존성들이 설치 후 바로 사라지게 되며 언제든지 최신 버전의 리액트를 설치할 수 있게 됩니다. CRA에 포함되지 않은 많이 쓰이는 라이브러리로는 대표적으로 redux, node-sass 등이 있습니다. 리액트를 처음 접할 때는 webpack의 설정이 복잡해 보일 수 있기 때문에 CRA를 통해 리액트의 구조에 대해 익히고 천천히 webpack을 배우는게 좋다고 생각합니다.
Webpack으로 React를 시작하기
CRA를 통해 기초적인 리액트의 구조를 익혔다고 가정하고 우리가 만드려는 어플리케이션에 필요한 모듈만을 설치하기 위해 webpack으로 React의 보일러 플레이트를 만드는 법에 대해 설명하겠습니다.
yarn init
npm init
yarn이나 npm을 이용하여 package.json 파일을 생성합니다.
이후 리액트에 필요한 라이브러리를 다운받습니다.
yarn add react react-dom
npm i --save react react-dom
yarn의 경우 add 명령어에 save 옵션이 기본적으로 달려 있습니다.
yarn add --dev webpack webpack-dev-server webpack-clinpm install --save-dev webpack webpack-dev-server webpack-cli
webpack-dev-server는 CRA를 통해 개발을 하면 코드를 수정하면 자동으로 리액트 앱이 최신화가 되는 hot-reload 설정에 필요합니다. webpack-cli는 커맨드 라인에서 웹팩을 사용하게 해주는 패키지입니다.
yarn add --dev @babel/core babel-loader @babel/preset-react @babel/preset-env
npm install --save-dev @babel/core babel-loader @babel/preset-react @babel/preset-env
babel/core는 모든 브라우저에서 지원할 수 있도록 es6문법을 바꿔주는 역할을 합니다. babel/preset은 babel의 플러그인들로 react, env 이외에도 typescript, flow등이 있습니다. 지금은 ReactJS를 사용하므로 두 개의 preset 패키지만 설치합니다. loader는 코드를 읽을 수 있도록 변환해주는 패키지입니다. webpack이 html,css 등 js가 아닌 다른 파일을 이해할 수 있도록(읽어서 로드할 수 있도록) 도와줍니다.babel-loader는 babel이 jsx를 js로 바꾸어서 다른 문법인 jsx를 이해할 수 있도록 해줍니다.
이제 루트폴더내에 webpack.config.js라는 파일을 생성해줍니다. 이 파일은 웹팩의 전반적인 세팅을 해주는 파일입니다. 생성하고 다음과 같이 작성해 줍니다.
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, '/dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_module/,
use:{
loader: 'babel-loader'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
여기서 html-webpack-plugin은 웹팩이 html 파일을 읽어서 로드할 수 있도록 도와줍니다.
yarn add html-webpack-plugin
npm i --save html-webpack-plugin
을 통해 설치해줍니다.
여기서 entry는 어플리케이션이 실행되는 시작파일을 의미합니다. 처음에 여러 곳에 나뉘어진 js파일을 하나의 index에 모아서 실행시킨다고 했는데 그 시작점이 바로 index.js입니다. output은 웹팩에 의해 변환된 코드들이 생성되는 곳입니다. 그 아래 모듈,rules는 loader를 통해 js가 아닌 파일들을 읽게 해줍니다. 이곳에 html-loader, css-loader등을 추가할 수 있습니다.
여기서 entry와 output은 설정을 하지 않아도 웹팩이 디폴트 설정으로 src폴더안의 index.js 파일을 찾게 되고 output은 dist폴더를 웹팩이 알아서 생성하고 그 안에 main.js라는 파일을 작성해줍니다. 물론 src폴더만 생성하고 그냥 웹팩을 이용해도 되지만 개발자가 원하는 대로 바꿀 수도 있습니다. 물론 바꾸지 않더라도 유지보수와 협업을 위해 명시해주는 것이 좋습니다.
이제 바벨을 적용할 수 있도록 .babelrc라는 파일을 루트폴더에 생성하고 안에 다음과 같이 작성합니다.
{
"presets": [
"@babel/env",
"@babel/react"
]
}
기본적인 웹팩과 바벨의 세팅은 끝났습니다. 이제 리액트 코드 작성을 위해 src폴더와 public폴더를 생성해주고 public 폴더내에 index.html을 만들고 다음과 같이 작성합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
src폴더내에 index.js를 만들고 다음과 같이 작성합니다.
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";ReactDOM.render(<App />, document.getElementById("root"));
그리고 src내에 App.js를 만들고 다음과 같이 작성합니다.
import React from 'react';function App(){
return(
<div className="app">
<h1>Webpack</h1>
</div>
)
}export default App;
리액트 어플리케이션의 실행을 위해 package.json에 start 스크립트를 작성해줍니다.
"scripts": {
"start":"webpack-dev-server --mode development --open --hot",
"build":"webpack --mode production"
}
open 옵션은 start 스크립트 실행시 자동으로 브라우저를 열어주고 hot옵션은 코드의 수정시 작동으로 리액트 어플리케이션을 최신화해줍니다.
모든게 끝났습니다. 이제 start 스크립트를 통해 실행해봅시다.
yarn start
npm start
만약 build 스크립트를 실행하면 webpack.config.js에 설정한대로 dist 폴더를 만들고 index.html에 자동으로 main.js를 연결하여 빌드하게 될 것입니다.
다양한 파일들의 로드
지금까지 작성한 상태로는 아주 간단한 리액트 어플리케이션 조차도 작성할 수 없습니다. 왜냐하면 css도 읽을 수 없고 html도 읽을 수 없기 때문입니다. 따라서 loader를 설치하고 적용해보는 방법을 알아보겠습니다.
실제로 src내에 App.css를 생성하고 App.js에 import하면
다음과 같은 에러를 보여줄 것 입니다. 지금까지 설정한 웹팩으로는 css 파일 svg, jpg와 같은 이미지파일 모두 사용할 수 없습니다. 왜냐하면 우리는 babel-loader를 통한 jsx의 문법만 처리했기 때문입니다. 따라서 다음과 같이 세 개의 패키지를 설치해줍니다.
yarn add --dev html-loader css-loader style-loader file-loader
npm i --save-dev html-loader css-loader style-loader file-loader
그리고 webpack.config.js를 다음과 같이 수정해줍니다.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "/dist"),
filename: "main.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_module/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: ["html-loader"]
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(svg|png|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "img"
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html"
})
]
};
test는 파일의 종류를 설정하고 use는 그 종류의 파일에 대해 어떤 loader를 사용할 것인지 또 options를 통해 추가적인 설정을 할 수 있습니다.
참고로 css loader에서는 style loader가 더 필요한데 만약 나중에 sass를 사용할 것이라면 sass-loader도 설치해주어야 합니다.
그리고 css-loader의 use 부분은 배열의 역순으로 실행이 되는데 만약 sass-loader를 사용한다면
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
}
위와 같이 작성하여야 합니다. 역순으로 실행된다는 말은 먼저 sass-loader가 scss를 읽고 그다음 css로 변환해줍니다. 그 후 css-loader가 css로 변환된 scss 파일을 읽고 style-loader가 최종적으로 읽어줍니다.
결론
이번 포스트는 최대한 CRA를 통해 리액트를 접한 사람이 웹팩의 기초 세팅을 이해할 수 있도록 CRA의 세팅과 비슷하게 웹팩을 설정해 보았습니다. 이 외에도 타입스크립트의 이용이라던가 리액트 이외의 다른 라이브러리나 프레임워크의 웹팩설정 등은 복잡하고 어려울 수 있습니다. CRA도 버전을 거쳐오며 아주 훌륭한 보일러 플레이트로 실제 현업에서도 사용을 한다고 합니다. 실제로 웹팩의 새로운 버전이 나오기 전에 parcel이 간단한 설정과 사용법으로 인해 화두가 되었었고 gulp도 많이 사용한다고 합니다. 하지만 프로젝트마다 꼭 필요할 정도의 optimization이 필요하다면 가장 상세한 설정이 가능하기 때문에 웹팩이 유용하게 사용될 수 있다고 생각합니다.