Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/config/webpack.config.js
- This file was added.
'use strict'; | |||||
const darkTheme = require('@ant-design/dark-theme'); | |||||
const fs = require('fs'); | |||||
const isWsl = require('is-wsl'); | |||||
const path = require('path'); | |||||
const webpack = require('webpack'); | |||||
const resolve = require('resolve'); | |||||
const PnpWebpackPlugin = require('pnp-webpack-plugin'); | |||||
const HtmlWebpackPlugin = require('html-webpack-plugin'); | |||||
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); | |||||
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); | |||||
const TerserPlugin = require('terser-webpack-plugin'); | |||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); | |||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); | |||||
const safePostCssParser = require('postcss-safe-parser'); | |||||
const ManifestPlugin = require('webpack-manifest-plugin'); | |||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); | |||||
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); | |||||
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); | |||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); | |||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); | |||||
const paths = require('./paths'); | |||||
const modules = require('./modules'); | |||||
const getClientEnvironment = require('./env'); | |||||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); | |||||
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); | |||||
const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); | |||||
const eslint = require('eslint'); | |||||
const workboxPlugin = require('workbox-webpack-plugin'); | |||||
const postcssNormalize = require('postcss-normalize'); | |||||
const appPackageJson = require(paths.appPackageJson); | |||||
// Source maps are resource heavy and can cause out of memory issue for large source files. | |||||
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; | |||||
// Some apps do not need the benefits of saving a web request, so not inlining the chunk | |||||
// makes for a smoother build process. | |||||
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; | |||||
const imageInlineSizeLimit = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'); | |||||
// Check if TypeScript is setup | |||||
const useTypeScript = fs.existsSync(paths.appTsConfig); | |||||
// style files regexes | |||||
const cssRegex = /\.css$/; | |||||
const cssModuleRegex = /\.module\.css$/; | |||||
const sassRegex = /\.(scss|sass)$/; | |||||
const sassModuleRegex = /\.module\.(scss|sass)$/; | |||||
// This is the production and development configuration. | |||||
// It is focused on developer experience, fast rebuilds, and a minimal bundle. | |||||
module.exports = function (webpackEnv) { | |||||
const isEnvDevelopment = webpackEnv === 'development'; | |||||
const isEnvProduction = webpackEnv === 'production'; | |||||
// Webpack uses `publicPath` to determine where the app is being served from. | |||||
// It requires a trailing slash, or the file assets will get an incorrect path. | |||||
// In development, we always serve from the root. This makes config easier. | |||||
const publicPath = isEnvProduction ? paths.servedPath : isEnvDevelopment && '/'; | |||||
// Some apps do not use client-side routing with pushState. | |||||
// For these, "homepage" can be set to "." to enable relative asset paths. | |||||
const shouldUseRelativeAssetPaths = publicPath === './'; | |||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app | |||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. | |||||
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. | |||||
const publicUrl = isEnvProduction ? publicPath.slice(0, -1) : isEnvDevelopment && ''; | |||||
// Get environment variables to inject into our app. | |||||
const env = getClientEnvironment(publicUrl); | |||||
// common function to get style loaders | |||||
const getStyleLoaders = (cssOptions, preProcessor) => { | |||||
const loaders = [ | |||||
isEnvDevelopment && require.resolve('style-loader'), | |||||
isEnvProduction && { | |||||
loader: MiniCssExtractPlugin.loader, | |||||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {}, | |||||
}, | |||||
{ | |||||
loader: require.resolve('css-loader'), | |||||
options: cssOptions, | |||||
}, | |||||
{ | |||||
loader: require.resolve('less-loader'), | |||||
options: { | |||||
modifyVars: { | |||||
'@layout-sider-background': '#131720', | |||||
'@layout-trigger-background': '#20242D', | |||||
'@light': '#7F7F7F', | |||||
'@dark': '#000', | |||||
'@heading-color': 'fade(@light, 85)', | |||||
'@text-color': 'fade(@light, 65)', | |||||
'@text-color-secondary': 'fade(@light, 45)', | |||||
'@disabled-color': 'fade(@light, 25)', | |||||
'@primary-5': '#40a9ff', | |||||
'@primary-color': '#20242D', | |||||
'@outline-color': '@primary-color', | |||||
'@icon-color': 'fade(@light, 65)', | |||||
'@icon-color-hover': 'fade(@light, 85)', | |||||
'@primary-6': '#096dd9', | |||||
'@border-color-base': '@border-color-split', | |||||
'@btn-default-color': '@heading-color', | |||||
'@btn-default-bg': '#444457', | |||||
'@btn-default-border': '#444457', | |||||
'@btn-ghost-color': 'fade(@light, 45)', | |||||
'@btn-ghost-border': 'fade(@light, 45)', | |||||
'@input-color': '@text-color', | |||||
'@input-bg': '#3b3b4d', | |||||
'@input-disabled-bg': '#4c4c61', | |||||
'@input-placeholder-color': '@text-color-secondary', | |||||
'@input-hover-border-color': 'fade(@light, 10)', | |||||
'@checkbox-check-color': '#3b3b4d', | |||||
'@checkbox-color': '@primary-color', | |||||
'@select-border-color': '#3b3b4d', | |||||
'@item-active-bg': '#272733', | |||||
'@border-color-split': '#17171f', | |||||
'@menu-dark-bg': '#131720', | |||||
'@body-background': '#FBFBFD', | |||||
'@component-background': '#FFFFFF', | |||||
'@layout-body-background': '#FBFBFD', | |||||
'@tooltip-bg': '#191922', | |||||
'@tooltip-arrow-color': '#191922', | |||||
'@popover-bg': '#2d2d3b', | |||||
'@success-color': '#00a854', | |||||
'@info-color': '@primary-color', | |||||
'@warning-color': '#ffbf00', | |||||
'@error-color': '#f04134', | |||||
'@menu-bg': '#20242D', | |||||
'@menu-item-active-bg': 'fade(@light, 5)', | |||||
'@menu-highlight-color': '@light', | |||||
'@card-background': '@component-background', | |||||
'@card-hover-border': '#383847', | |||||
'@card-actions-background': '#FBFCFD', | |||||
'@tail-color': 'fade(@light, 10)', | |||||
'@radio-button-bg': 'transparent', | |||||
'@radio-button-checked-bg': 'transparent', | |||||
'@radio-dot-color': '@primary-color', | |||||
'@table-row-hover-bg': '#383847', | |||||
'@item-hover-bg': '#383847', | |||||
'@alert-text-color': 'fade(@dark, 65%)', | |||||
'@tabs-horizontal-padding': '12px 0', | |||||
// zIndex': 'notification > popover > tooltip | |||||
'@zindex-notification': '1063', | |||||
'@zindex-popover': '1061', | |||||
'@zindex-tooltip': '1060', | |||||
// width | |||||
'@anchor-border-width': '1px', | |||||
// margin | |||||
'@form-item-margin-bottom': '24px', | |||||
'@menu-item-vertical-margin': '0px', | |||||
'@menu-item-boundary-margin': '0px', | |||||
// size | |||||
'@font-size-base': '14px', | |||||
'@font-size-lg': '16px', | |||||
'@screen-xl': '1208px', | |||||
'@screen-lg': '1024px', | |||||
'@screen-md': '768px', | |||||
// 移动 | |||||
'@screen-sm': '767.9px', | |||||
// 超小屏 | |||||
'@screen-xs': '375px', | |||||
'@alert-message-color': '@popover-bg', | |||||
'@background-color-light': '@popover-bg', | |||||
'@layout-header-background': '@menu-dark-bg', | |||||
// 官网 | |||||
'@site-text-color': '@text-color', | |||||
'@site-border-color-split': 'fade(@light, 5)', | |||||
'@site-heading-color': '@heading-color', | |||||
'@site-header-box-shadow': | |||||
'0 0.3px 0.9px rgba(0, 0, 0, 0.12), 0 1.6px 3.6px rgba(0, 0, 0, 0.12)', | |||||
'@home-text-color': '@text-color', | |||||
//自定义需要找设计师 | |||||
'@gray-8': '@text-color', | |||||
'@background-color-base': '#FBFBFD', | |||||
'@skeleton-color': 'rgba(0,0,0,0.8)', | |||||
// pro | |||||
'@pro-header-box-shadow': '@site-header-box-shadow', | |||||
}, | |||||
javascriptEnabled: true, | |||||
}, | |||||
}, | |||||
{ | |||||
// Options for PostCSS as we reference these options twice | |||||
// Adds vendor prefixing based on your specified browser support in | |||||
// package.json | |||||
loader: require.resolve('postcss-loader'), | |||||
options: { | |||||
// Necessary for external CSS imports to work | |||||
// https://github.com/facebook/create-react-app/issues/2677 | |||||
ident: 'postcss', | |||||
plugins: () => [ | |||||
require('postcss-flexbugs-fixes'), | |||||
require('postcss-preset-env')({ | |||||
autoprefixer: { | |||||
flexbox: 'no-2009', | |||||
}, | |||||
stage: 3, | |||||
}), | |||||
// Adds PostCSS Normalize as the reset css with default options, | |||||
// so that it honors browserslist config in package.json | |||||
// which in turn let's users customize the target behavior as per their needs. | |||||
postcssNormalize(), | |||||
], | |||||
sourceMap: isEnvProduction && shouldUseSourceMap, | |||||
}, | |||||
}, | |||||
].filter(Boolean); | |||||
if (preProcessor) { | |||||
loaders.push( | |||||
{ | |||||
loader: require.resolve('resolve-url-loader'), | |||||
options: { | |||||
sourceMap: isEnvProduction && shouldUseSourceMap, | |||||
}, | |||||
}, | |||||
{ | |||||
loader: require.resolve(preProcessor), | |||||
options: { | |||||
sourceMap: true, | |||||
}, | |||||
}, | |||||
); | |||||
} | |||||
return loaders; | |||||
}; | |||||
return { | |||||
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development', | |||||
// Stop compilation early in production | |||||
bail: isEnvProduction, | |||||
devtool: isEnvProduction | |||||
? shouldUseSourceMap | |||||
? 'source-map' | |||||
: false | |||||
: isEnvDevelopment && 'cheap-module-source-map', | |||||
// These are the "entry points" to our application. | |||||
// This means they will be the "root" imports that are included in JS bundle. | |||||
entry: [ | |||||
// Include an alternative client for WebpackDevServer. A client's job is to | |||||
// connect to WebpackDevServer by a socket and get notified about changes. | |||||
// When you save a file, the client will either apply hot updates (in case | |||||
// of CSS changes), or refresh the page (in case of JS changes). When you | |||||
// make a syntax error, this client will display a syntax error overlay. | |||||
// Note: instead of the default WebpackDevServer client, we use a custom one | |||||
// to bring better experience for Create React App users. You can replace | |||||
// the line below with these two lines if you prefer the stock client: | |||||
// require.resolve('webpack-dev-server/client') + '?/', | |||||
// require.resolve('webpack/hot/dev-server'), | |||||
isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'), | |||||
// Finally, this is your app's code: | |||||
paths.appIndexJs, | |||||
// We include the app code last so that if there is a runtime error during | |||||
// initialization, it doesn't blow up the WebpackDevServer client, and | |||||
// changing JS code would still trigger a refresh. | |||||
].filter(Boolean), | |||||
output: { | |||||
// The build folder. | |||||
path: isEnvProduction ? paths.appBuild : undefined, | |||||
// Add /* filename */ comments to generated require()s in the output. | |||||
pathinfo: isEnvDevelopment, | |||||
// There will be one main bundle, and one file per asynchronous chunk. | |||||
// In development, it does not produce real files. | |||||
filename: isEnvProduction | |||||
? 'static/js/[name].[contenthash:8].js' | |||||
: isEnvDevelopment && 'static/js/bundle.js', | |||||
// TODO: remove this when upgrading to webpack 5 | |||||
futureEmitAssets: true, | |||||
// There are also additional JS chunk files if you use code splitting. | |||||
chunkFilename: isEnvProduction | |||||
? 'static/js/[name].[contenthash:8].chunk.js' | |||||
: isEnvDevelopment && 'static/js/[name].chunk.js', | |||||
// We inferred the "public path" (such as / or /my-project) from homepage. | |||||
// We use "/" in development. | |||||
publicPath: publicPath, | |||||
// Point sourcemap entries to original disk location (format as URL on Windows) | |||||
devtoolModuleFilenameTemplate: isEnvProduction | |||||
? (info) => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/') | |||||
: isEnvDevelopment && | |||||
((info) => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), | |||||
// Prevents conflicts when multiple Webpack runtimes (from different apps) | |||||
// are used on the same page. | |||||
jsonpFunction: `webpackJsonp${appPackageJson.name}`, | |||||
}, | |||||
optimization: { | |||||
minimize: false, | |||||
minimizer: [ | |||||
// This is only used in production mode | |||||
new TerserPlugin({ | |||||
terserOptions: { | |||||
parse: { | |||||
// We want terser to parse ecma 8 code. However, we don't want it | |||||
// to apply any minification steps that turns valid ecma 5 code | |||||
// into invalid ecma 5 code. This is why the 'compress' and 'output' | |||||
// sections only apply transformations that are ecma 5 safe | |||||
// https://github.com/facebook/create-react-app/pull/4234 | |||||
ecma: 8, | |||||
}, | |||||
compress: { | |||||
ecma: 5, | |||||
warnings: false, | |||||
// Disabled because of an issue with Uglify breaking seemingly valid code: | |||||
// https://github.com/facebook/create-react-app/issues/2376 | |||||
// Pending further investigation: | |||||
// https://github.com/mishoo/UglifyJS2/issues/2011 | |||||
comparisons: false, | |||||
// Disabled because of an issue with Terser breaking valid code: | |||||
// https://github.com/facebook/create-react-app/issues/5250 | |||||
// Pending further investigation: | |||||
// https://github.com/terser-js/terser/issues/120 | |||||
inline: 2, | |||||
}, | |||||
mangle: { | |||||
safari10: true, | |||||
}, | |||||
output: { | |||||
ecma: 5, | |||||
comments: false, | |||||
// Turned on because emoji and regex is not minified properly using default | |||||
// https://github.com/facebook/create-react-app/issues/2488 | |||||
ascii_only: true, | |||||
}, | |||||
}, | |||||
// Use multi-process parallel running to improve the build speed | |||||
// Default number of concurrent runs: os.cpus().length - 1 | |||||
// Disabled on WSL (Windows Subsystem for Linux) due to an issue with Terser | |||||
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/21 | |||||
parallel: !isWsl, | |||||
// Enable file caching | |||||
cache: true, | |||||
sourceMap: shouldUseSourceMap, | |||||
}), | |||||
// This is only used in production mode | |||||
new OptimizeCSSAssetsPlugin({ | |||||
cssProcessorOptions: { | |||||
parser: safePostCssParser, | |||||
map: shouldUseSourceMap | |||||
? { | |||||
// `inline: false` forces the sourcemap to be output into a | |||||
// separate file | |||||
inline: false, | |||||
// `annotation: true` appends the sourceMappingURL to the end of | |||||
// the css file, helping the browser find the sourcemap | |||||
annotation: true, | |||||
} | |||||
: false, | |||||
}, | |||||
}), | |||||
], | |||||
// Automatically split vendor and commons | |||||
// https://twitter.com/wSokra/status/969633336732905474 | |||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 | |||||
splitChunks: { | |||||
chunks: 'all', | |||||
name: false, | |||||
}, | |||||
// Keep the runtime chunk separated to enable long term caching | |||||
// https://twitter.com/wSokra/status/969679223278505985 | |||||
// https://github.com/facebook/create-react-app/issues/5358 | |||||
runtimeChunk: { | |||||
name: (entrypoint) => `runtime-${entrypoint.name}`, | |||||
}, | |||||
}, | |||||
resolve: { | |||||
// This allows you to set a fallback for where Webpack should look for modules. | |||||
// We placed these paths second because we want `node_modules` to "win" | |||||
// if there are any conflicts. This matches Node resolution mechanism. | |||||
// https://github.com/facebook/create-react-app/issues/253 | |||||
modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []), | |||||
// These are the reasonable defaults supported by the Node ecosystem. | |||||
// We also include JSX as a common component filename extension to support | |||||
// some tools, although we do not recommend using it, see: | |||||
// https://github.com/facebook/create-react-app/issues/290 | |||||
// `web` extension prefixes have been added for better support | |||||
// for React Native Web. | |||||
extensions: paths.moduleFileExtensions | |||||
.map((ext) => `.${ext}`) | |||||
.filter((ext) => useTypeScript || !ext.includes('ts')), | |||||
alias: { | |||||
// Support React Native Web | |||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ | |||||
'react-native': 'react-native-web', | |||||
}, | |||||
plugins: [ | |||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding | |||||
// guards against forgotten dependencies and such. | |||||
PnpWebpackPlugin, | |||||
// Prevents users from importing files from outside of src/ (or node_modules/). | |||||
// This often causes confusion because we only process files within src/ with babel. | |||||
// To fix this, we prevent you from importing files out of src/ -- if you'd like to, | |||||
// please link the files into your node_modules/ and let module-resolution kick in. | |||||
// Make sure your source files are compiled, as they will not be processed in any way. | |||||
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), | |||||
], | |||||
}, | |||||
resolveLoader: { | |||||
plugins: [ | |||||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders | |||||
// from the current package. | |||||
PnpWebpackPlugin.moduleLoader(module), | |||||
], | |||||
}, | |||||
module: { | |||||
strictExportPresence: true, | |||||
rules: [ | |||||
// Disable require.ensure as it's not a standard language feature. | |||||
{ parser: { requireEnsure: false } }, | |||||
// First, run the linter. | |||||
// It's important to do this before Babel processes the JS. | |||||
{ | |||||
test: /\.(js|mjs|jsx|ts|tsx)$/, | |||||
enforce: 'pre', | |||||
use: [ | |||||
{ | |||||
options: { | |||||
cache: true, | |||||
formatter: require.resolve('react-dev-utils/eslintFormatter'), | |||||
eslintPath: require.resolve('eslint'), | |||||
resolvePluginsRelativeTo: __dirname, | |||||
}, | |||||
loader: require.resolve('eslint-loader'), | |||||
}, | |||||
], | |||||
include: paths.appSrc, | |||||
}, | |||||
{ | |||||
// "oneOf" will traverse all following loaders until one will | |||||
// match the requirements. When no loader matches it will fall | |||||
// back to the "file" loader at the end of the loader list. | |||||
oneOf: [ | |||||
// "url" loader works like "file" loader except that it embeds assets | |||||
// smaller than specified limit in bytes as data URLs to avoid requests. | |||||
// A missing `test` is equivalent to a match. | |||||
{ | |||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], | |||||
loader: require.resolve('url-loader'), | |||||
options: { | |||||
limit: imageInlineSizeLimit, | |||||
name: 'static/media/[name].[hash:8].[ext]', | |||||
}, | |||||
}, | |||||
// Process application JS with Babel. | |||||
// The preset includes JSX, Flow, TypeScript, and some ESnext features. | |||||
{ | |||||
test: /\.(js|mjs|jsx|ts|tsx)$/, | |||||
include: paths.appSrc, | |||||
loader: require.resolve('babel-loader'), | |||||
options: { | |||||
customize: require.resolve('babel-preset-react-app/webpack-overrides'), | |||||
plugins: [ | |||||
[ | |||||
require.resolve('babel-plugin-named-asset-import'), | |||||
{ | |||||
loaderMap: { | |||||
svg: { | |||||
ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]', | |||||
}, | |||||
}, | |||||
}, | |||||
], | |||||
], | |||||
// This is a feature of `babel-loader` for webpack (not Babel itself). | |||||
// It enables caching results in ./node_modules/.cache/babel-loader/ | |||||
// directory for faster rebuilds. | |||||
cacheDirectory: true, | |||||
// See #6846 for context on why cacheCompression is disabled | |||||
cacheCompression: false, | |||||
compact: isEnvProduction, | |||||
}, | |||||
}, | |||||
// Process any JS outside of the app with Babel. | |||||
// Unlike the application JS, we only compile the standard ES features. | |||||
{ | |||||
test: /\.(js|mjs)$/, | |||||
exclude: /@babel(?:\/|\\{1,2})runtime/, | |||||
loader: require.resolve('babel-loader'), | |||||
options: { | |||||
babelrc: false, | |||||
configFile: false, | |||||
compact: false, | |||||
presets: [ | |||||
[require.resolve('babel-preset-react-app/dependencies'), { helpers: true }], | |||||
], | |||||
cacheDirectory: true, | |||||
// See #6846 for context on why cacheCompression is disabled | |||||
cacheCompression: false, | |||||
// If an error happens in a package, it's possible to be | |||||
// because it was compiled. Thus, we don't want the browser | |||||
// debugger to show the original code. Instead, the code | |||||
// being evaluated would be much more helpful. | |||||
sourceMaps: false, | |||||
}, | |||||
}, | |||||
// "postcss" loader applies autoprefixer to our CSS. | |||||
// "css" loader resolves paths in CSS and adds assets as dependencies. | |||||
// "style" loader turns CSS into JS modules that inject <style> tags. | |||||
// In production, we use MiniCSSExtractPlugin to extract that CSS | |||||
// to a file, but in development "style" loader enables hot editing | |||||
// of CSS. | |||||
// By default we support CSS Modules with the extension .module.css | |||||
{ | |||||
test: cssRegex, | |||||
exclude: cssModuleRegex, | |||||
use: getStyleLoaders({ | |||||
importLoaders: 1, | |||||
sourceMap: isEnvProduction && shouldUseSourceMap, | |||||
}), | |||||
// Don't consider CSS imports dead code even if the | |||||
// containing package claims to have no side effects. | |||||
// Remove this when webpack adds a warning or an error for this. | |||||
// See https://github.com/webpack/webpack/issues/6571 | |||||
sideEffects: true, | |||||
}, | |||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules) | |||||
// using the extension .module.css | |||||
{ | |||||
test: cssModuleRegex, | |||||
use: getStyleLoaders({ | |||||
importLoaders: 1, | |||||
sourceMap: isEnvProduction && shouldUseSourceMap, | |||||
modules: true, | |||||
getLocalIdent: getCSSModuleLocalIdent, | |||||
}), | |||||
}, | |||||
// Opt-in support for SASS (using .scss or .sass extensions). | |||||
// By default we support SASS Modules with the | |||||
// extensions .module.scss or .module.sass | |||||
{ | |||||
test: sassRegex, | |||||
exclude: sassModuleRegex, | |||||
use: getStyleLoaders( | |||||
{ | |||||
importLoaders: 2, | |||||
sourceMap: isEnvProduction && shouldUseSourceMap, | |||||
}, | |||||
'sass-loader', | |||||
), | |||||
// Don't consider CSS imports dead code even if the | |||||
// containing package claims to have no side effects. | |||||
// Remove this when webpack adds a warning or an error for this. | |||||
// See https://github.com/webpack/webpack/issues/6571 | |||||
sideEffects: true, | |||||
}, | |||||
// Adds support for CSS Modules, but using SASS | |||||
// using the extension .module.scss or .module.sass | |||||
{ | |||||
test: sassModuleRegex, | |||||
use: getStyleLoaders( | |||||
{ | |||||
importLoaders: 2, | |||||
sourceMap: isEnvProduction && shouldUseSourceMap, | |||||
modules: true, | |||||
getLocalIdent: getCSSModuleLocalIdent, | |||||
}, | |||||
'sass-loader', | |||||
), | |||||
}, | |||||
// "file" loader makes sure those assets get served by WebpackDevServer. | |||||
// When you `import` an asset, you get its (virtual) filename. | |||||
// In production, they would get copied to the `build` folder. | |||||
// This loader doesn't use a "test" so it will catch all modules | |||||
// that fall through the other loaders. | |||||
{ | |||||
loader: require.resolve('file-loader'), | |||||
// Exclude `js` files to keep "css" loader working as it injects | |||||
// its runtime that would otherwise be processed through "file" loader. | |||||
// Also exclude `html` and `json` extensions so they get processed | |||||
// by webpacks internal loaders. | |||||
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], | |||||
options: { | |||||
name: 'static/media/[name].[hash:8].[ext]', | |||||
}, | |||||
}, | |||||
// ** STOP ** Are you adding a new loader? | |||||
// Make sure to add the new loader(s) before the "file" loader. | |||||
], | |||||
}, | |||||
], | |||||
}, | |||||
plugins: [ | |||||
// Generates an `index.html` file with the <script> injected. | |||||
new HtmlWebpackPlugin( | |||||
Object.assign( | |||||
{}, | |||||
{ | |||||
inject: true, | |||||
template: paths.appHtml, | |||||
}, | |||||
isEnvProduction | |||||
? { | |||||
minify: { | |||||
removeComments: true, | |||||
collapseWhitespace: true, | |||||
removeRedundantAttributes: true, | |||||
useShortDoctype: true, | |||||
removeEmptyAttributes: true, | |||||
removeStyleLinkTypeAttributes: true, | |||||
keepClosingSlash: true, | |||||
minifyJS: true, | |||||
minifyCSS: true, | |||||
minifyURLs: true, | |||||
}, | |||||
} | |||||
: undefined, | |||||
), | |||||
), | |||||
// Inlines the webpack runtime script. This script is too small to warrant | |||||
// a network request. | |||||
// https://github.com/facebook/create-react-app/issues/5358 | |||||
isEnvProduction && | |||||
shouldInlineRuntimeChunk && | |||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]), | |||||
// Makes some environment variables available in index.html. | |||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.: | |||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> | |||||
// In production, it will be an empty string unless you specify "homepage" | |||||
// in `package.json`, in which case it will be the pathname of that URL. | |||||
// In development, this will be an empty string. | |||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), | |||||
// This gives some necessary context to module not found errors, such as | |||||
// the requesting resource. | |||||
new ModuleNotFoundPlugin(paths.appPath), | |||||
// Makes some environment variables available to the JS code, for example: | |||||
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. | |||||
// It is absolutely essential that NODE_ENV is set to production | |||||
// during a production build. | |||||
// Otherwise React will be compiled in the very slow development mode. | |||||
new webpack.DefinePlugin(env.stringified), | |||||
// This is necessary to emit hot updates (currently CSS only): | |||||
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(), | |||||
// Watcher doesn't work well if you mistype casing in a path so we use | |||||
// a plugin that prints an error when you attempt to do this. | |||||
// See https://github.com/facebook/create-react-app/issues/240 | |||||
isEnvDevelopment && new CaseSensitivePathsPlugin(), | |||||
// If you require a missing module and then `npm install` it, you still have | |||||
// to restart the development server for Webpack to discover it. This plugin | |||||
// makes the discovery automatic so you don't have to restart. | |||||
// See https://github.com/facebook/create-react-app/issues/186 | |||||
isEnvDevelopment && new WatchMissingNodeModulesPlugin(paths.appNodeModules), | |||||
isEnvProduction && | |||||
new MiniCssExtractPlugin({ | |||||
// Options similar to the same options in webpackOptions.output | |||||
// both options are optional | |||||
filename: 'static/css/[name].[contenthash:8].css', | |||||
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css', | |||||
}), | |||||
// Generate a manifest file which contains a mapping of all asset filenames | |||||
// to their corresponding output file so that tools can pick it up without | |||||
// having to parse `index.html`. | |||||
new ManifestPlugin({ | |||||
fileName: 'asset-manifest.json', | |||||
publicPath: publicPath, | |||||
generate: (seed, files) => { | |||||
const manifestFiles = files.reduce(function (manifest, file) { | |||||
manifest[file.name] = file.path; | |||||
return manifest; | |||||
}, seed); | |||||
return { | |||||
files: manifestFiles, | |||||
}; | |||||
}, | |||||
}), | |||||
// Moment.js is an extremely popular library that bundles large locale files | |||||
// by default due to how Webpack interprets its code. This is a practical | |||||
// solution that requires the user to opt into importing specific locales. | |||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack | |||||
// You can remove this if you don't use Moment.js: | |||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), | |||||
// TypeScript type checking | |||||
useTypeScript && | |||||
new ForkTsCheckerWebpackPlugin({ | |||||
typescript: resolve.sync('typescript', { | |||||
basedir: paths.appNodeModules, | |||||
}), | |||||
async: isEnvDevelopment, | |||||
useTypescriptIncrementalApi: true, | |||||
checkSyntacticErrors: true, | |||||
resolveModuleNameModule: process.versions.pnp ? `${__dirname}/pnpTs.js` : undefined, | |||||
resolveTypeReferenceDirectiveModule: process.versions.pnp | |||||
? `${__dirname}/pnpTs.js` | |||||
: undefined, | |||||
tsconfig: paths.appTsConfig, | |||||
reportFiles: [ | |||||
'**', | |||||
'!**/__tests__/**', | |||||
'!**/?(*.)(spec|test).*', | |||||
'!**/src/setupProxy.*', | |||||
'!**/src/setupTests.*', | |||||
], | |||||
silent: true, | |||||
// The formatter is invoked directly in WebpackDevServerUtils during development | |||||
formatter: isEnvProduction ? typescriptFormatter : undefined, | |||||
}), | |||||
new workboxPlugin.InjectManifest({ | |||||
swSrc: './src/serviceWorker.js', | |||||
swDest: 'serviceWorker.js', | |||||
}), | |||||
].filter(Boolean), | |||||
// Some libraries import Node modules but don't use them in the browser. | |||||
// Tell Webpack to provide empty mocks for them so importing them works. | |||||
node: { | |||||
module: 'empty', | |||||
dgram: 'empty', | |||||
dns: 'mock', | |||||
fs: 'empty', | |||||
http2: 'empty', | |||||
net: 'empty', | |||||
tls: 'empty', | |||||
child_process: 'empty', | |||||
}, | |||||
// Turn off performance processing because we utilize | |||||
// our own hints via the FileSizeReporter | |||||
performance: false, | |||||
}; | |||||
}; |