1 import path from 'path';
2 import type { 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 inlineIcons: env.inlineIcons === 'true',
38 browserslist: env.browserslist ?? defaultBrowsersList,
46 warningLogs: env.warningLogs || false,
47 errorLogs: env.errorLogs || false,
48 overlayWarnings: env.overlayWarnings || false,
49 overlayErrors: env.overlayErrors || false,
50 overlayRuntimeErrors: env.overlayRuntimeErrors || false,
51 logical: env.logical || false,
52 analyze: env.analyze || false,
55 const version = options.buildData.version;
58 target: `browserslist:${options.browserslist}`,
59 mode: isProduction ? 'production' : 'development',
61 devtool: isProduction ? 'source-map' : 'cheap-module-source-map',
63 ignored: /dist|node_modules|locales|\.(gif|jpeg|jpg|ico|png|svg)/,
64 aggregateTimeout: 600,
67 extensions: ['.js', '.tsx', '.ts'],
77 experiments: { asyncWebAssembly: true },
80 filename: isProduction
81 ? `${assetsFolder}/[name].[contenthash:8].js?v=${version}`
82 : `${assetsFolder}/[name].js?v=${version}`,
83 publicPath: options.publicPath,
84 chunkFilename: (pathData) => {
85 const result = isProduction
86 ? `${assetsFolder}/[name].[contenthash:8].chunk.js?v=${version}`
87 : `${assetsFolder}/[name].chunk.js?v=${version}`;
88 const chunkName = pathData?.chunk?.name;
89 if (chunkName && (chunkName.startsWith('date-fns/') || chunkName.startsWith('locales/'))) {
91 const strippedChunkName = chunkName.replaceAll(/-index-js|-json/g, '');
92 return result.replace('[name]', strippedChunkName);
94 // Drive need static URL for transpiled SW
95 if (chunkName && chunkName.startsWith('downloadSW')) {
96 return `[name].js?v=${version}`;
100 assetModuleFilename: (data) => {
101 const { path: file } = parseResource(data?.filename || '');
102 const ext = path.extname(file);
103 const base = path.basename(file);
104 const name = base.slice(0, base.length - ext.length);
105 if (name.includes('.var')) {
106 const replacedNamed = name.replace('.var', '-var');
107 return `${assetsFolder}/${replacedNamed}.[hash][ext]?v=${version}`;
109 return `${assetsFolder}/[name].[hash][ext]?v=${version}`;
111 crossOriginLoading: 'anonymous',
114 strictExportPresence: true, // Make missing exports an error instead of warning
115 rules: [...getJsLoaders(options), ...getCssLoaders(options), ...getAssetsLoaders(options)],
117 plugins: getPlugins({
119 cssName: isProduction
120 ? `${assetsFolder}/[name].[contenthash:8].css?v=${version}`
121 : `${assetsFolder}/[name].css?v=${version}`,
123 optimization: getOptimizations(options),
128 publicPath: options.publicPath,
132 historyApiFallback: {
133 index: options.publicPath,
136 webSocketURL: 'auto://0.0.0.0:0/ws',
138 warnings: options.overlayWarnings,
139 errors: options.overlayErrors,
140 runtimeErrors: options.overlayRuntimeErrors,
143 webSocketServer: 'ws',
147 context: ['/api', '/internal-api'],
151 onProxyRes: (proxyRes) => {
152 delete proxyRes.headers['content-security-policy'];
153 delete proxyRes.headers['x-frame-options'];
154 proxyRes.headers['set-cookie'] = proxyRes.headers['set-cookie']?.map((cookies) =>
157 .filter((cookie) => {
158 return !/(secure$|samesite=|domain=)/i.test(cookie);
170 export default getConfig;