Webpack
webpack은 Node.js 런타임 기반의 웹어플리케이션을 구성하는 자원을 모듈
단위로 번들링 해주는 도구이다. 프론트엔드 개발 트렌드로 자주 사용되는
라이브러리, 프레임워크(React, Vue 등)는 프로젝트 파일의 크기가 큰 경우가
대다수이기 때문에 webpack을 통하여 파일들간의 의존성 관계를 정리하고
코드를 최적화하여 하나의 스크립트 파일로 만들어 주로 최적화된 서비스를
제공하기 위해 사용된다.
Webpack의 장점
- 코드를 축소하여 최적화하고 사용하지 않는 코드를 제거하여 빌드하는 방식으로 성능을 최적화할 수 있다.
- CSS가 아닌 SASS 혹은 stylus, Typescript 사용 시 컴파일 과정에서 필요 플러그인을 추가하고 번들러를 실행해준다.
- 종속성 문제의 해결
Webpack의 단점
- 일부 패키지들을 loader를 통해 매번 추가해주어야 하며 추가하고자 하는 자원의 타입에 따라 추가해 주어야 하는 loader가 다를 수 있기 때문에 러닝커브가 다소 있는 편이다.
Install
# 웹팩, 개발자 서버 인스톨
npm i -D webpack webpack-dev-server
# 필요한 플러그인 및 로더 설치 (css, sass, static copy plugin, env 등)
npm i -D html-webpack-plugin dotenv-webpack css-loader copy-webpack-plugin cross-env source-map-loader sass-loader clean-webpack-plugin
웹팩(개발자 서버 포함)과 필요한 로더와 플러그인을 설치한다.
webpack.config.js 분리
html / css / vanillaJS 구성으로 웹팩 적용하였으며 config 작성할 때 common, dev, prod로
나누어 빌드환경에 맞춰 별도로 관리해주었다.
webpack.common.js
공통으로 적용 될 config를 작성한다.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const DotEnv = require('dotenv-webpack');
module.exports = {
entry: {
main: path.resolve(__dirname, '../src/script.js'),
},
output: {
path: path.resolve(__dirname, '../public'),
filename: '[name].min.js'
},
// target: ['web', 'es5'], // es5 환경 작업 시 사용
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
enforce: 'pre',
use: ['source-map-loader'],
},
{
test: /\.s?css$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(glb|gltf)$/,
use: ['file-loader']
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/index.html'),
filename: 'index.html',
minify: true,
}),
// origin 그대로 복사할 파일을 지정
new CopyWebpackPlugin({
// 빌드 시 public 폴더에 자동 생성(patterns 경로에 해당 파일이 없으면 에러발생)
patterns: [
{ from: path.resolve(__dirname, '../static') },
{ from: path.resolve(__dirname, '../src/style.css') },
]
}),
// dotenv-webpack패키지를 통한 환경변수(env) 사용
new DotEnv({ path: '.env' }),
]
};
webpack.dev.js
webpack.common.js에 추가적으로 개발자 서버에서만 적용될 config를 작성한다.
const path = require('path')
const { merge } = require('webpack-merge')
const commonConfiguration = require('./webpack.common.js')
module.exports = merge(
commonConfiguration,
{
mode: 'development',
devServer: {
liveReload: true,
static: {
directory: path.resolve(__dirname, '../public')
},
// hot: true,
watchFiles: ['src/**/*'],
port: 3000,
},
}
)
webpack.prod.js
webpack.common.js에 추가적으로 빌드 시 적용될 config를 작성한다.
const { merge } = require('webpack-merge')
const commonConfiguration = require('./webpack.common.js')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
module.exports = merge(
commonConfiguration,
{
mode: 'production',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.s?css$/,
use: [MiniCssExtractPlugin.loader, 'style-loader', 'css-loader', 'sass-loader']
}
]
},
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
// 빌드 시 콘솔로그 drop
drop_console: true
}
}
})
],
splitChunks: { chunks: 'all' }
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin(),
// build 과정에서 환경변수 사용 가능하도록 설정
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), // 환경변수 접근 필수 지정!
'process.env.FIREBASE_API_KEY': JSON.stringify(process.env.FIREBASE_API_KEY),
'process.env.FIREBASE_AUTH_DOMAIN': JSON.stringify(process.env.FIREBASE_AUTH_DOMAIN),
'process.env.FIREBASE_PROJECT_ID': JSON.stringify(process.env.FIREBASE_PROJECT_ID),
'process.env.FIREBASE_SENDER_ID': JSON.stringify(process.env.FIREBASE_SENDER_ID),
'process.env.FIREBASE_APP_ID': JSON.stringify(process.env.FIREBASE_APP_ID),
'process.env.FIREBASE_MEASUREMENT_ID': JSON.stringify(process.env.FIREBASE_MEASUREMENT_ID),
})
]
}
)
package.json
scripts를 수정하여 webpack을 적용한다.
{
"scripts": {
"start": "webpack serve --open --config ./bundler/webpack.dev.js",
"build": "webpack --config ./bundler/webpack.prod.js"
},
}
마치며...
주로 react를 create-react-app을 통해 보일러플레이트를 설치하여 개발을 진행하였고 webpack은 create-react-app을 통해 함께 설치되며 최적화에 도움을 준다는 기본적인 개념만 알고있었다.
이렇게 웹팩을 직접 프로젝트에 도입하며 경험해보니 그 동안 create-react-app을 통해 react 보일러플레이트를 설치하고 이미 구성되어있는 편리한 환경속에서 webpack을 사용하고 있었다는 것을 깨달았다.
생각했던 것 보다 높은 자유도 때문인지 러닝커브를 느꼈던 것 같고 특히나 환경변수를 적용하는 것이 가장 어려웠다...
항상 그렇듯 알고나면 별거 아니지만 그 과정은 험난했고, 이 후에 문제를 극복하며 따라오는 만족감은 이로 말할 수 없는 것 같다. 아직도 갈 길이 멀었음을 깨달았고 다시 한 번 더 열심히 정진해야겠다는 다짐을 굳히는 시간들이었다.