UNPKG

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