webpack.config.js 29 KB

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