webpack
#
Find similar titles
- 최초 작성자
- 최근 업데이트
Structured data
- Category
- Programming
Table of Contents
webpack #
개요 #
'webpack은 모듈 번들러로, 의존성을 가진 모듈들을 다루고, 그 모듈로부터 정적인 asset을 생성한다.'
-webpack 공식페이지-
웹 서비스를 개발할 때 자바스크립트로 작성하는 코드의 양이 많아지면 유지, 보수가 쉽도록 코드를 모듈로 나누어 관리하는 모듈 시스템이 필요한데 자바스크립트는 언어 자체가 지원하는 모듈 시스템이 없다. webpack은 이런 한계를 극복하기 위한 도구 중 하나로 자바스크립트 모듈화 도구이다.
이 문서에선 간단한 Webpack 설명과 예제를 통해 Webpack5로 개발환경을 세팅하는 방법에 관해 설명한다.
프로젝트 생성 #
먼저 webpack으로 실행할 프로젝트 파일을 생성하고 node로 새로운 패키지를 생성한다.
npm init
혹은 -y를 추가해 기본 세팅을 건너뛰고 생성할 수 있다.
npm init -y
webpack과 함께 필수적인 webpack 패키지도 함께 다운로드 한다.
npm install webpack webpack-cli webpack-dev-server --save-dev
약자는 이렇게 된다.
npm i webpack webpack-cli webpack-dev-server -D
디렉터리 설정 #
디렉터리는 프로젝트를 빌드하거나 파일이나 문서를 연결할 때 주요한 요소 중 하나이기에 정확히 파악하는 것이 중요하다. 이 문서에서 다루는 프로젝트의 디렉터리는 다음과 같다.
dist
└── index.html
└── src
└── . . .
public
└── index.html
└── images
└── . . . .png/jpg
Src
└── index.js
└── htmls
└── . . . .html
└── scss
└── . . . .scss
└── js
└── . . . .js
└── images
└── . . . .png/jpg
tasks
└── webpack.config.js
package.json
package-lock.json
dist 폴더는 당장 있는 것이 아닌, webpack을 실행하고 난 후 생성된다. Webpack을 설정하는 데 필요한 webpack.config.js파일은 공식 문서에서는 가장 바깥에 있는 package.json과 같은 경로에 있지만 여기서는 깔끔한 파일 배치를 위해 tasks 파일 안에 있다. 이 경우 경로가 달라지는 점을 유의한다.
Webpack 설정하기 #
Webpack을 설정하는 webpack.config.js 파일을 만든다. 이 문서에서는 위의 디렉터리 설정대로 tasks 폴더 안에 만들었다.
Webpack 환경설정을 위해 중요한 객체들은 다음과 같다.
Entry: 모든 의존 객체들이 모인 Webpack의 시작점.
Output: 빌드할 때 JS와 정적 파일들(output files)의 경로를 설정.
Loaders: Webpack이 다양한 파일 확장자를 다룰 수 있도록 도와주는 서드파티 확장 프로그램. JS가 아닌 파일들을 모듈로 바꿔줌.
Plugins: Webpack의 동작 방식을 바꿔주는 서드파티 확장 프로그램.
Mode: 개발(development)과 생산(production) 두 모드 설정. Default는 생산(Production).
위의 객체들을 설명하기 전 config 파일의 기본적인 환경은 다음과 같다.
const webpack = require('webpack');
module.exports = {
mode: ‘ . . . ‘,
entry: { . . . },
output: { . . . },
module: { . . . },
};
Webpack을 실행하는 데에 필요한 플러그인들은 devDependencies에 다운로드 한다.
npm i . . . -D
다운로드 한 플러그는 config 파일 안에서 불러와 사용하면 된다.
const webpack = require('webpack');
entry #
Entry 안에 시작점이 될 JS 파일 경로를 입력한다.
module.exports = {
entry: '../src/dist/index.js',
}
더 정확한 경로를 위해 path를 사용할 수도 있다. Path는 기본적으로 node에 있는 값이기에 다운로드 할 필요 없이 Webpack에 가져오기만 하면 된다.
const path = require('path')
module.exports = {
entry: path.resolve(__dirname, ‘../src/js/index.js’)
}
상황에 따라 한 개 이상의 entry를 설정하기도 한다.
module.exports = {
entry: {
index : path.resolve(__dirname, ‘../src/index.js’),
main : path.resolve(__dirname, ‘../src/js/main.js’)
}
}
output #
Path에 Webpack으로 빌드한 파일 경로를 정하고 빌드한 파일 이름을 설정한다. Entry의 JS 파일들의 이름을 그대로 유지하고 싶다면 [name].js로 설정한다.
module.exports = {
output: {
path: path.resolve(__dirname, '../dist'),
filename: [name].js',
},
};
이렇게 하면 빌드된 JS 파일 디렉터리는 이렇게 된다.
dist
└── index.js
└── main.js
Filename으로 경로를 설정해 기획한 디렉터리대로 빌드되게 한다.
module.exports = {
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'src/js/[name].js',
},
};
결과는 다음과 같다.
dist
└── src
└── js
└── index.js
└── main.js
Plugins #
html-webpack-plugin #
html-webpack-plugin를 받아 웹페이지의 기본이 되는 index.html 파일을 읽고, 같은 파일에 번들을 삽입한다.
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
plugins: [
new HtmlWebpackPlugin ({
title: 'webpack5',
template: path.resolve(__dirname, '../ public /index.html'),
favicon: path.resolve(__dirname, '../public/images/favicon.png'),
filename: 'index.html',
}),
],
}
clean-webpack-plugin #
clean-webpack-plugin로 webpack을 실행할 때마다 생기는 dist와 dist 안 파일들을 지운다.
npm i clean-webpack-plugin -D
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin(),
]
}
webpack Dev Server #
모드는 config에서 설정할 수도 있지만 package.json 파일에 scripts를 수정해 명령어로도 설정할 수 있다.
{
"name": "webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
}
Webpack을 실행과 동시에 파일을 열기를 원한다면 –open을 추가하면 된다.
"scripts": {
"dev": "webpack serve --open --mode development",
}
이 프로젝트에는 config 파일이 task 폴더 안에 있으므로 script에서 경로를 표시해주어야 한다. serve –open과 모드 설정을 같이 실행할 경우, 순서가 중요하다.
"scripts": {
"dev": "webpack serve --open --mode=development --config tasks/webpack.config.js",
"build": "webpack --mode=production --config tasks/webpack. config.js"
}
이러면 상황에 따라 설정된 명령어로 프로젝트를 빌드 할 수 있다.
npm run dev // 개발모드
npm run build // 배포모드
module #
loader #
Webpack에는 파일 확장자를 다루기 위해 여러 종류의 loader, 서드파티 확장 프로그램이 있다.
loader는 module 객체 안, rules라는 속성으로 설정한다. loader의 일반적인 구문은 다음과 같다.
module.exports = {
module: {
rules: [
{
test: /\.filename1$/,
use: ['loader-b', 'loader-a'],
},
{
test: /\.filename2$/,
use: ['loader-d', 'loader-c'],
},
],
},
}
loader for script #
호환성을 위해 JS파일 babeling을 설정한다.
npm i babel-loader @babel/core @babel/preset-env -D
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
],
],
},
},
exclude: /node_modules/,
},
],
},
loader for style #
기본적으로 Webpack에서 CSS를 적용하기 위해서 우리는 2가지 loader가 필요하다. css-loader 와 style-loader 이 프로젝트에선 scss를 사용하기 때문에 Webpack으로 scss를 css로 컴파일링 하기 위해 sass, sass-loader 또한 필요하며, 호환성을 위해 'autoprefixer'도 함께 사용할 것이다.
npm i css-loader style-loader postcss-loader sass-loader autoprefixer -D
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [
'style-loader',
{
loader: "css-loader",
options: {
importLoaders: 2,
sourceMap: true,
url: false,
}
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
'autoprefixer',
]
}
}
},
'sass-loader'
],
exclude: /node_modules/,
}
],
},
또, 파일 크기를 줄이기 위해 mini-css-extract-plugin를 다운로드하여 plugins에 추가한다.
npm i mini-css-extract-plugin -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
plugins: [
new MiniCssExtractPlugin(),
],
}
컴파일링한 css파일을 원하는 경로에 넣으려면 아래와 같이 설정한다.
plugins: [ new MiniCssExtractPlugin({ filename: "src/css/style.css", chunkFilename: "[id].css" }), ],
Webpack은 js를 중심으로 파일을 빌드하기 때문에 설정한 scss파일을 entry-js파일에 import해줘야 한다. 여기서는 index.js파일에 import했다.
import './scss/style.scss';
이제 Webpack을 실행해보면 dist 폴더와 그 안의 내용물을 확인할 수 있다.
dist
└── index.html
└── src
└── js
└── index.js
└── main.js
└── css
└── style.css
Webpack 실행 결과 #
여기까지 파일은 다음과 같다.
webpack.config.js
const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index : paths.src,
main : path.resolve(__dirname, '../src') + '/js/main.js',
},
output: {
path: path.resolve(__dirname, '../dist),
filename: 'src/js/[name].js',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
corejs: { version: 3, proposals: true },
useBuiltIns: 'usage',
shippedProposals: true,
targets: {
browsers: ['>= 1%, not dead'],
},
},
],
],
},
},
exclude: /node_modules/,
},
{
test: /\.(scss|sass|css)$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: /node_modules/,
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack-5',
template: path.resolve(__dirname, '../dist) + '/index.html',
filename: 'index.html',
}),
new MiniCssExtractPlugin({
filename: "src/css/style.css",
chunkFilename: "[id].css"
}),
],
}
index.js
import './scss/style.scss';
console.log('index!!');
main.js
console.log('main.js');
style.scss
@charset 'utf-8';
body {
text-align: center;
background-color: orange;
.container {
background-color: pink;
p {
color: green;
font-weight: bold;
}
}
}
HTML 결과
JS 결과
디렉터리 결과
Mode 설정 및 config 파일 정리 #
Webpack은 모드에 따라 파일을 다르게 컴파일링 하는 것을 추천한다. 앞서 나온 대로 실행어로 mode를 설정할 수도 있지만 그럴 때 각 모드에 따른 디테일한 설정이 어렵기 때문에 다시 config 파일을 정리한다.
config파일은 공통된 값은 common, development에 따른 값은 dev, prod 3개로 나누어 작성한다. 여기서는 mode, css/scss, devtool, server을 다르게 설정할 것이다.
webpack.common.js
const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index : paths.src,
main : path.resolve(__dirname, '../src') + '/js/main.js',
},
output: {
path: path.resolve(__dirname, '../dist),
filename: 'src/js/[name].js',
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
corejs: { version: 3, proposals: true },
useBuiltIns: 'usage',
shippedProposals: true,
targets: {
browsers: ['>= 1%, not dead'],
},
},
],
],
},
},
exclude: /node_modules/,
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack-5',
template: path.resolve(__dirname, '../dist) + '/index.html',
filename: 'index.html',
}),
new MiniCssExtractPlugin({
filename: "src/css/style.css",
chunkFilename: "[id].css"
}),
],
}
Dev와 prod 파일을 실행할 때도 common값을 가져오기 위해 'webpack-merge'를 다운받아 연결한다.
npm i webpack-merge -D
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
( . . . )
});
개발자 모드일 때는 코드 수정이 잦아 코드값을 잘 찾기 위해 minimize는 피하고 source-map도 가독성이 높은 inline-source-map가 좋다. 또한 실행되는 화면을 확인하기 위해 sever port를 설정해야 한다.
webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const paths = require('./paths');
module.exports = merge(common, {
mode: 'development',
module: {
rules: [
{
test: /\.(scss|sass|css)$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: /node_modules/,
},
],
},
devtool: 'inline-source-map',
devServer: {
contentBase: paths.build,
compress: true,
hot: true,
port: 8000,
},
});
webpack.prod.js
const { merge } = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const common = require('./webpack.common.js');
const paths = require('./paths');
module.exports = merge(common, {
mode: 'production',
module: {
rules: [
{
test: /\.(scss|sass|css)$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
exclude: /node_modules/,
},
],
},
devtool: 'cheap-module-source-map',
});
config 파일이 바뀌었으니 package.json 안 script 파일도 수정하면 각 모드에 맞춰 파일이 컴파일링 된다.
"scripts": {
"build": "webpack --config tasks/webpack.prod.js",
"dev": "webpack serve --open --config tasks/webpack.dev.js"
},