xref: /openbmc/webui-vue/vue.config.js (revision d3b05033fe82aed6c53f4f2b52c23d3bd285d423)
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=false to run with HTTP
48    // ref https://webpack.js.org/configuration/dev-server/#devserverserver
49    server:
50      process.env.DEV_HTTPS === 'false' ? { type: 'http' } : { type: 'https' },
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    // Add TypeScript file resolution
85    config.resolve.extensions = ['.ts', '.tsx', '.js', '.jsx', '.vue', '.json'];
86
87    config.module.rules.push({
88      test: /\.tsx?$/,
89      loader: 'ts-loader',
90      exclude: /node_modules/,
91      options: {
92        appendTsSuffixTo: [/\.vue$/],
93        transpileOnly: true,
94      },
95    });
96
97    config.plugins.push(
98      new LimitChunkCountPlugin({
99        maxChunks: 1,
100      }),
101    );
102    config.optimization.splitChunks = {
103      cacheGroups: {
104        default: false,
105      },
106    };
107    const crypto = require('crypto');
108    const crypto_orig_createHash = crypto.createHash;
109    crypto.createHash = (algorithm) =>
110      crypto_orig_createHash(algorithm == 'md4' ? 'sha256' : algorithm);
111
112    const envName = process.env.VUE_APP_ENV_NAME;
113    const hasCustomStore = process.env.CUSTOM_STORE === 'true';
114    const hasCustomRouter = process.env.CUSTOM_ROUTER === 'true';
115    const hasCustomAppNav = process.env.CUSTOM_APP_NAV === 'true';
116
117    if (envName !== undefined) {
118      if (hasCustomStore) {
119        // If env has custom store, resolve all store modules. Currently found
120        // in src/router/index.js src/store/api.js and src/main.js
121        config.resolve.alias['./store$'] = `@/env/store/${envName}.js`;
122        config.resolve.alias['../store$'] = `@/env/store/${envName}.js`;
123      }
124      if (hasCustomRouter) {
125        // If env has custom router, resolve routes in src/router/index.js
126        config.resolve.alias['./routes$'] = `@/env/router/${envName}.js`;
127      }
128      if (hasCustomAppNav) {
129        // If env has custom AppNavigation, resolve AppNavigationMixin module in src/components/AppNavigation/AppNavigation.vue
130        config.resolve.alias['./AppNavigationMixin$'] =
131          `@/env/components/AppNavigation/${envName}.js`;
132      }
133    }
134
135    if (process.env.NODE_ENV === 'production') {
136      config.plugins.push(
137        new CompressionPlugin({
138          deleteOriginalAssets: true,
139        }),
140      );
141    }
142
143    config.performance = {
144      hints: 'warning',
145      maxEntrypointSize: 512000,
146      maxAssetSize: 512000,
147    };
148
149    config.optimization.runtimeChunk = false;
150
151    // Define Vue 3 compile-time feature flags
152    // These flags must be explicitly defined to avoid Vue warnings and optimize bundle size
153    config.plugins.push(
154      new webpack.DefinePlugin({
155        // Enable Options API support (required - this codebase uses Options API extensively)
156        // Setting to true includes Options API in the bundle (~3kb gzipped)
157        // Cannot be disabled until full migration to Composition API
158        __VUE_OPTIONS_API__: JSON.stringify(true),
159
160        // Disable Vue Devtools in production builds for security and performance
161        // Devtools automatically enabled in development mode regardless of this flag
162        __VUE_PROD_DEVTOOLS__: JSON.stringify(false),
163
164        // Disable detailed hydration mismatch warnings in production
165        // This is a SPA (not SSR), so hydration warnings don't apply
166        // Reduces bundle size and eliminates unnecessary runtime checks
167        __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: JSON.stringify(false),
168
169        // Expose session storage toggle to client code
170        'process.env.STORE_SESSION': JSON.stringify(
171          process.env.STORE_SESSION || '',
172        ),
173        'process.env.VUE_APP_STORE_SESSION': JSON.stringify(
174          process.env.VUE_APP_STORE_SESSION || '',
175        ),
176      }),
177    );
178  },
179  pluginOptions: {
180    i18n: {
181      localeDir: 'locales',
182      enableInSFC: true,
183    },
184  },
185};
186