생계유지형 개발자/JS Framework
[Webpack5] 배포환경 별 빌드 설정 및 실행하기 (webpack-merge, dotenv)
이 가을
2023. 2. 13. 21:23
내가 일하는 곳에서는 배포환경을 주로 다음과 같이 셋 또는 넷으로 설정한다.
- Local
- Develop
- Real
- Staging
이번에는 webpack 사용하여 공통 js모듈을 개발했는데 빌드 설정 하면서 웹팩에서 기본으로 사용하는 mode 이름 때문에 조금 애먹었다.
웹팩에서 사용하는 mode는 none | development | production 세 종류가 있는데, none은 말 그대로 논이고, development가 이제 내가 생각하는 Local 느낌이고 production이 real 같은 배포용이다.
mode를 저 세개 외에 다른 이름은 사용할 수 없다. 다른거 입력하면 웹팩 실행할 때 에러난다.
나는 개발환경에 배포하는거 이름을 굳이굳이 development로 하겠다고 package.json 스크립트에 "build.dev": webpack --mode=development 이렇게 써놓고 빌드하니까 자꾸 안됐다. ㅋㅋ
webpack.config.js
배포환경 별 webpack config파일을 생성해주되, 웹팩 가이드에서 제공하는 것처럼 빌드 실행된 환경의 파일에서 공통 webpack.confg.js 를 merge하는게 아니라 webpack.config.js 파일에서 환경에 맞는 파일을 merge한다.
npm 실행할 때 target 이라는 이름의 argument로 환경이름(local, dev, real)을 전달한다.
// package.json
"scripts": {
"start": "webpack serve --mode=development --host=local.host.com",
"build.dev": "webpack --mode=production --env target=dev",
"build.prod": "webpack --mode=production --env target=real"
}
target을 전달받은 webpack.config.js 내부에서는 target에 해당하는 .env 파일과 webpack 설정파일을 불러온다.
// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const dotenv = require("dotenv")
const { merge } = require('webpack-merge');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devConfig = require("./webpack.dev")
const realConfig = require("./webpack.real")
const localConfig = require("./webpack.local")
module.exports = (env, args) => {
const target = args.env.target || "local" // target -> real | dev | local (default)
/** dotenv 설정 */
dotenv.config({
path: path.resolve(__dirname, ".env." + target), debug: target === "local"
})
const commonConfig = {
entry: {
desktop: path.resolve(__dirname, 'src/pc/index'),
mobile: path.resolve(__dirname, 'src/mobile/index')
},
output: {
filename: "[name].js",
clean: true,
path: path.resolve(__dirname, 'dist'),
library: {
name: 'ConnectComment',
type: 'umd',
},
},
optimization: {
minimize: true,
splitChunks: {
chunks: "all",
minChunks: 1,
name: false
}
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' },
{ test: /\.(sa|sc|c)ss$/i, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] },
//{ test: /\.(png|svg|jpg|jpeg|gif)$/i, use: [{ loader: "file-loader", options: { name: '[name].[ext]' } }]},
{ test: /\.(png|svg|jpg|jpeg|gif)$/i, type: 'asset/resource' },
{ test: /\.(woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource' },
{
test: /\.m?js$/, include: path.resolve(__dirname, 'src'), exclude: /(node_modules|bower_components)/,
use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } }
}
],
},
plugins: [
new MiniCssExtractPlugin(),
new webpack.DefinePlugin({
"__env": JSON.stringify(process.env)
}),
],
resolve: {
extensions: [".ts", ".js"],
modules: [path.join(__dirname, "src"), "node_modules"],
},
}
switch (target) {
case 'dev':
return merge(commonConfig, devConfig);
case 'real':
return merge(commonConfig, realConfig);
case 'local':
return merge(commonConfig, localConfig);
default:
throw new Error('No matching configuration was found!');
}
}
// webpack.local.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: "development",
plugins: [
new HtmlWebpackPlugin({ filename: 'desktop.html', chunks: ["desktop"], minify: true, template: './src/pc/index.html' }),
new HtmlWebpackPlugin({ filename: 'mobile.html', chunks: ["mobile"], template: './src/mobile/index.html' }),
],
devtool: 'source-map',
devServer: {
host: "http://local.host.com",
port: 8081,
historyApiFallback: true,
static: {
directory: path.resolve(__dirname, 'dist')
},
}
}
// webpack.prod.js (== webpack.dev.js)
const path = require('path');
module.exports = {
mode: 'production',
output: {
filename: "[name].js",
clean: true,
path: path.resolve(__dirname, 'dist'),
//iife: true,
library: {
name: 'ConnectComment',
type: 'umd',
},
},
}