main
js 702 lines 27 KB
Raw
1 'use strict';
2
3 // Fork Start
4 const ReactFlightWebpackPlugin = require('react-server-dom-webpack/plugin');
5 // Fork End
6
7 const fs = require('fs');
8 const {createHash} = require('crypto');
9 const path = require('path');
10 const {pathToFileURL} = require('url');
11 const webpack = require('webpack');
12 const resolve = require('resolve');
13 const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
14 const TerserPlugin = require('terser-webpack-plugin');
15 const MiniCssExtractPlugin = require('mini-css-extract-plugin');
16 const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
17 const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
18 const DevToolsIgnorePlugin = require('devtools-ignore-webpack-plugin');
19 const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
20 const paths = require('./paths');
21 const modules = require('./modules');
22 const getClientEnvironment = require('./env');
23 const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
24 const ForkTsCheckerWebpackPlugin =
25 process.env.TSC_COMPILE_ON_ERROR === 'true'
26 ? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin')
27 : require('react-dev-utils/ForkTsCheckerWebpackPlugin');
28 const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
29 const {WebpackManifestPlugin} = require('webpack-manifest-plugin');
30
31 function createEnvironmentHash(env) {
32 const hash = createHash('md5');
33 hash.update(JSON.stringify(env));
34
35 return hash.digest('hex');
36 }
37
38 // Source maps are resource heavy and can cause out of memory issue for large source files.
39 const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
40
41 const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime');
42 const reactRefreshWebpackPluginRuntimeEntry = require.resolve(
43 '@pmmmwh/react-refresh-webpack-plugin'
44 );
45 const babelRuntimeEntry = require.resolve('babel-preset-react-app');
46 const babelRuntimeEntryHelpers = require.resolve(
47 '@babel/runtime/helpers/esm/assertThisInitialized',
48 {paths: [babelRuntimeEntry]}
49 );
50 const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', {
51 paths: [babelRuntimeEntry],
52 });
53
54 // Some apps do not need the benefits of saving a web request, so not inlining the chunk
55 // makes for a smoother build process.
56 const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
57
58 const imageInlineSizeLimit = parseInt(
59 process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
60 );
61
62 // Check if TypeScript is setup
63 const useTypeScript = fs.existsSync(paths.appTsConfig);
64
65 // Check if Tailwind config exists
66 const useTailwind = fs.existsSync(
67 path.join(paths.appPath, 'tailwind.config.js')
68 );
69
70 // Get the path to the uncompiled service worker (if it exists).
71 const swSrc = paths.swSrc;
72
73 // style files regexes
74 const cssRegex = /\.css$/;
75 const cssModuleRegex = /\.module\.css$/;
76 const sassRegex = /\.(scss|sass)$/;
77 const sassModuleRegex = /\.module\.(scss|sass)$/;
78
79 // This is the production and development configuration.
80 // It is focused on developer experience, fast rebuilds, and a minimal bundle.
81 module.exports = function (webpackEnv) {
82 const isEnvDevelopment = webpackEnv === 'development';
83 const isEnvProduction = webpackEnv === 'production';
84
85 // Variable used for enabling profiling in Production
86 // passed into alias object. Uses a flag if passed into the build command
87 const isEnvProductionProfile =
88 isEnvProduction && process.argv.includes('--profile');
89
90 // We will provide `paths.publicUrlOrPath` to our app
91 // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
92 // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
93 // Get environment variables to inject into our app.
94 const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
95
96 const shouldUseReactRefresh = env.raw.FAST_REFRESH;
97
98 // common function to get style loaders
99 const getStyleLoaders = (cssOptions, preProcessor) => {
100 const loaders = [
101 isEnvDevelopment && require.resolve('style-loader'),
102 {
103 loader: MiniCssExtractPlugin.loader,
104 // css is located in `static/css`, use '../../' to locate index.html folder
105 // in production `paths.publicUrlOrPath` can be a relative path
106 options: paths.publicUrlOrPath.startsWith('.')
107 ? {publicPath: '../../'}
108 : {},
109 },
110 {
111 loader: require.resolve('css-loader'),
112 options: cssOptions,
113 },
114 {
115 // Options for PostCSS as we reference these options twice
116 // Adds vendor prefixing based on your specified browser support in
117 // package.json
118 loader: require.resolve('postcss-loader'),
119 options: {
120 postcssOptions: {
121 // Necessary for external CSS imports to work
122 // https://github.com/facebook/create-react-app/issues/2677
123 ident: 'postcss',
124 config: false,
125 plugins: !useTailwind
126 ? [
127 'postcss-flexbugs-fixes',
128 [
129 'postcss-preset-env',
130 {
131 autoprefixer: {
132 flexbox: 'no-2009',
133 },
134 stage: 3,
135 },
136 ],
137 // Adds PostCSS Normalize as the reset css with default options,
138 // so that it honors browserslist config in package.json
139 // which in turn let's users customize the target behavior as per their needs.
140 'postcss-normalize',
141 ]
142 : [
143 'tailwindcss',
144 'postcss-flexbugs-fixes',
145 [
146 'postcss-preset-env',
147 {
148 autoprefixer: {
149 flexbox: 'no-2009',
150 },
151 stage: 3,
152 },
153 ],
154 ],
155 },
156 sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
157 },
158 },
159 ].filter(Boolean);
160 if (preProcessor) {
161 loaders.push(
162 {
163 loader: require.resolve('resolve-url-loader'),
164 options: {
165 sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
166 root: paths.appSrc,
167 },
168 },
169 {
170 loader: require.resolve(preProcessor),
171 options: {
172 sourceMap: true,
173 },
174 }
175 );
176 }
177 return loaders;
178 };
179
180 return {
181 target: ['browserslist'],
182 // Webpack noise constrained to errors and warnings
183 stats: 'errors-warnings',
184 mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
185 // Stop compilation early in production
186 bail: isEnvProduction,
187 devtool: isEnvProduction
188 ? shouldUseSourceMap
189 ? 'source-map'
190 : false
191 : isEnvDevelopment && 'source-map',
192 // These are the "entry points" to our application.
193 // This means they will be the "root" imports that are included in JS bundle.
194 entry: isEnvProduction
195 ? [paths.appIndexJs]
196 : [
197 paths.appIndexJs,
198 // HMR client
199 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
200 ],
201 output: {
202 // The build folder.
203 path: paths.appBuild,
204 // Add /* filename */ comments to generated require()s in the output.
205 pathinfo: isEnvDevelopment,
206 // There will be one main bundle, and one file per asynchronous chunk.
207 // In development, it does not produce real files.
208 filename: isEnvProduction
209 ? 'static/js/[name].[contenthash:8].js'
210 : isEnvDevelopment && 'static/js/bundle.js',
211 // There are also additional JS chunk files if you use code splitting.
212 chunkFilename: isEnvProduction
213 ? 'static/js/[name].[contenthash:8].chunk.js'
214 : isEnvDevelopment && 'static/js/[name].chunk.js',
215 assetModuleFilename: 'static/media/[name].[hash][ext]',
216 // webpack uses `publicPath` to determine where the app is being served from.
217 // It requires a trailing slash, or the file assets will get an incorrect path.
218 // We inferred the "public path" (such as / or /my-project) from homepage.
219 publicPath: paths.publicUrlOrPath,
220 // Point sourcemap entries to original disk location (format as URL on Windows)
221 devtoolModuleFilenameTemplate: isEnvProduction
222 ? info =>
223 path
224 .relative(paths.appSrc, info.absoluteResourcePath)
225 .replace(/\\/g, '/')
226 : isEnvDevelopment &&
227 (info => pathToFileURL(path.resolve(info.absoluteResourcePath))),
228 },
229 cache: {
230 type: 'filesystem',
231 version: createEnvironmentHash(env.raw),
232 cacheDirectory: paths.appWebpackCache,
233 store: 'pack',
234 buildDependencies: {
235 defaultWebpack: ['webpack/lib/'],
236 config: [__filename],
237 tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>
238 fs.existsSync(f)
239 ),
240 },
241 },
242 infrastructureLogging: {
243 level: 'none',
244 },
245 optimization: {
246 minimize: isEnvProduction,
247 minimizer: [
248 // This is only used in production mode
249 new TerserPlugin({
250 terserOptions: {
251 parse: {
252 // We want terser to parse ecma 8 code. However, we don't want it
253 // to apply any minification steps that turns valid ecma 5 code
254 // into invalid ecma 5 code. This is why the 'compress' and 'output'
255 // sections only apply transformations that are ecma 5 safe
256 // https://github.com/facebook/create-react-app/pull/4234
257 ecma: 8,
258 },
259 compress: {
260 ecma: 5,
261 warnings: false,
262 // Disabled because of an issue with Uglify breaking seemingly valid code:
263 // https://github.com/facebook/create-react-app/issues/2376
264 // Pending further investigation:
265 // https://github.com/mishoo/UglifyJS2/issues/2011
266 comparisons: false,
267 // Disabled because of an issue with Terser breaking valid code:
268 // https://github.com/facebook/create-react-app/issues/5250
269 // Pending further investigation:
270 // https://github.com/terser-js/terser/issues/120
271 inline: 2,
272 },
273 mangle: {
274 safari10: true,
275 },
276 // Added for profiling in devtools
277 keep_classnames: isEnvProductionProfile,
278 keep_fnames: isEnvProductionProfile,
279 output: {
280 ecma: 5,
281 comments: false,
282 // Turned on because emoji and regex is not minified properly using default
283 // https://github.com/facebook/create-react-app/issues/2488
284 ascii_only: true,
285 },
286 },
287 }),
288 // This is only used in production mode
289 new CssMinimizerPlugin(),
290 ],
291 },
292 resolve: {
293 // This allows you to set a fallback for where webpack should look for modules.
294 // We placed these paths second because we want `node_modules` to "win"
295 // if there are any conflicts. This matches Node resolution mechanism.
296 // https://github.com/facebook/create-react-app/issues/253
297 modules: ['node_modules', paths.appNodeModules].concat(
298 modules.additionalModulePaths || []
299 ),
300 // These are the reasonable defaults supported by the Node ecosystem.
301 // We also include JSX as a common component filename extension to support
302 // some tools, although we do not recommend using it, see:
303 // https://github.com/facebook/create-react-app/issues/290
304 // `web` extension prefixes have been added for better support
305 // for React Native Web.
306 extensions: paths.moduleFileExtensions
307 .map(ext => `.${ext}`)
308 .filter(ext => useTypeScript || !ext.includes('ts')),
309 alias: {
310 // Support React Native Web
311 // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
312 'react-native': 'react-native-web',
313 // Allows for better profiling with ReactDevTools
314 ...(isEnvProductionProfile && {
315 'react-dom$': 'react-dom/profiling',
316 'scheduler/tracing': 'scheduler/tracing-profiling',
317 }),
318 ...(modules.webpackAliases || {}),
319 },
320 plugins: [
321 // Prevents users from importing files from outside of src/ (or node_modules/).
322 // This often causes confusion because we only process files within src/ with babel.
323 // To fix this, we prevent you from importing files out of src/ -- if you'd like to,
324 // please link the files into your node_modules/ and let module-resolution kick in.
325 // Make sure your source files are compiled, as they will not be processed in any way.
326 new ModuleScopePlugin(paths.appSrc, [
327 paths.appPackageJson,
328 reactRefreshRuntimeEntry,
329 reactRefreshWebpackPluginRuntimeEntry,
330 babelRuntimeEntry,
331 babelRuntimeEntryHelpers,
332 babelRuntimeRegenerator,
333 ]),
334 ],
335 },
336 module: {
337 strictExportPresence: true,
338 rules: [
339 // Handle node_modules packages that contain sourcemaps
340 shouldUseSourceMap && {
341 enforce: 'pre',
342 exclude: /@babel(?:\/|\\{1,2})runtime/,
343 test: /\.(js|mjs|jsx|ts|tsx|css)$/,
344 loader: require.resolve('source-map-loader'),
345 },
346 {
347 // "oneOf" will traverse all following loaders until one will
348 // match the requirements. When no loader matches it will fall
349 // back to the "file" loader at the end of the loader list.
350 oneOf: [
351 // TODO: Merge this config once `image/avif` is in the mime-db
352 // https://github.com/jshttp/mime-db
353 {
354 test: [/\.avif$/],
355 type: 'asset',
356 mimetype: 'image/avif',
357 parser: {
358 dataUrlCondition: {
359 maxSize: imageInlineSizeLimit,
360 },
361 },
362 },
363 // "url" loader works like "file" loader except that it embeds assets
364 // smaller than specified limit in bytes as data URLs to avoid requests.
365 // A missing `test` is equivalent to a match.
366 {
367 test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
368 type: 'asset',
369 parser: {
370 dataUrlCondition: {
371 maxSize: imageInlineSizeLimit,
372 },
373 },
374 },
375 {
376 test: /\.svg$/,
377 use: [
378 {
379 loader: require.resolve('@svgr/webpack'),
380 options: {
381 prettier: false,
382 svgo: false,
383 svgoConfig: {
384 plugins: [{removeViewBox: false}],
385 },
386 titleProp: true,
387 ref: true,
388 },
389 },
390 {
391 loader: require.resolve('file-loader'),
392 options: {
393 name: 'static/media/[name].[hash].[ext]',
394 },
395 },
396 ],
397 issuer: {
398 and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
399 },
400 },
401 // Process application JS with Babel.
402 // The preset includes JSX, Flow, TypeScript, and some ESnext features.
403 {
404 test: /\.(js|mjs|jsx|ts|tsx)$/,
405 include: paths.appSrc,
406 loader: require.resolve('babel-loader'),
407 options: {
408 customize: require.resolve(
409 'babel-preset-react-app/webpack-overrides'
410 ),
411 presets: [
412 [
413 require.resolve('babel-preset-react-app'),
414 {
415 runtime: 'automatic',
416 },
417 ],
418 ],
419
420 plugins: [
421 isEnvDevelopment &&
422 shouldUseReactRefresh &&
423 require.resolve('react-refresh/babel'),
424 ].filter(Boolean),
425 // This is a feature of `babel-loader` for webpack (not Babel itself).
426 // It enables caching results in ./node_modules/.cache/babel-loader/
427 // directory for faster rebuilds.
428 cacheDirectory: true,
429 // See #6846 for context on why cacheCompression is disabled
430 cacheCompression: false,
431 compact: isEnvProduction,
432 },
433 },
434 // Process any JS outside of the app with Babel.
435 // Unlike the application JS, we only compile the standard ES features.
436 {
437 test: /\.(js|mjs)$/,
438 exclude: /@babel(?:\/|\\{1,2})runtime/,
439 loader: require.resolve('babel-loader'),
440 options: {
441 babelrc: false,
442 configFile: false,
443 compact: false,
444 presets: [
445 [
446 require.resolve('babel-preset-react-app/dependencies'),
447 {helpers: true},
448 ],
449 ],
450 cacheDirectory: true,
451 // See #6846 for context on why cacheCompression is disabled
452 cacheCompression: false,
453
454 // Babel sourcemaps are needed for debugging into node_modules
455 // code. Without the options below, debuggers like VSCode
456 // show incorrect code and set breakpoints on the wrong lines.
457 sourceMaps: shouldUseSourceMap,
458 inputSourceMap: shouldUseSourceMap,
459 },
460 },
461 // "postcss" loader applies autoprefixer to our CSS.
462 // "css" loader resolves paths in CSS and adds assets as dependencies.
463 // "style" loader turns CSS into JS modules that inject <style> tags.
464 // In production, we use MiniCSSExtractPlugin to extract that CSS
465 // to a file, but in development "style" loader enables hot editing
466 // of CSS.
467 // By default we support CSS Modules with the extension .module.css
468 {
469 test: cssRegex,
470 exclude: cssModuleRegex,
471 use: getStyleLoaders({
472 importLoaders: 1,
473 sourceMap: isEnvProduction
474 ? shouldUseSourceMap
475 : isEnvDevelopment,
476 modules: {
477 mode: 'icss',
478 },
479 }),
480 // Don't consider CSS imports dead code even if the
481 // containing package claims to have no side effects.
482 // Remove this when webpack adds a warning or an error for this.
483 // See https://github.com/webpack/webpack/issues/6571
484 sideEffects: true,
485 },
486 // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
487 // using the extension .module.css
488 {
489 test: cssModuleRegex,
490 use: getStyleLoaders({
491 importLoaders: 1,
492 sourceMap: isEnvProduction
493 ? shouldUseSourceMap
494 : isEnvDevelopment,
495 modules: {
496 mode: 'local',
497 getLocalIdent: getCSSModuleLocalIdent,
498 },
499 }),
500 },
501 // Opt-in support for SASS (using .scss or .sass extensions).
502 // By default we support SASS Modules with the
503 // extensions .module.scss or .module.sass
504 {
505 test: sassRegex,
506 exclude: sassModuleRegex,
507 use: getStyleLoaders(
508 {
509 importLoaders: 3,
510 sourceMap: isEnvProduction
511 ? shouldUseSourceMap
512 : isEnvDevelopment,
513 modules: {
514 mode: 'icss',
515 },
516 },
517 'sass-loader'
518 ),
519 // Don't consider CSS imports dead code even if the
520 // containing package claims to have no side effects.
521 // Remove this when webpack adds a warning or an error for this.
522 // See https://github.com/webpack/webpack/issues/6571
523 sideEffects: true,
524 },
525 // Adds support for CSS Modules, but using SASS
526 // using the extension .module.scss or .module.sass
527 {
528 test: sassModuleRegex,
529 use: getStyleLoaders(
530 {
531 importLoaders: 3,
532 sourceMap: isEnvProduction
533 ? shouldUseSourceMap
534 : isEnvDevelopment,
535 modules: {
536 mode: 'local',
537 getLocalIdent: getCSSModuleLocalIdent,
538 },
539 },
540 'sass-loader'
541 ),
542 },
543 // "file" loader makes sure those assets get served by WebpackDevServer.
544 // When you `import` an asset, you get its (virtual) filename.
545 // In production, they would get copied to the `build` folder.
546 // This loader doesn't use a "test" so it will catch all modules
547 // that fall through the other loaders.
548 {
549 // Exclude `js` files to keep "css" loader working as it injects
550 // its runtime that would otherwise be processed through "file" loader.
551 // Also exclude `html` and `json` extensions so they get processed
552 // by webpacks internal loaders.
553 exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
554 type: 'asset/resource',
555 },
556 // ** STOP ** Are you adding a new loader?
557 // Make sure to add the new loader(s) before the "file" loader.
558 ],
559 },
560 ].filter(Boolean),
561 },
562 plugins: [
563 new webpack.HotModuleReplacementPlugin(),
564 // This gives some necessary context to module not found errors, such as
565 // the requesting resource.
566 new ModuleNotFoundPlugin(paths.appPath),
567 // Makes some environment variables available to the JS code, for example:
568 // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
569 // It is absolutely essential that NODE_ENV is set to production
570 // during a production build.
571 // Otherwise React will be compiled in the very slow development mode.
572 new webpack.DefinePlugin(env.stringified),
573 // Experimental hot reloading for React .
574 // https://github.com/facebook/react/tree/main/packages/react-refresh
575 isEnvDevelopment &&
576 shouldUseReactRefresh &&
577 new ReactRefreshWebpackPlugin({
578 overlay: false,
579 }),
580 // Watcher doesn't work well if you mistype casing in a path so we use
581 // a plugin that prints an error when you attempt to do this.
582 // See https://github.com/facebook/create-react-app/issues/240
583 isEnvDevelopment && new CaseSensitivePathsPlugin(),
584 new MiniCssExtractPlugin({
585 // Options similar to the same options in webpackOptions.output
586 // both options are optional
587 filename: 'static/css/[name].[contenthash:8].css',
588 chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
589 }),
590 // Generate a manifest containing the required script / css for each entry.
591 new WebpackManifestPlugin({
592 fileName: 'entrypoint-manifest.json',
593 publicPath: paths.publicUrlOrPath,
594 generate: (seed, files, entrypoints) => {
595 const entrypointFiles = entrypoints.main.filter(
596 fileName => !fileName.endsWith('.map')
597 );
598
599 const processedEntrypoints = {};
600 for (let key in entrypoints) {
601 processedEntrypoints[key] = {
602 js: entrypoints[key].filter(
603 filename =>
604 // Include JS assets but ignore hot updates because they're not
605 // safe to include as async script tags.
606 filename.endsWith('.js') &&
607 !filename.endsWith('.hot-update.js')
608 ),
609 css: entrypoints[key].filter(filename =>
610 filename.endsWith('.css')
611 ),
612 };
613 }
614
615 return processedEntrypoints;
616 },
617 }),
618 // Moment.js is an extremely popular library that bundles large locale files
619 // by default due to how webpack interprets its code. This is a practical
620 // solution that requires the user to opt into importing specific locales.
621 // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
622 // You can remove this if you don't use Moment.js:
623 new webpack.IgnorePlugin({
624 resourceRegExp: /^\.\/locale$/,
625 contextRegExp: /moment$/,
626 }),
627 // TypeScript type checking
628 useTypeScript &&
629 new ForkTsCheckerWebpackPlugin({
630 async: isEnvDevelopment,
631 typescript: {
632 typescriptPath: resolve.sync('typescript', {
633 basedir: paths.appNodeModules,
634 }),
635 configOverwrite: {
636 compilerOptions: {
637 sourceMap: isEnvProduction
638 ? shouldUseSourceMap
639 : isEnvDevelopment,
640 skipLibCheck: true,
641 inlineSourceMap: false,
642 declarationMap: false,
643 noEmit: true,
644 incremental: true,
645 tsBuildInfoFile: paths.appTsBuildInfoFile,
646 },
647 },
648 context: paths.appPath,
649 diagnosticOptions: {
650 syntactic: true,
651 },
652 mode: 'write-references',
653 // profile: true,
654 },
655 issue: {
656 // This one is specifically to match during CI tests,
657 // as micromatch doesn't match
658 // '../cra-template-typescript/template/src/App.tsx'
659 // otherwise.
660 include: [
661 {file: '../**/src/**/*.{ts,tsx}'},
662 {file: '**/src/**/*.{ts,tsx}'},
663 ],
664 exclude: [
665 {file: '**/src/**/__tests__/**'},
666 {file: '**/src/**/?(*.){spec|test}.*'},
667 {file: '**/src/setupProxy.*'},
668 {file: '**/src/setupTests.*'},
669 ],
670 },
671 logger: {
672 infrastructure: 'silent',
673 },
674 }),
675 // Fork Start
676 new DevToolsIgnorePlugin({
677 shouldIgnorePath: function (path) {
678 return (
679 path.includes('/node_modules/') ||
680 path.includes('/webpack/') ||
681 path.endsWith('/src/index.js')
682 );
683 },
684 }),
685 new ReactFlightWebpackPlugin({
686 isServer: false,
687 clientReferences: {
688 directory: './src',
689 recursive: true,
690 include: /\.(js|ts|jsx|tsx)$/,
691 },
692 }),
693 // Fork End
694 ].filter(Boolean),
695 experiments: {
696 topLevelAwait: true,
697 },
698 // Turn off performance processing because we utilize
699 // our own hints via the FileSizeReporter
700 performance: false,
701 };
702 };