webpack.config.js 31 KB

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