const path = require('path'); const { VueLoaderPlugin } = require('vue-loader'); const MiniCssExtractPlugin = require('mini-css-extract-plugin') const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const { resolve } = require('path'); const CleanTerminalPlugin = require('clean-terminal-webpack-plugin'); const { EsbuildPlugin } = require('esbuild-loader') const webpack = require('webpack'); const fs = require('fs'); module.exports = (env, argv) => { const rawTarget = env.target ?? 'hwe'; const target = (rawTarget == 'gateway') ? 'hwe' : rawTarget; const mode = argv.mode ?? 'production'; const tsDir = resolve(__dirname, `${target}/ts/`); const scssDir = resolve(__dirname, `${target}/scss/`); const build_exports = require(`${tsDir}/build_exports.json`); const versionGitPath = resolve(__dirname, target, 'd_setting', 'VersionGit.json'); const versionValue = (() => { if (!fs.existsSync(versionGitPath)) { return undefined; } const versionInfo = JSON.parse(fs.readFileSync(versionGitPath, 'utf-8')); return versionInfo.versionGit; })() const versionTarget = versionValue ?? `${target}_dynamic`; const outputPath = resolve(__dirname, 'dist_js', versionTarget); fs.mkdirSync(outputPath, { recursive: true }); const genBuildHook = function (oTarget) { const checkFilePath = resolve(outputPath, `build_${oTarget}.txt`); let emitDone = false; let writeDone = false; return function (percentage, msg, ...args) { if (msg == 'emitting') { emitDone = true; } if (percentage == 0) { if (fs.existsSync(checkFilePath)) { fs.unlinkSync(checkFilePath); } } else if (percentage == 1 && emitDone && !writeDone) { fs.writeFileSync(checkFilePath, new Date().toISOString(), 'utf-8'); writeDone = true; } }; }; //TODO: esbuild에 browserslist 사용 가능하면 적용 //서버마다 ts 파일 구성이 다를 가능성이 높기 때문에 어떤 파일이 필요한지는 ts/build_exports.json을 확인한다. const entryIngameVue = {}; for (const [entry, filePath] of Object.entries(build_exports.ingame_vue) ?? []) { entryIngameVue[entry] = `${tsDir}/${filePath}`; } const entryIngame = {}; for (const [entry, filePath] of Object.entries(build_exports.ingame) ?? []) { entryIngame[entry] = `${tsDir}/${filePath}`; } entryIngameVue['bootstrap'] = `${scssDir}/bootstrap.scss`; const cacheDirectory = path.resolve(__dirname, 'node_modules/.cache/webpack'); //const devtool = mode != 'production' ? 'eval-source-map' : (env.WEBPACK_WATCH ? 'source-map' : undefined); const devtool = mode != 'production' ? 'eval-source-map' : 'source-map'; const optimization = { splitChunks: { cacheGroups: { commons: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: -10, chunks: 'all', reuseExistingChunk: true, }, default: { name: 'common_ts', minChunks: 2, priority: -20, chunks: 'all', reuseExistingChunk: true, }, }, }, minimizer: [ new EsbuildPlugin({ css: true }), ], moduleIds: 'deterministic', }; const performance = { maxAssetSize: 5 * 1024 * 1024, maxEntrypointSize: 3 * 1024 * 1024, } const ingame_vue = { name: `ingame_${versionTarget}_vue`, resolve: { extensions: [".ts", ".tsx", ".vue", ".js"], alias: { vue: "@vue/runtime-dom", '@': tsDir, '@scss': path.resolve(tsDir, '../scss'), '@util': path.resolve(tsDir, 'util'), }, }, mode, entry: entryIngameVue, output: { filename: '[name].js', path: resolve(outputPath, 'vue') }, devtool, optimization, module: { rules: [ //FROM `vue inspect` and some tweaks { test: /\.ts$/, //exclude: /(node_modules)/, use: [ { loader: 'esbuild-loader', options: { loader: 'ts', target: 'es2021', } } ] }, { test: /\.tsx$/, //exclude: /(node_modules)/, use: [ { loader: 'esbuild-loader', options: { loader: 'tsx', target: 'es2021', } } ] }, { test: /\.js$/, exclude: /(node_modules)/, use: [ { loader: 'esbuild-loader', options: { loader: 'js', target: 'es2021', } } ] }, { test: /\.vue$/, loader: 'vue-loader', //exclude: /(node_modules)/, options: { hotReload: false, } }, { test: /\.vue\.(s?[ac]ss)$/, use: ['vue-style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] }, { test: /(?