1const CompressionPlugin = require('compression-webpack-plugin'); 2const webpack = require('webpack'); 3const LimitChunkCountPlugin = webpack.optimize.LimitChunkCountPlugin; 4 5module.exports = { 6 css: { 7 loaderOptions: { 8 sass: { 9 additionalData: (() => { 10 const envName = process.env.VUE_APP_ENV_NAME; 11 const hasCustomStyles = process.env.CUSTOM_STYLES === 'true'; 12 if (hasCustomStyles && envName !== undefined) { 13 return ` 14 @import "@/assets/styles/bmc/helpers"; 15 @import "@/env/assets/styles/_${envName}"; 16 @import "@/assets/styles/bootstrap/_helpers"; 17 `; 18 } else { 19 return ` 20 @import "@/assets/styles/bmc/helpers"; 21 @import "@/assets/styles/bootstrap/_helpers"; 22 `; 23 } 24 })(), // immediately invoked function expression (IIFE) 25 }, 26 scss: { 27 additionalData: (() => { 28 const envName = process.env.VUE_APP_ENV_NAME; 29 const hasCustomStyles = process.env.CUSTOM_STYLES === 'true'; 30 if (hasCustomStyles && envName !== undefined) { 31 return ` 32 @import "@/assets/styles/bmc/helpers"; 33 @import "@/env/assets/styles/_${envName}"; 34 @import "@/assets/styles/bootstrap/_helpers"; 35 `; 36 } else { 37 return ` 38 @import "@/assets/styles/bmc/helpers"; 39 @import "@/assets/styles/bootstrap/_helpers"; 40 `; 41 } 42 })(), 43 }, 44 }, 45 }, 46 devServer: { 47 // Set DEV_HTTPS=true to run with HTTPS (helpful for testing secure-only features or with a signed cert) 48 // ref https://webpack.js.org/configuration/dev-server/#devserverserver 49 server: 50 process.env.DEV_HTTPS === 'true' ? { type: 'https' } : { type: 'http' }, 51 proxy: { 52 '/': { 53 target: process.env.BASE_URL, 54 onProxyRes: (proxyRes) => { 55 delete proxyRes.headers['strict-transport-security']; 56 }, 57 }, 58 }, 59 port: 8000, 60 }, 61 productionSourceMap: false, 62 chainWebpack: (config) => { 63 config.module 64 .rule('vue') 65 .use('vue-svg-inline-loader') 66 .loader('vue-svg-inline-loader'); 67 config.module 68 .rule('ico') 69 .test(/\.ico$/) 70 .use('file-loader') 71 .loader('file-loader') 72 .options({ 73 name: '[name].[contenthash:8].[ext]', 74 }); 75 config.plugins.delete('preload'); 76 if (process.env.NODE_ENV === 'production') { 77 config.plugin('html').tap((options) => { 78 options[0].filename = 'index.[hash:8].html'; 79 return options; 80 }); 81 } 82 }, 83 configureWebpack: (config) => { 84 config.plugins.push( 85 new LimitChunkCountPlugin({ 86 maxChunks: 1, 87 }), 88 ); 89 config.optimization.splitChunks = { 90 cacheGroups: { 91 default: false, 92 }, 93 }; 94 const crypto = require('crypto'); 95 const crypto_orig_createHash = crypto.createHash; 96 crypto.createHash = (algorithm) => 97 crypto_orig_createHash(algorithm == 'md4' ? 'sha256' : algorithm); 98 99 const envName = process.env.VUE_APP_ENV_NAME; 100 const hasCustomStore = process.env.CUSTOM_STORE === 'true'; 101 const hasCustomRouter = process.env.CUSTOM_ROUTER === 'true'; 102 const hasCustomAppNav = process.env.CUSTOM_APP_NAV === 'true'; 103 104 if (envName !== undefined) { 105 if (hasCustomStore) { 106 // If env has custom store, resolve all store modules. Currently found 107 // in src/router/index.js src/store/api.js and src/main.js 108 config.resolve.alias['./store$'] = `@/env/store/${envName}.js`; 109 config.resolve.alias['../store$'] = `@/env/store/${envName}.js`; 110 } 111 if (hasCustomRouter) { 112 // If env has custom router, resolve routes in src/router/index.js 113 config.resolve.alias['./routes$'] = `@/env/router/${envName}.js`; 114 } 115 if (hasCustomAppNav) { 116 // If env has custom AppNavigation, resolve AppNavigationMixin module in src/components/AppNavigation/AppNavigation.vue 117 config.resolve.alias['./AppNavigationMixin$'] = 118 `@/env/components/AppNavigation/${envName}.js`; 119 } 120 } 121 122 if (process.env.NODE_ENV === 'production') { 123 config.plugins.push( 124 new CompressionPlugin({ 125 deleteOriginalAssets: true, 126 }), 127 ); 128 } 129 130 config.performance = { 131 hints: 'warning', 132 maxEntrypointSize: 512000, 133 maxAssetSize: 512000, 134 }; 135 136 config.optimization.runtimeChunk = false; 137 138 // Define Vue 3 compile-time feature flags 139 // These flags must be explicitly defined to avoid Vue warnings and optimize bundle size 140 config.plugins.push( 141 new webpack.DefinePlugin({ 142 // Enable Options API support (required - this codebase uses Options API extensively) 143 // Setting to true includes Options API in the bundle (~3kb gzipped) 144 // Cannot be disabled until full migration to Composition API 145 __VUE_OPTIONS_API__: JSON.stringify(true), 146 147 // Disable Vue Devtools in production builds for security and performance 148 // Devtools automatically enabled in development mode regardless of this flag 149 __VUE_PROD_DEVTOOLS__: JSON.stringify(false), 150 151 // Disable detailed hydration mismatch warnings in production 152 // This is a SPA (not SSR), so hydration warnings don't apply 153 // Reduces bundle size and eliminates unnecessary runtime checks 154 __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: JSON.stringify(false), 155 156 // Expose session storage toggle to client code 157 'process.env.STORE_SESSION': JSON.stringify( 158 process.env.STORE_SESSION || '', 159 ), 160 'process.env.VUE_APP_STORE_SESSION': JSON.stringify( 161 process.env.VUE_APP_STORE_SESSION || '', 162 ), 163 }), 164 ); 165 }, 166 pluginOptions: { 167 i18n: { 168 localeDir: 'locales', 169 enableInSFC: true, 170 }, 171 }, 172}; 173