1 import path from 'path';
2 import { Configuration } from 'webpack';
3 import 'webpack-dev-server';
5 import { parseResource } from 'webpack/lib/util/identifier';
7 import { getEntries } from './webpack/entries';
9 const getCssLoaders = require('./webpack/css.loader');
10 const getAssetsLoaders = require('./webpack/assets.loader');
11 const getPlugins = require('./webpack/plugins');
12 const getOptimizations = require('./webpack/optimization');
14 const getConfig = (env: any): Configuration => {
15 const isProduction = process.env.NODE_ENV === 'production';
16 const isRelease = !!process.env.CI_COMMIT_TAG;
18 // This folder is separate from the assets folder because they are special assets which get served through
19 // a long-term storage
20 const assetsFolder = 'assets/static';
22 const { getJsLoaders } = require(env.webpackOnCaffeine ? './webpack/js.loader.swc' : './webpack/js.loader');
24 const defaultBrowsersList = isProduction
25 ? `> 0.5%, not IE 11, Firefox ESR, Safari 14, iOS 14, Chrome 80`
26 : 'last 1 chrome version, last 1 firefox version, last 1 safari version';
31 publicPath: env.publicPath || '/',
33 appMode: env.appMode || 'standalone',
34 webpackOnCaffeine: env.webpackOnCaffeine,
35 featureFlags: env.featureFlags || '',
36 writeSRI: env.writeSri !== 'false',
37 browserslist: env.browserslist ?? defaultBrowsersList,
45 warningLogs: env.warningLogs || false,
46 errorLogs: env.errorLogs || false,
47 overlayWarnings: env.overlayWarnings || false,
48 overlayErrors: env.overlayErrors || false,
49 overlayRuntimeErrors: env.overlayRuntimeErrors || false,
50 logical: env.logical || false,
51 analyze: env.analyze || false,
54 const version = options.buildData.version;
57 target: `browserslist:${options.browserslist}`,
58 mode: isProduction ? 'production' : 'development',
60 devtool: isProduction ? 'source-map' : 'cheap-module-source-map',
62 ignored: /dist|node_modules|locales|\.(gif|jpeg|jpg|ico|png|svg)/,
63 aggregateTimeout: 600,
66 extensions: ['.js', '.tsx', '.ts'],
76 experiments: { asyncWebAssembly: true },
79 filename: isProduction
80 ? `${assetsFolder}/[name].[contenthash:8].js?v=${version}`
81 : `${assetsFolder}/[name].js?v=${version}`,
82 publicPath: options.publicPath,
83 chunkFilename: (pathData) => {
84 const result = isProduction
85 ? `${assetsFolder}/[name].[contenthash:8].chunk.js?v=${version}`
86 : `${assetsFolder}/[name].chunk.js?v=${version}`;
87 const chunkName = pathData?.chunk?.name;
88 if (chunkName && (chunkName.startsWith('date-fns/') || chunkName.startsWith('locales/'))) {
90 const strippedChunkName = chunkName.replaceAll(/-index-js|-json/g, '');
91 return result.replace('[name]', strippedChunkName);
93 // Drive need static URL for transpiled SW
94 if (chunkName && chunkName.startsWith('downloadSW')) {
95 return `[name].js?v=${version}`;
99 assetModuleFilename: (data) => {
100 const { path: file } = parseResource(data?.filename || '');
101 const ext = path.extname(file);
102 const base = path.basename(file);
103 const name = base.slice(0, base.length - ext.length);
104 if (name.includes('.var')) {
105 const replacedNamed = name.replace('.var', '-var');
106 return `${assetsFolder}/${replacedNamed}.[hash][ext]?v=${version}`;
108 return `${assetsFolder}/[name].[hash][ext]?v=${version}`;
110 crossOriginLoading: 'anonymous',
113 strictExportPresence: true, // Make missing exports an error instead of warning
114 rules: [...getJsLoaders(options), ...getCssLoaders(options), ...getAssetsLoaders()],
116 plugins: getPlugins({
118 cssName: isProduction
119 ? `${assetsFolder}/[name].[contenthash:8].css?v=${version}`
120 : `${assetsFolder}/[name].css?v=${version}`,
122 optimization: getOptimizations(options),
127 publicPath: options.publicPath,
131 historyApiFallback: {
132 index: options.publicPath,
135 webSocketURL: 'auto://0.0.0.0:0/ws',
137 warnings: options.overlayWarnings,
138 errors: options.overlayErrors,
139 runtimeErrors: options.overlayRuntimeErrors,
142 webSocketServer: 'ws',
146 context: ['/api', '/internal-api'],
150 onProxyRes: (proxyRes) => {
151 delete proxyRes.headers['content-security-policy'];
152 delete proxyRes.headers['x-frame-options'];
153 proxyRes.headers['set-cookie'] = proxyRes.headers['set-cookie']?.map((cookies) =>
156 .filter((cookie) => {
157 return !/(secure$|samesite=|domain=)/i.test(cookie);
169 export default getConfig;