리액트 웹팩으로 개발환경 구축하기(without CRA)
How to set up React, Webpack, and Babel: what you will learn
webpack boiler-plate repository
프로젝트 폴더 생성 및 package.json을 생성한다.
webpack-react-study
폴더를 생성하고 package.json
파일 생성
$ mkdir webpack-react-study
$ cd webpack-react-study
$ npm init -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-cli -D
설치된 라이브러리?
react // 리액트
react-dom // 브라우저 DOM을 제어한다. UI를 렌더링할때 사용
@babel/core // babel의 핵심 라이브러리, es6를 es5로 컴파일
babel-loader // babel과 webpack을 사용해서 자바스크립트 파일을 컴파일
@babel/preset-env // es6, es7 버전을 지정안해도 babel이 자동 탐지
@babel/preset-react // 리액트(JSX)를 js로 인식 가능케 함
css-loader // css 파일을 import 또는 require 가능케 함
style-loader // css 파일을 style 태그로 만들어 head에 삽입
html-webpack-plugin // 웹팩 번들에 html 파일을 제공
webpack // 웹팩을 사용
webpack-dev-server // 웹팩 개발 서버를 구동
webpack-cli // 웹팩 커멘드라인을 사용
babel이란 es6 코드를 이전 버전에서 실행가능하도록 변환해주는 컴파일러이다.
프로젝트 최상위 webpack-react-study
에 바벨 설정 파일을 만든다.
$ touch .babelrc
.babelrc
파일을 만들어서 아래와 같이 코드를 추가한다. babel 그 자체로는 아무것도 동작하지 않기 때문에 plugin을 설치해야 한다. .babelrc
라는 파일은 바벨에 대한 플러그인을 설정해주는 파일이다.
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
매번 플러그인을 설치하고 등록하기가 귀찮아서 presets
라는 기능을 만들었다. presets
이 무엇이냐면 플러그인들을 포함한 번들 파일인데, 한번만 설정하면 자동으로 설치된다.
webpack.config.js
라는 파일을 생성하자.
$ touch webpack.config.js
하단에 아래와 같은 코드를 작성하자!
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const port = process.env.PORT || 3000;
module.exports = {
// webpack 설정 코드 작성. 작성된 코드는 module.export로 내보냅니다.
};
webpack.config.js
파일 안에 아래 코드를 추가한다. mode
옵션은 웹팩 설정이 development 모드인지 production 모드인지 정한다.
...
module.exports = {
mode: 'development',
};
entry
옵션은 앱이 있는 위치와 번들링 프로세스가 시작되는 지점이다. 웹팩4 부터는 entry 옵션을 생략할 수 있다고 한다. 생략할 경우에는 ./src/index.js
를 기본으로 가정한다.
output
옵션은 번들링 프로세스가 끝난 뒤 번들링 된 파일을 저장할 장소와 이름을 지정한다. 번들링된 파일 이름을 bundle.[hash].js
로 하고, 그 파일을 ./dist
에 저장하라는 의미이다.
_filename의 [hash]는 어플리케이션이 수정되어 다시 컴파일될 때마다 웹팩에서 생성된 해시로 변경해 캐싱에 도움이 된다.
module.exports= {
...
entry:'./src/index.js',
output:{
path: __dirname + '/dist',
filename: 'bundle.[hash].js'
}
}
...
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
옵션은 번들링 과정에서 사용할 규칙을 설정한다. ES6, ES7 문법으로 작성된 JS 파일을 ES5로 바꾸기 위해 작성했던 .babelrc
를 babel-loader
를 이용해 규칙에 적용한다.
node_modules
폴더를 제외한 모든 .js
파일에 babel-loader
(.babelrc
에 설정한 파일)를 적용한다.
.js
파일에서 import 또는 require로 .css
파일을 가져올 수 있게 해주는 css-loader와 .css
파일을 style 태그로 만든 뒤 head 태그 안에 삽입해주는 style-loader를 규칙에 적용한다. css-loader의 option에서 modules는 CSS Module을 사용하는 것을, camelCase는 해당 옵션으로 CSS를 사용할 것을 의미한다.
plugins 옵션은 웹팩 번들링 과정에 적용할 플러그인을 설정해준다. HtmlWebpackPlugin은 html 파일이나 favicon을 번들링 과정에 포함한다. 예를 들어 번들된 파일 bundle.[hash].js
를 index.html에 자동 삽입해준다.
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
})
],
};
devServer 개발 서버를 정의하는 옵션이다. host는 로컬호스트로 지정하고 port는 상단에서 정의한 값으로 설정해준다. open: true
은 서버를 시작했을 때 자동으로 브라우저를 열어주는 옵션이고, historyApiFallback
은 브라우저에서 URL을 변경할 수 있도록 도와주는 옵션이다.
module.exports = {
...
devServer: {
host: 'localhost',
port: port,
open: true,
historyApiFallback: true
}
};
먼저 HtmlWebpackPlugin에 사용되는 index.html
을 아래와 같이 생성한다.
mkdir public && cd $_ && touch 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
// 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;
}
...
"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"
}
}
리액트를 실행한다. 개발 서버를 작동한다!
$ npm start