지인의 블로그를 보다가 충격적인 사실을 발견했다.
"내가 회사에 가서도 CRA를 통해 개발할까? " 🤔
에 대한 답변이 X(아니?) 라는 사실이였다. 몇개월 뿐이지만 리액트를 공부한 시점부터 현재까지 리액트로 개발한 프로젝트를 모두 CRA를 통해 진행하였다. 그래서 난 이게 당연하고 정답인줄 알았다. 하지만 이곳의 세계는 너무나도 깊었다. 해답을 찾던중 webpack으로 CRA를 대신할수 있다는 사실을 알았고 이에 대해 공부하고 모르는 개념을 정리하는 시간을 가져보도록 하겠다.
먼저 웹팩에 대해 알아보겠다. 구글에 웹팩을 검색하게되면 **"자바스크립트 모듈 번들러"**라고 나온다. 근데 모듈 번들러가 뭘까?
실습하기 전 node가 준비되어야 한다.
(의존성 초기화)
webpack-react-study
폴더를 생성하고 package.json
파일 생성
mkdir webpack-react-study && cd $_
yarn init -y
-y 옵션은 All Yes로 yarn init만 했을시 나타나는 질문에 모두 yes로 넘어가게 해준다. 원하는대로 설정해도 상관 없으나 필자는 -y옵션으로 진행했다.
package.json
파일은 아래와 같을 것이다.
{
"name": "webpack-react-study",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}
이번 실습을 진행할때 필요한 초기 라이브러리를 설치하겠다. 초기 프로덕션 의존성(production dependencies) 과 개발 의존성(development dependencies)을 설치한다. 개발 의존성은 개발 단계에서만 사용되는 의존 라이브러리이며, 프로덕션 의존성은 배포 단계에서 사용되는 라이브러리를 말한다.
yarn add react react-dom
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-react css-loader style-loader html-webpack-plugin webpack webpack-dev-server webpack webpack-cli -D
설치된 라이브러리가 무엇인지 간단하게 알아보자.
- react: 리액트
babel이 무엇인가 하면 babel은 es6코드를 이전 버전에서 실행 가능하도록 변환해주는 컴파일러이다. babel에 대한 사용법은 나중에 아래에서 살펴보자.
프로젝트 최상위 webpack-react-study
에 바벨 설정 파일을 만든다.
touch .babelrc
.babelrc
파일을 열어 아래와 같이 코드를 추가한다.
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
- babel 그 자체로는 아무것도 동작하지 않는다. 무언가 하게하려면 plugin을 설치한다.
지금부터 웹팩을 설정해보자. webpack.config.js
라는 파일을 생성하자.
touch webpack.config.js
그 다음 아래 코드를 작성하자.
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const port = 3000;
module.exports = {
// webpack 설정 코드 작성. 작성된 코드는 module.export로 내보냅니다.
};
- 기본적으로 webpack과 html-webpack-plugin이 필요하다.
webpack.config.js
파일을 열어 아래 코드를 추가하도록 하자.
...
module.exports = {
mode: 'development',
};
- mode옵션은 웹팩 설정이 development(개발)모드인지 production(프로덕션) 모드인지 정한다.
module.exports= {
...
entry:'./src/index.js',
output:{
path: __dirname + '/dist',
filename: 'bundle.[hash].js'
}
}
- entry 옵션은 앱이 있는 위치와 번들링 프로세스가 시작되는 지점이다.
...
module.exports = {
...
module: {
rules: [
// 첫 번째 룰
{
test: /\.(js)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
// 두 번째 룰
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
camelCase: true,
}
}
]
}
]
},
};
- module옵션은 번들링과정에서 사용할 규칙을 설정한다.
/src/App.css
.main_wrapper {
background-color: blue;
}
라는 클래스가 있다면
/src/App.js
import { mainWrapper } from 'App.css`;
와 같이 사용가능하다.
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
})
],
};
- plugins옵션은 웹팩 번들과정에 적용할 플러그인을 설정해준다.
bundle.[hash].js
를 index.html에 자동 삽입해준다.module.exports = {
...
devServer: {
host: 'localhost',
port: port,
open: true,
historyApiFallback: true
}
};
- devServer 개발서버를 정의하는 옵션이다.
webpack.config.js
코드const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const port = 3000;
module.exports = {
mode: 'development',
entry:'./src/index.js',
output:{
path: __dirname + '/dist',
filename: 'bundle.[hash].js',
publicPath: '/'
},
module: {
rules: [
// 첫 번째 룰
{
test: /\.(js)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
// 두 번째 룰
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
localsConvention: 'camelCase',
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
})
],
devServer: {
host: 'localhost',
port: port,
open: true,
historyApiFallback: true,
hot: true
}
};
먼저 HtmlWebpackPlugin에 사용되는 index.html
을 아래와 같이 생성한다.
mkdir public && cd $_ && touch index.html
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>webpack-react-study</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
루트 디렉토리로 돌아와 index.js
를 생성한다.
mkdir src && cd $_ && touch index.js
components/App.js와 App.css를 생성하고 아래와 같이 코드를 작성한다.
mkdir components && cd $_ && touch App.js App.css
src/components/App.js
import React from 'react';
import { mainWrapper } from './App.css';
const App = () => {
return (
<div className={mainWrapper}>
<h1>Hello, Webpack!!! with React</h1>
</div>
);
};
export default App;
src/components/App.css
.main_wrapper {
background-color: blue;
}
리액트 프로젝트가 거의 다 완성됐다.
package.json
에 script를 추가하자.
...
"scripts": {
"start": "webpack-dev-server"
},
...
package.json
전체 코드는 아래와 같다.
{
"name": "webpack-react-study",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
"babel-loader": "^8.1.0",
"css-loader": "^3.5.3",
"html-webpack-plugin": "^4.2.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
}
}
이제 터미널에서 yarn start
로 개발 서버를 작동한다.
아래 사진과 같이 번들 파일이랑 css가 잘 적용된 모습을 볼수 있다.
먼저 react-hot-loader란 코드가 변경되었을 때 페이지를 새로고침하지 않고 바뀐부분만 빠르게 교체해주는 라이브러리이다.
그럼 터미널에서 react-hot-loader를 설치하자.
yarn add react-hot-loader -D
그다음 .babelrc
파일을 열고 plugin을 추가해주자.
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["react-hot-loader/babel"]
}
webpack.config.js
도 수정해주자.
...
module.exports = {
entry: './src/index.js',
output: {
...
publicPath: '/'
},
...
plugins: [
new webpack.HotModuleReplacementPlugin(),
...
],
devServer: {
...
hot: true
}
};
- publicPath: '/' Hot reloading은 중첩된 경로에서 동작하지 않는다고 하여 설정해주지 않을경우 핫리로딩이 작동이 안된다 하는데 나는 자세하겐 모르겠다.
webpack.HotModuleReplacementPlugin
이 자동으로 추가된다고 했는데 확실하겐 모르겠다. webpack.HotModuleReplacementPlugin
이 없고 hot: true
만 있을때 핫리로딩이 잘 작동하긴 한다.App.js
에 hot을 적용시키자.
import { hot } from 'react-hot-loader';
...
export default hot(module)(App);
yarn start
로 실행후 App.js
를 수정후 저장해보자. 브라우저가 새로고침하지 않고 변경사항이 반영된 모습을 볼수 있다. 또 크롬 개발자 도구에서 Rendering -> Paint를 선택하면 사진과 같이 변겨오딘 부분에 블럭이 생겨 눈에 띈다.
⬆ 위로가기
이번엔 프로젝트를 빌드해보도록 하겠다.
yarn build
로 빌드를 하자.
아래 사진과 같이 정상적으로 dist폴더 밑에 bundle.[hash].js와 html이 생기는걸 볼수 있다.
오늘 처음으로 CRA를 사용하지 않고 webpack으로만 리액트 프로젝트를 구동시켜 봤다. 무작정 예제를 따라하고 에러가 났다. 그래서 공식 문서를 찾고 고쳐가면서 웹팩을 구성하는 부분이 무엇인지 알았고 이해할수 있엇다.
하지만 오늘 내가 정리한게 다가 아니다. webpack의 일부분만 배운것이다. 앞으로 웹팩의 다양한 기능을 공부하고 어느정도 작지않은 프로젝트를 webpack으로 개발해 볼것이다.
항상 CRA로 작업하다가 이번에 처음으로 웹팩을 배우고 있는데, 찾아본 블로그 중에서 가장 이해가 잘 되게 정리해주신 것 같아요! 잘 배우고 갑니다 •͈ᴗ•͈