생계유지형 개발자/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',
		},
	},
}