diff --git a/config/env.js b/config/env.js
index 211711b2..f04c21ad 100644
--- a/config/env.js
+++ b/config/env.js
@@ -1,4 +1,3 @@
-'use strict';
const fs = require('fs');
const path = require('path');
@@ -7,7 +6,8 @@ const paths = require('./paths');
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
-const NODE_ENV = process.env.NODE_ENV;
+const { NODE_ENV } = process.env;
+
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
@@ -18,6 +18,7 @@ if (!NODE_ENV) {
const dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
+
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
@@ -30,7 +31,7 @@ const dotenvFiles = [
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
-dotenvFiles.forEach(dotenvFile => {
+dotenvFiles.forEach((dotenvFile) => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
@@ -50,10 +51,11 @@ dotenvFiles.forEach(dotenvFile => {
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
+
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
- .filter(folder => folder && !path.isAbsolute(folder))
- .map(folder => path.resolve(appDirectory, folder))
+ .filter((folder) => folder && !path.isAbsolute(folder))
+ .map((folder) => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
@@ -62,16 +64,19 @@ const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
- .filter(key => REACT_APP.test(key))
+ .filter((key) => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
+
return env;
},
{
+
// Useful for determining whether we’re running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
+
// Useful for resolving the correct path to static assets in `public`.
// For example, .
// This should only be used as an escape hatch. Normally you would put
@@ -79,10 +84,12 @@ function getClientEnvironment(publicUrl) {
PUBLIC_URL: publicUrl,
}
);
+
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
+
return env;
}, {}),
};
diff --git a/config/jest/cssTransform.js b/config/jest/cssTransform.js
index 8f651148..4e138d18 100644
--- a/config/jest/cssTransform.js
+++ b/config/jest/cssTransform.js
@@ -1,4 +1,3 @@
-'use strict';
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js
index 07010e33..1567f853 100644
--- a/config/jest/fileTransform.js
+++ b/config/jest/fileTransform.js
@@ -1,4 +1,3 @@
-'use strict';
const path = require('path');
diff --git a/config/paths.js b/config/paths.js
index 65bd4599..b34d9058 100644
--- a/config/paths.js
+++ b/config/paths.js
@@ -1,4 +1,3 @@
-'use strict';
const path = require('path');
const fs = require('fs');
@@ -7,22 +6,23 @@ const url = require('url');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
-const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
+const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
const envPublicUrl = process.env.PUBLIC_URL;
function ensureSlash(inputPath, needsSlash) {
const hasSlash = inputPath.endsWith('/');
+
if (hasSlash && !needsSlash) {
return inputPath.substr(0, inputPath.length - 1);
} else if (!hasSlash && needsSlash) {
return `${inputPath}/`;
- } else {
- return inputPath;
}
+
+ return inputPath;
}
-const getPublicUrl = appPackageJson =>
+const getPublicUrl = (appPackageJson) =>
envPublicUrl || require(appPackageJson).homepage;
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
@@ -35,6 +35,7 @@ function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl =
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
+
return ensureSlash(servedUrl, true);
}
@@ -54,9 +55,8 @@ const moduleFileExtensions = [
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
- const extension = moduleFileExtensions.find(extension =>
- fs.existsSync(resolveFn(`${filePath}.${extension}`))
- );
+ const extension = moduleFileExtensions.find((extension) =>
+ fs.existsSync(resolveFn(`${filePath}.${extension}`)));
if (extension) {
return resolveFn(`${filePath}.${extension}`);
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 184c4dbb..babf3b02 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -1,4 +1,3 @@
-'use strict';
const fs = require('fs');
const path = require('path');
@@ -18,15 +17,15 @@ 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 getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt');
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
-
+const getClientEnvironment = require('./env');
+const paths = require('./paths');
// 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';
@@ -42,7 +41,8 @@ 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) {
+/* eslint-disable complexity */
+module.exports = (webpackEnv) => {
const isEnvDevelopment = webpackEnv === 'development';
const isEnvProduction = webpackEnv === 'production';
@@ -52,6 +52,7 @@ module.exports = function(webpackEnv) {
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 === './';
@@ -62,6 +63,7 @@ module.exports = function(webpackEnv) {
const publicUrl = isEnvProduction
? publicPath.slice(0, -1)
: isEnvDevelopment && '';
+
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
@@ -81,11 +83,13 @@ module.exports = function(webpackEnv) {
options: cssOptions,
},
{
+
// 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',
@@ -102,6 +106,7 @@ module.exports = function(webpackEnv) {
},
},
].filter(Boolean);
+
if (preProcessor) {
loaders.push({
loader: require.resolve(preProcessor),
@@ -110,11 +115,13 @@ module.exports = function(webpackEnv) {
},
});
}
+
return loaders;
};
return {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
+
// Stop compilation early in production
bail: isEnvProduction,
devtool: isEnvProduction
@@ -122,9 +129,11 @@ module.exports = function(webpackEnv) {
? '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
@@ -137,45 +146,55 @@ module.exports = function(webpackEnv) {
// 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].[chunkhash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
+
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[chunkhash: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,
+ publicPath,
+
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: isEnvProduction
- ? info =>
- path
- .relative(paths.appSrc, info.absoluteResourcePath)
- .replace(/\\/g, '/')
+ ? (info) =>
+ path
+ .relative(paths.appSrc, info.absoluteResourcePath)
+ .replace(/\\/g, '/')
: isEnvDevelopment &&
- (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
+ ((info) => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
},
optimization: {
minimize: isEnvProduction,
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 minfication steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
@@ -186,11 +205,13 @@ module.exports = function(webpackEnv) {
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 futher investigation:
@@ -203,35 +224,42 @@ module.exports = function(webpackEnv) {
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
parallel: true,
+
// 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,
- }
+
+ // `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
@@ -239,19 +267,23 @@ module.exports = function(webpackEnv) {
chunks: 'all',
name: false,
},
+
// Keep the runtime chunk separated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
runtimeChunk: true,
},
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'].concat(
+ modules: [ 'node_modules' ].concat(
+
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
+
// 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:
@@ -259,27 +291,31 @@ module.exports = function(webpackEnv) {
// `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')),
+ .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]),
+ 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),
@@ -288,6 +324,7 @@ module.exports = function(webpackEnv) {
module: {
strictExportPresence: true,
rules: [
+
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
@@ -301,7 +338,7 @@ module.exports = function(webpackEnv) {
options: {
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
-
+
},
loader: require.resolve('eslint-loader'),
},
@@ -309,21 +346,24 @@ module.exports = function(webpackEnv) {
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$/],
+ test: [ /\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/ ],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
+
// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
{
@@ -334,7 +374,7 @@ module.exports = function(webpackEnv) {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
-
+
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
@@ -348,6 +388,7 @@ module.exports = function(webpackEnv) {
},
],
],
+
// 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.
@@ -356,6 +397,7 @@ module.exports = function(webpackEnv) {
compact: isEnvProduction,
},
},
+
// Process any JS outside of the app with Babel.
// Unlike the application JS, we only compile the standard ES features.
{
@@ -374,7 +416,7 @@ module.exports = function(webpackEnv) {
],
cacheDirectory: true,
cacheCompression: isEnvProduction,
-
+
// 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
@@ -382,6 +424,7 @@ module.exports = function(webpackEnv) {
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