UNPKG

30.8 kBJavaScriptView Raw
1// @remove-on-eject-begin
2/**
3 * Copyright (c) 2015-present, Facebook, Inc.
4 *
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8// @remove-on-eject-end
9'use strict';
10
11const fs = require('fs');
12const isWsl = require('is-wsl');
13const path = require('path');
14const webpack = require('webpack');
15const resolve = require('resolve');
16const PnpWebpackPlugin = require('pnp-webpack-plugin');
17const HtmlWebpackPlugin = require('html-webpack-plugin');
18const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
19const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
20const TerserPlugin = require('terser-webpack-plugin');
21const MiniCssExtractPlugin = require('mini-css-extract-plugin');
22const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
23const safePostCssParser = require('postcss-safe-parser');
24const ManifestPlugin = require('webpack-manifest-plugin');
25const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
26const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
27const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
28const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
29const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
30const paths = require('./paths');
31const modules = require('./modules');
32const getClientEnvironment = require('./env');
33const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
34const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
35const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
36// @remove-on-eject-begin
37const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier');
38// @remove-on-eject-end
39const postcssNormalize = require('postcss-normalize');
40
41const SpritePlugin = require('svg-sprite-loader/plugin');
42const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
43 .BundleAnalyzerPlugin;
44const version = process.env.REACT_APP_VERSION;
45
46// Source maps are resource heavy and can cause out of memory issue for large source files.
47const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
48// Some apps do not need the benefits of saving a web request, so not inlining the chunk
49// makes for a smoother build process.
50const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
51
52// Check if TypeScript is setup
53const useTypeScript = fs.existsSync(paths.appTsConfig);
54
55const shouldRunAnalyzer = process.env.NO_ANALYZER !== 'true';
56
57// style files regexes
58const cssRegex = /\.css$/;
59const cssModuleRegex = /\.module\.css$/;
60const sassRegex = /\.(scss|sass)$/;
61const sassModuleRegex = /\.module\.(scss|sass)$/;
62
63// This is the production and development configuration.
64// It is focused on developer experience, fast rebuilds, and a minimal bundle.
65module.exports = function(webpackEnv) {
66 const isEnvDevelopment = webpackEnv === 'development';
67 const isEnvProduction = webpackEnv === 'production';
68
69 // Webpack uses `publicPath` to determine where the app is being served from.
70 // It requires a trailing slash, or the file assets will get an incorrect path.
71 // In development, we always serve from the root. This makes config easier.
72 const publicPath = isEnvProduction
73 ? paths.servedPath
74 : isEnvDevelopment && '/';
75 // Some apps do not use client-side routing with pushState.
76 // For these, "homepage" can be set to "." to enable relative asset paths.
77 const shouldUseRelativeAssetPaths = publicPath === './';
78
79 // `publicUrl` is just like `publicPath`, but we will provide it to our app
80 // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
81 // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
82 const publicUrl = isEnvProduction
83 ? publicPath.slice(0, -1)
84 : isEnvDevelopment && '';
85 // Get environment variables to inject into our app.
86 const env = getClientEnvironment(publicUrl);
87
88 // common function to get style loaders
89 const getStyleLoaders = (cssOptions, preProcessor) => {
90 const loaders = [
91 isEnvDevelopment && require.resolve('style-loader'),
92 isEnvProduction && {
93 loader: MiniCssExtractPlugin.loader,
94 options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
95 },
96 {
97 loader: require.resolve('css-loader'),
98 options: cssOptions,
99 },
100 {
101 // Options for PostCSS as we reference these options twice
102 // Adds vendor prefixing based on your specified browser support in
103 // package.json
104 loader: require.resolve('postcss-loader'),
105 options: {
106 // Necessary for external CSS imports to work
107 // https://github.com/facebook/create-react-app/issues/2677
108 ident: 'postcss',
109 plugins: () => [
110 require('postcss-flexbugs-fixes'),
111 require('postcss-preset-env')({
112 autoprefixer: {
113 flexbox: 'no-2009',
114 },
115 stage: 3,
116 }),
117 // Adds PostCSS Normalize as the reset css with default options,
118 // so that it honors browserslist config in package.json
119 // which in turn let's users customize the target behavior as per their needs.
120 postcssNormalize(),
121 ],
122 sourceMap: isEnvProduction && shouldUseSourceMap,
123 },
124 },
125 ].filter(Boolean);
126 if (preProcessor) {
127 loaders.push({
128 loader: require.resolve(preProcessor),
129 options: {
130 sourceMap: isEnvProduction && shouldUseSourceMap,
131 },
132 });
133 }
134 return loaders;
135 };
136
137 return {
138 mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
139 // Stop compilation early in production
140 bail: isEnvProduction,
141 devtool: isEnvProduction
142 ? shouldUseSourceMap
143 ? 'source-map'
144 : false
145 : isEnvDevelopment && 'cheap-module-source-map',
146 // These are the "entry points" to our application.
147 // This means they will be the "root" imports that are included in JS bundle.
148 entry: [
149 // Include an alternative client for WebpackDevServer. A client's job is to
150 // connect to WebpackDevServer by a socket and get notified about changes.
151 // When you save a file, the client will either apply hot updates (in case
152 // of CSS changes), or refresh the page (in case of JS changes). When you
153 // make a syntax error, this client will display a syntax error overlay.
154 // Note: instead of the default WebpackDevServer client, we use a custom one
155 // to bring better experience for Create React App users. You can replace
156 // the line below with these two lines if you prefer the stock client:
157 // require.resolve('webpack-dev-server/client') + '?/',
158 // require.resolve('webpack/hot/dev-server'),
159 isEnvDevelopment &&
160 require.resolve('react-dev-utils/webpackHotDevClient'),
161 // Finally, this is your app's code:
162 paths.appIndexJs,
163 // We include the app code last so that if there is a runtime error during
164 // initialization, it doesn't blow up the WebpackDevServer client, and
165 // changing JS code would still trigger a refresh.
166 ].filter(Boolean),
167 output: {
168 // The build folder.
169 path: isEnvProduction ? paths.appBuild : undefined,
170 // Add /* filename */ comments to generated require()s in the output.
171 pathinfo: isEnvDevelopment,
172 // There will be one main bundle, and one file per asynchronous chunk.
173 // In development, it does not produce real files.
174 filename: isEnvProduction
175 ? 'app/app.' + version + '.js'
176 : isEnvDevelopment && 'static/js/bundle.js',
177 // TODO: remove this when upgrading to webpack 5
178 futureEmitAssets: true,
179 // There are also additional JS chunk files if you use code splitting.
180 chunkFilename: isEnvProduction
181 ? 'app/[name].[chunkhash:8].js'
182 : isEnvDevelopment && 'static/js/[name].chunk.js',
183 // We inferred the "public path" (such as / or /my-project) from homepage.
184 // We use "/" in development.
185 publicPath: publicPath,
186 // Point sourcemap entries to original disk location (format as URL on Windows)
187 devtoolModuleFilenameTemplate: isEnvProduction
188 ? info =>
189 path
190 .relative(paths.appSrc, info.absoluteResourcePath)
191 .replace(/\\/g, '/')
192 : isEnvDevelopment &&
193 (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
194 },
195 optimization: {
196 minimize: isEnvProduction,
197 minimizer: [
198 // This is only used in production mode
199 new TerserPlugin({
200 terserOptions: {
201 parse: {
202 // we want terser to parse ecma 8 code. However, we don't want it
203 // to apply any minfication steps that turns valid ecma 5 code
204 // into invalid ecma 5 code. This is why the 'compress' and 'output'
205 // sections only apply transformations that are ecma 5 safe
206 // https://github.com/facebook/create-react-app/pull/4234
207 ecma: 8,
208 },
209 compress: {
210 ecma: 5,
211 warnings: false,
212 // Disabled because of an issue with Uglify breaking seemingly valid code:
213 // https://github.com/facebook/create-react-app/issues/2376
214 // Pending further investigation:
215 // https://github.com/mishoo/UglifyJS2/issues/2011
216 comparisons: false,
217 // Disabled because of an issue with Terser breaking valid code:
218 // https://github.com/facebook/create-react-app/issues/5250
219 // Pending futher investigation:
220 // https://github.com/terser-js/terser/issues/120
221 inline: 2,
222 },
223 mangle: {
224 safari10: true,
225 },
226 output: {
227 ecma: 5,
228 comments: false,
229 // Turned on because emoji and regex is not minified properly using default
230 // https://github.com/facebook/create-react-app/issues/2488
231 ascii_only: true,
232 },
233 },
234 // Use multi-process parallel running to improve the build speed
235 // Default number of concurrent runs: os.cpus().length - 1
236 // Disabled on WSL (Windows Subsystem for Linux) due to an issue with Terser
237 // https://github.com/webpack-contrib/terser-webpack-plugin/issues/21
238 parallel: !isWsl,
239 // Enable file caching
240 cache: true,
241 sourceMap: shouldUseSourceMap,
242 }),
243 // This is only used in production mode
244 new OptimizeCSSAssetsPlugin({
245 cssProcessorOptions: {
246 parser: safePostCssParser,
247 map: shouldUseSourceMap
248 ? {
249 // `inline: false` forces the sourcemap to be output into a
250 // separate file
251 inline: false,
252 // `annotation: true` appends the sourceMappingURL to the end of
253 // the css file, helping the browser find the sourcemap
254 annotation: true,
255 }
256 : false,
257 },
258 }),
259 ],
260 // Automatically split vendor and commons
261 // https://twitter.com/wSokra/status/969633336732905474
262 // https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
263 splitChunks: {
264 //chunks: 'all',
265 //name: false,
266 cacheGroups: {
267 default: false,
268 vendors: false,
269 },
270 },
271 // Keep the runtime chunk separated to enable long term caching
272 // https://twitter.com/wSokra/status/969679223278505985
273 runtimeChunk: false,
274 },
275 resolve: {
276 // This allows you to set a fallback for where Webpack should look for modules.
277 // We placed these paths second because we want `node_modules` to "win"
278 // if there are any conflicts. This matches Node resolution mechanism.
279 // https://github.com/facebook/create-react-app/issues/253
280 modules: ['node_modules', paths.appNodeModules].concat(
281 modules.additionalModulePaths || []
282 ),
283 // These are the reasonable defaults supported by the Node ecosystem.
284 // We also include JSX as a common component filename extension to support
285 // some tools, although we do not recommend using it, see:
286 // https://github.com/facebook/create-react-app/issues/290
287 // `web` extension prefixes have been added for better support
288 // for React Native Web.
289 extensions: paths.moduleFileExtensions
290 .map(ext => `.${ext}`)
291 .filter(ext => useTypeScript || !ext.includes('ts')),
292 alias: {
293 // Support React Native Web
294 // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
295 'react-native': 'react-native-web',
296 },
297 plugins: [
298 // Adds support for installing with Plug'n'Play, leading to faster installs and adding
299 // guards against forgotten dependencies and such.
300 PnpWebpackPlugin,
301 // Prevents users from importing files from outside of src/ (or node_modules/).
302 // This often causes confusion because we only process files within src/ with babel.
303 // To fix this, we prevent you from importing files out of src/ -- if you'd like to,
304 // please link the files into your node_modules/ and let module-resolution kick in.
305 // Make sure your source files are compiled, as they will not be processed in any way.
306 new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
307 ],
308 },
309 resolveLoader: {
310 plugins: [
311 // Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
312 // from the current package.
313 PnpWebpackPlugin.moduleLoader(module),
314 ],
315 },
316 module: {
317 strictExportPresence: true,
318 rules: [
319 // Disable require.ensure as it's not a standard language feature.
320 { parser: { requireEnsure: false } },
321
322 // First, run the linter.
323 // It's important to do this before Babel processes the JS.
324 {
325 test: /\.(js|mjs|jsx|ts|tsx)$/,
326 enforce: 'pre',
327 use: [
328 {
329 options: {
330 formatter: require.resolve('react-dev-utils/eslintFormatter'),
331 eslintPath: require.resolve('eslint'),
332 // @remove-on-eject-begin
333 baseConfig: {
334 extends: [require.resolve('eslint-config-react-app')],
335 },
336 ignore: false,
337 useEslintrc: false,
338 // @remove-on-eject-end
339 },
340 loader: require.resolve('eslint-loader'),
341 },
342 ],
343 include: paths.appSrc,
344 },
345 {
346 // "oneOf" will traverse all following loaders until one will
347 // match the requirements. When no loader matches it will fall
348 // back to the "file" loader at the end of the loader list.
349 oneOf: [
350 // "url" loader works like "file" loader except that it embeds assets
351 // smaller than specified limit in bytes as data URLs to avoid requests.
352 // A missing `test` is equivalent to a match.
353 {
354 test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
355 loader: require.resolve('url-loader'),
356 options: {
357 limit: 10000,
358 name: 'static/media/[name].[hash:8].[ext]',
359 },
360 },
361 // Process application JS with Babel.
362 // The preset includes JSX, Flow, TypeScript, and some ESnext features.
363 {
364 test: /\.(js|mjs|jsx|ts|tsx)$/,
365 include: paths.appSrc,
366 loader: require.resolve('babel-loader'),
367 options: {
368 customize: require.resolve(
369 '@eglaost/babel-preset-react-app/webpack-overrides'
370 ),
371 // @remove-on-eject-begin
372 babelrc: false,
373 configFile: false,
374 presets: [require.resolve('@eglaost/babel-preset-react-app')],
375 // Make sure we have a unique cache identifier, erring on the
376 // side of caution.
377 // We remove this when the user ejects because the default
378 // is sane and uses Babel options. Instead of options, we use
379 // the react-scripts and babel-preset-react-app versions.
380 cacheIdentifier: getCacheIdentifier(
381 isEnvProduction
382 ? 'production'
383 : isEnvDevelopment && 'development',
384 [
385 'babel-plugin-named-asset-import',
386 '@eglaost/babel-preset-react-app',
387 'react-dev-utils',
388 'react-scripts',
389 ]
390 ),
391 // @remove-on-eject-end
392 // plugins: [
393 // [
394 // require.resolve('babel-plugin-named-asset-import'),
395 // {
396 // loaderMap: {
397 // svg: {
398 // ReactComponent: '@svgr/webpack?-svgo,+ref![path]',
399 // },
400 // },
401 // },
402 // ],
403 // ],
404 // This is a feature of `babel-loader` for webpack (not Babel itself).
405 // It enables caching results in ./node_modules/.cache/babel-loader/
406 // directory for faster rebuilds.
407 cacheDirectory: true,
408 cacheCompression: isEnvProduction,
409 compact: isEnvProduction,
410 },
411 },
412 // Process any JS outside of the app with Babel.
413 // Unlike the application JS, we only compile the standard ES features.
414 {
415 test: /\.(js|mjs)$/,
416 exclude: /@babel(?:\/|\\{1,2})runtime/,
417 loader: require.resolve('babel-loader'),
418 options: {
419 babelrc: false,
420 configFile: false,
421 compact: false,
422 presets: [
423 [
424 require.resolve(
425 '@eglaost/babel-preset-react-app/dependencies'
426 ),
427 { helpers: true },
428 ],
429 ],
430 cacheDirectory: true,
431 cacheCompression: isEnvProduction,
432 // @remove-on-eject-begin
433 cacheIdentifier: getCacheIdentifier(
434 isEnvProduction
435 ? 'production'
436 : isEnvDevelopment && 'development',
437 [
438 'babel-plugin-named-asset-import',
439 '@eglaost/babel-preset-react-app',
440 'react-dev-utils',
441 'react-scripts',
442 ]
443 ),
444 // @remove-on-eject-end
445 // If an error happens in a package, it's possible to be
446 // because it was compiled. Thus, we don't want the browser
447 // debugger to show the original code. Instead, the code
448 // being evaluated would be much more helpful.
449 sourceMaps: false,
450 },
451 },
452 // "postcss" loader applies autoprefixer to our CSS.
453 // "css" loader resolves paths in CSS and adds assets as dependencies.
454 // "style" loader turns CSS into JS modules that inject <style> tags.
455 // In production, we use MiniCSSExtractPlugin to extract that CSS
456 // to a file, but in development "style" loader enables hot editing
457 // of CSS.
458 // By default we support CSS Modules with the extension .module.css
459 {
460 test: cssRegex,
461 exclude: cssModuleRegex,
462 use: getStyleLoaders({
463 importLoaders: 1,
464 sourceMap: isEnvProduction && shouldUseSourceMap,
465 }),
466 // Don't consider CSS imports dead code even if the
467 // containing package claims to have no side effects.
468 // Remove this when webpack adds a warning or an error for this.
469 // See https://github.com/webpack/webpack/issues/6571
470 sideEffects: true,
471 },
472 // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
473 // using the extension .module.css
474 {
475 test: cssModuleRegex,
476 use: getStyleLoaders({
477 importLoaders: 1,
478 sourceMap: isEnvProduction && shouldUseSourceMap,
479 modules: true,
480 getLocalIdent: getCSSModuleLocalIdent,
481 }),
482 },
483 // Opt-in support for SASS (using .scss or .sass extensions).
484 // By default we support SASS Modules with the
485 // extensions .module.scss or .module.sass
486 {
487 test: sassRegex,
488 exclude: sassModuleRegex,
489 use: getStyleLoaders(
490 {
491 importLoaders: 2,
492 sourceMap: isEnvProduction && shouldUseSourceMap,
493 },
494 'sass-loader'
495 ),
496 // Don't consider CSS imports dead code even if the
497 // containing package claims to have no side effects.
498 // Remove this when webpack adds a warning or an error for this.
499 // See https://github.com/webpack/webpack/issues/6571
500 sideEffects: true,
501 },
502 // Adds support for CSS Modules, but using SASS
503 // using the extension .module.scss or .module.sass
504 {
505 test: sassModuleRegex,
506 use: getStyleLoaders(
507 {
508 importLoaders: 2,
509 sourceMap: isEnvProduction && shouldUseSourceMap,
510 modules: true,
511 getLocalIdent: getCSSModuleLocalIdent,
512 },
513 'sass-loader'
514 ),
515 },
516 {
517 test: /\.svg$/,
518 use: {
519 loader: 'svg-sprite-loader',
520 options: {
521 extract: true,
522 spriteFilename: isEnvProduction
523 ? 'app/sprite.[hash:8].svg'
524 : 'app/sprite.svg',
525 symbolId: 'sprite-[name]',
526 },
527 },
528 },
529 // "file" loader makes sure those assets get served by WebpackDevServer.
530 // When you `import` an asset, you get its (virtual) filename.
531 // In production, they would get copied to the `build` folder.
532 // This loader doesn't use a "test" so it will catch all modules
533 // that fall through the other loaders.
534 {
535 loader: require.resolve('file-loader'),
536 // Exclude `js` files to keep "css" loader working as it injects
537 // its runtime that would otherwise be processed through "file" loader.
538 // Also exclude `html` and `json` extensions so they get processed
539 // by webpacks internal loaders.
540 exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
541 options: {
542 name: 'static/media/[name].[hash:8].[ext]',
543 },
544 },
545 // ** STOP ** Are you adding a new loader?
546 // Make sure to add the new loader(s) before the "file" loader.
547 ],
548 },
549 ],
550 },
551 plugins: [
552 new SpritePlugin({
553 plainSprite: isEnvProduction,
554 }),
555 isEnvProduction && shouldRunAnalyzer && new BundleAnalyzerPlugin(),
556 // Generates an `index.html` file with the <script> injected.
557 new HtmlWebpackPlugin(
558 Object.assign(
559 {},
560 {
561 inject: true,
562 template: paths.appHtml,
563 },
564 isEnvProduction
565 ? {
566 minify: {
567 removeComments: true,
568 collapseWhitespace: true,
569 removeRedundantAttributes: true,
570 useShortDoctype: true,
571 removeEmptyAttributes: true,
572 removeStyleLinkTypeAttributes: true,
573 keepClosingSlash: true,
574 minifyJS: true,
575 minifyCSS: true,
576 minifyURLs: true,
577 },
578 }
579 : undefined
580 )
581 ),
582 // Inlines the webpack runtime script. This script is too small to warrant
583 // a network request.
584 isEnvProduction &&
585 shouldInlineRuntimeChunk &&
586 new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
587 // Makes some environment variables available in index.html.
588 // The public URL is available as %PUBLIC_URL% in index.html, e.g.:
589 // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
590 // In production, it will be an empty string unless you specify "homepage"
591 // in `package.json`, in which case it will be the pathname of that URL.
592 // In development, this will be an empty string.
593 new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
594 // This gives some necessary context to module not found errors, such as
595 // the requesting resource.
596 new ModuleNotFoundPlugin(paths.appPath),
597 // Makes some environment variables available to the JS code, for example:
598 // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
599 // It is absolutely essential that NODE_ENV is set to production
600 // during a production build.
601 // Otherwise React will be compiled in the very slow development mode.
602 new webpack.DefinePlugin(env.stringified),
603 // This is necessary to emit hot updates (currently CSS only):
604 isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
605 // Watcher doesn't work well if you mistype casing in a path so we use
606 // a plugin that prints an error when you attempt to do this.
607 // See https://github.com/facebook/create-react-app/issues/240
608 isEnvDevelopment && new CaseSensitivePathsPlugin(),
609 // If you require a missing module and then `npm install` it, you still have
610 // to restart the development server for Webpack to discover it. This plugin
611 // makes the discovery automatic so you don't have to restart.
612 // See https://github.com/facebook/create-react-app/issues/186
613 isEnvDevelopment &&
614 new WatchMissingNodeModulesPlugin(paths.appNodeModules),
615 isEnvProduction &&
616 new MiniCssExtractPlugin({
617 // Options similar to the same options in webpackOptions.output
618 // both options are optional
619 //filename: 'static/css/[name].[contenthash:8].css',
620 //chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
621 filename: 'css/app.' + version + '.css',
622 chunkFilename: 'css/[name].[contenthash:8].css',
623 }),
624 // Generate a manifest file which contains a mapping of all asset filenames
625 // to their corresponding output file so that tools can pick it up without
626 // having to parse `index.html`.
627 new ManifestPlugin({
628 fileName: 'asset-manifest.json',
629 publicPath: publicPath,
630 generate: (seed, files) => {
631 const manifestFiles = files.reduce(function(manifest, file) {
632 manifest[file.name] = file.path;
633 return manifest;
634 }, seed);
635
636 return {
637 files: manifestFiles,
638 };
639 },
640 }),
641 // Moment.js is an extremely popular library that bundles large locale files
642 // by default due to how Webpack interprets its code. This is a practical
643 // solution that requires the user to opt into importing specific locales.
644 // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
645 // You can remove this if you don't use Moment.js:
646 new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
647 // Generate a service worker script that will precache, and keep up to date,
648 // the HTML & assets that are part of the Webpack build.
649 isEnvProduction &&
650 new WorkboxWebpackPlugin.GenerateSW({
651 clientsClaim: true,
652 exclude: [/\.map$/, /asset-manifest\.json$/],
653 importWorkboxFrom: 'cdn',
654 navigateFallback: publicUrl + '/index.html',
655 navigateFallbackBlacklist: [
656 // Exclude URLs starting with /_, as they're likely an API call
657 new RegExp('^/_'),
658 // Exclude URLs containing a dot, as they're likely a resource in
659 // public/ and not a SPA route
660 new RegExp('/[^/]+\\.[^/]+$'),
661 ],
662 }),
663 // TypeScript type checking
664 useTypeScript &&
665 new ForkTsCheckerWebpackPlugin({
666 typescript: resolve.sync('typescript', {
667 basedir: paths.appNodeModules,
668 }),
669 async: isEnvDevelopment,
670 useTypescriptIncrementalApi: true,
671 checkSyntacticErrors: true,
672 resolveModuleNameModule: process.versions.pnp
673 ? `${__dirname}/pnpTs.js`
674 : undefined,
675 resolveTypeReferenceDirectiveModule: process.versions.pnp
676 ? `${__dirname}/pnpTs.js`
677 : undefined,
678 tsconfig: paths.appTsConfig,
679 reportFiles: [
680 '**',
681 '!**/__tests__/**',
682 '!**/?(*.)(spec|test).*',
683 '!**/src/setupProxy.*',
684 '!**/src/setupTests.*',
685 ],
686 watch: paths.appSrc,
687 silent: true,
688 // The formatter is invoked directly in WebpackDevServerUtils during development
689 formatter: isEnvProduction ? typescriptFormatter : undefined,
690 }),
691 ].filter(Boolean),
692 // Some libraries import Node modules but don't use them in the browser.
693 // Tell Webpack to provide empty mocks for them so importing them works.
694 node: {
695 module: 'empty',
696 dgram: 'empty',
697 dns: 'mock',
698 fs: 'empty',
699 http2: 'empty',
700 net: 'empty',
701 tls: 'empty',
702 child_process: 'empty',
703 },
704 // Turn off performance processing because we utilize
705 // our own hints via the FileSizeReporter
706 performance: false,
707 };
708};