Webpack과 Babel을 하나도 몰라도 Typescript, React, CSS까지 번들링 하는 법을 알아보겠습니다.
Webpack이 뭔지 Babel이 뭔지는 다른 블로그가 설명이 더 잘 되어있으니 여기서는 실습에 집중하겠습니다.
1. 일단 webpack 써보기
1 2 3 4
| $ mkdir webpack-test $ cd webpack-test $ npm init -y $ npm i -D webpack webpack-cli
|
위 명령어를 통해 NPM 프로젝트를 만들어 준 후 webpack
과 webpack-cli
를 설치합니다.
src/index.js1
| console.log("hello, world!");
|
src/index.js
에 위의 코드를 적습니다.
1
| $ npx webpack --mode none --entry ./src/index.js -o dist
|
콘솔창에 위와 같은 명령어를 입력하면 아래와 같은 내용이 적혀있는 파일이 dist/main.js
에 생성됩니다.
dist/main.js1 2 3 4
| (() => { console.log("hello, world"); })() ;
|
entry 옵션을 줄 때 src/index.js
와 같이 경로를 적으면 파일을 찾지 못합니다. ./src/index.js
와 같이 앞에 ./
을 붙여야합니다.
옵션을 파일로 주기 (webpack.config.js)
그런데 이렇게 일일히 옵션 입력하면 귀찮으니까 보통은 아래와 같이 webpack.config.js
를 만들어 줍니다.
위 파일을 생성한 다음에 npx webpack
명령어를 입력하면 위와 같은 동작을 하는 것을 알 수 있습니다.
webpack.config.js1 2 3 4 5 6 7 8 9 10
| const path = require('path');
module.exports = { mode: 'development', entry: './src/index.js', output: { filename: 'main.js', path: path.join(__dirname, '.'), }, }
|
여기서 output path에는 절대경로만 들어가야합니다.
2. 여러 파일을 하나로 묶기
src/math.js
파일을 생성하여 아래와 같이 적습니다.
src/math.js1
| module.exports.add = (a, b) => a + b;
|
src/index.js1 2 3
| const math = require('./math');
console.log(math.add(1, 2));
|
그러면 webpack이 알아서 dependency를 추적해서 관련된 모든 파일을 한 파일로 묶어줍니다.
1 2 3
| $ npx webpack $ node dist/main.js 3
|
ES6 모듈 시스템
node는 CommonJS 모듈 시스템을 쓰고 있습니다.
따라서 ES6 모듈 시스템을 사용할 수 없었는데
webpack을 사용하면 ES6 모듈 시스템을 쓸 수 있습니다.
math.js1
| export const add = (a, b) => a + b;
|
index.js1 2 3
| import * as math from './math';
console.log(math.add(1, 2));
|
1 2 3 4
| $ node src/index.js $ npx webpack $ node dist/main.js 3
|
3. webpack dev server
3.1. webpack watch
위의 명령어를 사용하면 webpack 데몬이 돌아가면서 파일이 변경될 때마다 자동으로 빌드해줍니다.
3.2. webpack dev server
1
| $ npm i -D webpack-dev-server
|
webpack-dev-server는 웹 브라우저에서 자동으로 live reload를 하게 해줌으로써 생산성을 높일 수 있습니다.
dist/index.html1 2 3 4 5 6 7 8
| <html> <head> <title>webpack-test</title> </head> <body> <script src="./main.js"></script> </body> </html>
|
webpack.config.js1 2 3 4 5 6
| module.exports = { + devServer: { + contentBase: path.join(__dirname, 'dist'), + hot: true, + }, }
|
위와 같이 html파일을 만들고 webpack.config.js 파일을 수정한 후 아래의 명령어로 server를 실행시킬 수 있습니다.
http://localhost:8080
경로에 웹 브라우저로 접속한 후 개발자 도구로 console 창을 확인하면 3이 떠있는 것을 볼 수 있습니다.
여기서 src 폴더의 파일을 수정하면 웹 페이지가 자동으로 새로고짐 됩니다.
contentBase 경로가 프로젝트 루트 경로이면 hot reloading이 되지 않습니다.
4. React
1
| $ npm i -D react react-dom @types/react @types/react-dom babel-loader @babel/core @babel/preset-react
|
src/index.js1 2 3 4 5 6 7 8 9 10 11
| import React from 'react' import ReactDOM from 'react-dom' import * as math from './math';
const App = () => { return ( <h1>{math.add(1, 2)}</h1> ) }
ReactDOM.render(<App />, document.getElementById('root'));
|
dist/index.html1 2 3 4 5 6 7 8 9
| <html> <head> <title>webpack-test</title> </head> <body> <div id="root"></div> <script src="./main.js"></script> </body> </html>
|
webpack.config.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| module.exports = { + module: { + rules: [ + { + test: /\.(js|jsx)$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-react'], + }, + } + } + ] + }, }
|
5. Typescript
1 2
| $ npm i -D ts-loader typescript $ npx tsc --init
|
src/index.ts1 2 3
| import * as math from './math.js';
console.log(math.add(1, 2));
|
src/math.ts1
| export const add = (a: number, b: number) => a + b;
|
webpack.config.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| module.exports = { ... - entry: './src/index.js', + entry: './src/index.ts', ... + resolve: { + extensions: ['.ts', '.js'] + }, module: { rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: ['ts-loader'], + }, ] }, }
|
webpack은 ts 확장자 파일을 자동으로 인식하지 않기 때문에 위와같이 extension으로 추가해주어야합니다.
6. Typescript + React
tsconfig.json1 2 3 4 5 6 7 8 9
| { "compilerOptions": { "target": "es6", "module": "es6", "jsx": "react", "moduleResolution": "node", "allowSyntheticDefaultImports": true } }
|
index.tsx1 2 3 4 5 6 7 8 9 10 11
| import React from 'react'; import ReactDOM from 'react-dom'; import * as math from './math';
const App = () => { return ( <h1>{math.add(1, 2)}</h1> ) }
ReactDOM.render(<App />, document.getElementById('root'));
|
webpack.config.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| module.exports = { ... - entry: './src/index.ts', + entry: './src/index.tsx', ... resolve: { - extensions: ['.ts', '.js'] + extensions: ['.ts', '.tsx', '.js'] }, module: { rules: [ { - test: /\.ts$/, + test: /\.(ts|tsx)$/, exclude: /node_modules/, use: ['ts-loader'], }, ] }, }
|
7. CSS
1
| $ npm i -D style-loader css-loader
|
webpack.config.js1 2 3 4 5 6 7 8 9 10 11
| module.exports = { module: { rules: [ + { + test: /\.css$/, + exclude: /node_modules/, + use: ['style-loader', 'css-loader'], + }, ] } }
|
css-loader
는 css 파일을 읽는 역할을 하고 style-loader
는 읽은 css 파일을 html 파일에 넣어주는 역할을 합니다.
css-loader
말고 less-loader
, sass-loader
, postcss-loader
등 많은 loader를 사용할 수 있습니다.