Skip to content

Instantly share code, notes, and snippets.

@bartekus
Last active April 3, 2020 22:32
Show Gist options
  • Select an option

  • Save bartekus/10896b9821a3ad91bb353e985144d38f to your computer and use it in GitHub Desktop.

Select an option

Save bartekus/10896b9821a3ad91bb353e985144d38f to your computer and use it in GitHub Desktop.

Revisions

  1. bartekus revised this gist Apr 3, 2020. 3 changed files with 87 additions and 29 deletions.
    2 changes: 1 addition & 1 deletion build.js
    Original file line number Diff line number Diff line change
    @@ -222,6 +222,6 @@ function build(previousFileSizes) {
    function copyPublicFolder() {
    fs.copySync(paths.appPublic, paths.appBuild, {
    dereference: true,
    filter: file => file !== paths.appHtml,
    filter: file => file !== paths.appHtml && file !== paths.appBackgroundHtml && file !== paths.appOptionsHtml,
    });
    }
    12 changes: 12 additions & 0 deletions paths.js
    Original file line number Diff line number Diff line change
    @@ -63,7 +63,11 @@ module.exports = {
    appBuild: resolveApp('build'),
    appPublic: resolveApp('public'),
    appHtml: resolveApp('public/index.html'),
    appBackgroundHtml: resolveApp('public/background.html'),
    appOptionsHtml: resolveApp('public/options.html'),
    appIndexJs: resolveModule(resolveApp, 'src/index'),
    appBackgroundJs: resolveModule(resolveApp, 'src/background'),
    appOptionsJs: resolveModule(resolveApp, 'src/options'),
    appPackageJson: resolveApp('package.json'),
    appSrc: resolveApp('src'),
    appTsConfig: resolveApp('tsconfig.json'),
    @@ -85,7 +89,11 @@ module.exports = {
    appBuild: resolveApp('build'),
    appPublic: resolveApp('public'),
    appHtml: resolveApp('public/index.html'),
    appBackgroundHtml: resolveApp('public/background.html'),
    appOptionsHtml: resolveApp('public/options.html'),
    appIndexJs: resolveModule(resolveApp, 'src/index'),
    appBackgroundJs: resolveModule(resolveApp, 'src/background'),
    appOptionsJs: resolveModule(resolveApp, 'src/options'),
    appPackageJson: resolveApp('package.json'),
    appSrc: resolveApp('src'),
    appTsConfig: resolveApp('tsconfig.json'),
    @@ -120,7 +128,11 @@ if (
    appBuild: resolveOwn('../../build'),
    appPublic: resolveOwn(`${templatePath}/public`),
    appHtml: resolveOwn(`${templatePath}/public/index.html`),
    appBackgroundHtml: resolveOwn(`${templatePath}/public/background.html`),
    appOptionsHtml: resolveOwn(`${templatePath}/public/options.html`),
    appIndexJs: resolveModule(resolveOwn, `${templatePath}/src/index`),
    appBackgroundJs: resolveModule(resolveOwn, `${templatePath}/src/background`),
    appOptionsJs: resolveModule(resolveOwn, `${templatePath}/src/options`),
    appPackageJson: resolveOwn('package.json'),
    appSrc: resolveOwn(`${templatePath}/src`),
    appTsConfig: resolveOwn(`${templatePath}/tsconfig.json`),
    102 changes: 74 additions & 28 deletions webpack.config.js
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@ const appPackageJson = require(paths.appPackageJson);
    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 shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';

    const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true';

    @@ -149,35 +149,21 @@ module.exports = function(webpackEnv) {
    : 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),
    entry: {
    background: paths.appBackgroundJs,
    options: paths.appOptionsJs,
    popup: paths.appIndexJs,
    },
    output: {
    // The build folder.
    path: isEnvProduction ? paths.appBuild : undefined,
    path: paths.appBuild,
    // 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',
    : isEnvDevelopment && 'static/js/[name].bundle.js',
    // TODO: remove this when upgrading to webpack 5
    futureEmitAssets: true,
    // There are also additional JS chunk files if you use code splitting.
    @@ -558,13 +544,70 @@ module.exports = function(webpackEnv) {
    ],
    },
    plugins: [
    // Generates an `background.html` file with the <script> injected.
    new HtmlWebpackPlugin(
    Object.assign(
    {},
    {
    inject: true,
    template: paths.appBackgroundHtml,
    filename: 'background.html',
    excludeChunks: ['popup', 'options'],
    },
    isEnvProduction
    ? {
    minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeRedundantAttributes: true,
    useShortDoctype: true,
    removeEmptyAttributes: true,
    removeStyleLinkTypeAttributes: true,
    keepClosingSlash: true,
    minifyJS: true,
    minifyCSS: true,
    minifyURLs: true,
    },
    }
    : undefined
    )
    ),
    // Generates an `options.html` file with the <script> injected.
    new HtmlWebpackPlugin(
    Object.assign(
    {},
    {
    inject: true,
    template: paths.appOptionsHtml,
    filename: 'options.html',
    excludeChunks: ['popup', 'background'],
    },
    isEnvProduction
    ? {
    minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeRedundantAttributes: true,
    useShortDoctype: true,
    removeEmptyAttributes: true,
    removeStyleLinkTypeAttributes: true,
    keepClosingSlash: true,
    minifyJS: true,
    minifyCSS: true,
    minifyURLs: true,
    },
    }
    : undefined
    )
    ),
    // Generates an `index.html` file with the <script> injected.
    new HtmlWebpackPlugin(
    Object.assign(
    {},
    {
    inject: true,
    template: paths.appHtml,
    excludeChunks: ['background', 'options'],
    },
    isEnvProduction
    ? {
    @@ -587,9 +630,9 @@ module.exports = function(webpackEnv) {
    // 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/]),
    // 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="icon" href="%PUBLIC_URL%/favicon.ico">
    @@ -638,9 +681,12 @@ module.exports = function(webpackEnv) {
    manifest[file.name] = file.path;
    return manifest;
    }, seed);
    const entrypointFiles = entrypoints.main.filter(
    fileName => !fileName.endsWith('.map')
    );
    const entrypointFiles = {};
    for (const property in entrypoints) {
    entrypointFiles[property] = entrypoints[property].filter(
    fileName => !fileName.endsWith('.map')
    );
    }

    return {
    files: manifestFiles,
  2. bartekus created this gist Apr 3, 2020.
    227 changes: 227 additions & 0 deletions build.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,227 @@
    // @remove-on-eject-begin
    /**
    * Copyright (c) 2015-present, Facebook, Inc.
    *
    * This source code is licensed under the MIT license found in the
    * LICENSE file in the root directory of this source tree.
    */
    // @remove-on-eject-end
    'use strict';

    // Do this as the first thing so that any code reading it knows the right env.
    process.env.BABEL_ENV = 'production';
    process.env.NODE_ENV = 'production';

    // Makes the script crash on unhandled rejections instead of silently
    // ignoring them. In the future, promise rejections that are not handled will
    // terminate the Node.js process with a non-zero exit code.
    process.on('unhandledRejection', err => {
    throw err;
    });

    // Ensure environment variables are read.
    require('../config/env');
    // @remove-on-eject-begin
    // Do the preflight checks (only happens before eject).
    const verifyPackageTree = require('./utils/verifyPackageTree');
    if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') {
    verifyPackageTree();
    }
    const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup');
    verifyTypeScriptSetup();
    // @remove-on-eject-end

    const path = require('path');
    const chalk = require('react-dev-utils/chalk');
    const fs = require('fs-extra');
    const webpack = require('webpack');
    const configFactory = require('../config/webpack.config');
    const paths = require('../config/paths');
    const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
    const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
    const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
    const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
    const printBuildError = require('react-dev-utils/printBuildError');

    const measureFileSizesBeforeBuild =
    FileSizeReporter.measureFileSizesBeforeBuild;
    const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
    const useYarn = fs.existsSync(paths.yarnLockFile);

    // These sizes are pretty large. We'll warn for bundles exceeding them.
    const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
    const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;

    const isInteractive = process.stdout.isTTY;

    // Warn and crash if required files are missing
    if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
    process.exit(1);
    }

    // Generate configuration
    const config = configFactory('production');

    // We require that you explicitly set browsers and do not fall back to
    // browserslist defaults.
    const { checkBrowsers } = require('react-dev-utils/browsersHelper');
    checkBrowsers(paths.appPath, isInteractive)
    .then(() => {
    // First, read the current file sizes in build directory.
    // This lets us display how much they changed later.
    return measureFileSizesBeforeBuild(paths.appBuild);
    })
    .then(previousFileSizes => {
    // Remove all content but keep the directory so that
    // if you're in it, you don't end up in Trash
    fs.emptyDirSync(paths.appBuild);
    // Merge with the public folder
    copyPublicFolder();
    // Start the webpack build
    return build(previousFileSizes);
    })
    .then(
    ({ stats, previousFileSizes, warnings }) => {
    if (warnings.length) {
    console.log(chalk.yellow('Compiled with warnings.\n'));
    console.log(warnings.join('\n\n'));
    console.log(
    '\nSearch for the ' +
    chalk.underline(chalk.yellow('keywords')) +
    ' to learn more about each warning.'
    );
    console.log(
    'To ignore, add ' +
    chalk.cyan('// eslint-disable-next-line') +
    ' to the line before.\n'
    );
    } else {
    console.log(chalk.green('Compiled successfully.\n'));
    }

    console.log('File sizes after gzip:\n');
    printFileSizesAfterBuild(
    stats,
    previousFileSizes,
    paths.appBuild,
    WARN_AFTER_BUNDLE_GZIP_SIZE,
    WARN_AFTER_CHUNK_GZIP_SIZE
    );
    console.log();

    const appPackage = require(paths.appPackageJson);
    const publicUrl = paths.publicUrlOrPath;
    const publicPath = config.output.publicPath;
    const buildFolder = path.relative(process.cwd(), paths.appBuild);
    printHostingInstructions(
    appPackage,
    publicUrl,
    publicPath,
    buildFolder,
    useYarn
    );
    },
    err => {
    const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
    if (tscCompileOnError) {
    console.log(
    chalk.yellow(
    'Compiled with the following type errors (you may want to check these before deploying your app):\n'
    )
    );
    printBuildError(err);
    } else {
    console.log(chalk.red('Failed to compile.\n'));
    printBuildError(err);
    process.exit(1);
    }
    }
    )
    .catch(err => {
    if (err && err.message) {
    console.log(err.message);
    }
    process.exit(1);
    });

    // Create the production build and print the deployment instructions.
    function build(previousFileSizes) {
    // We used to support resolving modules according to `NODE_PATH`.
    // This now has been deprecated in favor of jsconfig/tsconfig.json
    // This lets you use absolute paths in imports inside large monorepos:
    if (process.env.NODE_PATH) {
    console.log(
    chalk.yellow(
    'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
    )
    );
    console.log();
    }

    console.log('Creating an optimized production build...');

    const compiler = webpack(config);
    return new Promise((resolve, reject) => {
    compiler.run((err, stats) => {
    let messages;
    if (err) {
    if (!err.message) {
    return reject(err);
    }

    let errMessage = err.message;

    // Add additional information for postcss errors
    if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
    errMessage +=
    '\nCompileError: Begins at CSS selector ' +
    err['postcssNode'].selector;
    }

    messages = formatWebpackMessages({
    errors: [errMessage],
    warnings: [],
    });
    } else {
    messages = formatWebpackMessages(
    stats.toJson({ all: false, warnings: true, errors: true })
    );
    }
    if (messages.errors.length) {
    // Only keep the first error. Others are often indicative
    // of the same problem, but confuse the reader with noise.
    if (messages.errors.length > 1) {
    messages.errors.length = 1;
    }
    return reject(new Error(messages.errors.join('\n\n')));
    }
    if (
    process.env.CI &&
    (typeof process.env.CI !== 'string' ||
    process.env.CI.toLowerCase() !== 'false') &&
    messages.warnings.length
    ) {
    console.log(
    chalk.yellow(
    '\nTreating warnings as errors because process.env.CI = true.\n' +
    'Most CI servers set it automatically.\n'
    )
    );
    return reject(new Error(messages.warnings.join('\n\n')));
    }

    return resolve({
    stats,
    previousFileSizes,
    warnings: messages.warnings,
    });
    });
    });
    }

    function copyPublicFolder() {
    fs.copySync(paths.appPublic, paths.appBuild, {
    dereference: true,
    filter: file => file !== paths.appHtml,
    });
    }
    142 changes: 142 additions & 0 deletions paths.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,142 @@
    // @remove-on-eject-begin
    /**
    * Copyright (c) 2015-present, Facebook, Inc.
    *
    * This source code is licensed under the MIT license found in the
    * LICENSE file in the root directory of this source tree.
    */
    // @remove-on-eject-end
    'use strict';

    const path = require('path');
    const fs = require('fs');
    const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');

    // 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);

    // We use `PUBLIC_URL` environment variable or "homepage" field to infer
    // "public path" at which the app is served.
    // webpack needs to know it to put the right <script> hrefs into HTML even in
    // single-page apps that may serve index.html for nested URLs like /todos/42.
    // We can't use a relative path in HTML because we don't want to load something
    // like /todos/42/static/js/bundle.7289d.js. We have to know the root.
    const publicUrlOrPath = getPublicUrlOrPath(
    process.env.NODE_ENV === 'development',
    require(resolveApp('package.json')).homepage,
    process.env.PUBLIC_URL
    );

    const moduleFileExtensions = [
    'web.mjs',
    'mjs',
    'web.js',
    'js',
    'web.ts',
    'ts',
    'web.tsx',
    'tsx',
    'json',
    'web.jsx',
    'jsx',
    ];

    // Resolve file paths in the same order as webpack
    const resolveModule = (resolveFn, filePath) => {
    const extension = moduleFileExtensions.find(extension =>
    fs.existsSync(resolveFn(`${filePath}.${extension}`))
    );

    if (extension) {
    return resolveFn(`${filePath}.${extension}`);
    }

    return resolveFn(`${filePath}.js`);
    };

    // config after eject: we're in ./config/
    module.exports = {
    dotenv: resolveApp('.env'),
    appPath: resolveApp('.'),
    appBuild: resolveApp('build'),
    appPublic: resolveApp('public'),
    appHtml: resolveApp('public/index.html'),
    appIndexJs: resolveModule(resolveApp, 'src/index'),
    appPackageJson: resolveApp('package.json'),
    appSrc: resolveApp('src'),
    appTsConfig: resolveApp('tsconfig.json'),
    appJsConfig: resolveApp('jsconfig.json'),
    yarnLockFile: resolveApp('yarn.lock'),
    testsSetup: resolveModule(resolveApp, 'src/setupTests'),
    proxySetup: resolveApp('src/setupProxy.js'),
    appNodeModules: resolveApp('node_modules'),
    publicUrlOrPath,
    };

    // @remove-on-eject-begin
    const resolveOwn = relativePath => path.resolve(__dirname, '..', relativePath);

    // config before eject: we're in ./node_modules/react-scripts/config/
    module.exports = {
    dotenv: resolveApp('.env'),
    appPath: resolveApp('.'),
    appBuild: resolveApp('build'),
    appPublic: resolveApp('public'),
    appHtml: resolveApp('public/index.html'),
    appIndexJs: resolveModule(resolveApp, 'src/index'),
    appPackageJson: resolveApp('package.json'),
    appSrc: resolveApp('src'),
    appTsConfig: resolveApp('tsconfig.json'),
    appJsConfig: resolveApp('jsconfig.json'),
    yarnLockFile: resolveApp('yarn.lock'),
    testsSetup: resolveModule(resolveApp, 'src/setupTests'),
    proxySetup: resolveApp('src/setupProxy.js'),
    appNodeModules: resolveApp('node_modules'),
    publicUrlOrPath,
    // These properties only exist before ejecting:
    ownPath: resolveOwn('.'),
    ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3
    appTypeDeclarations: resolveApp('src/react-app-env.d.ts'),
    ownTypeDeclarations: resolveOwn('lib/react-app.d.ts'),
    };

    const ownPackageJson = require('../package.json');
    const reactScriptsPath = resolveApp(`node_modules/${ownPackageJson.name}`);
    const reactScriptsLinked =
    fs.existsSync(reactScriptsPath) &&
    fs.lstatSync(reactScriptsPath).isSymbolicLink();

    // config before publish: we're in ./packages/react-scripts/config/
    if (
    !reactScriptsLinked &&
    __dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1
    ) {
    const templatePath = '../cra-template/template';
    module.exports = {
    dotenv: resolveOwn(`${templatePath}/.env`),
    appPath: resolveApp('.'),
    appBuild: resolveOwn('../../build'),
    appPublic: resolveOwn(`${templatePath}/public`),
    appHtml: resolveOwn(`${templatePath}/public/index.html`),
    appIndexJs: resolveModule(resolveOwn, `${templatePath}/src/index`),
    appPackageJson: resolveOwn('package.json'),
    appSrc: resolveOwn(`${templatePath}/src`),
    appTsConfig: resolveOwn(`${templatePath}/tsconfig.json`),
    appJsConfig: resolveOwn(`${templatePath}/jsconfig.json`),
    yarnLockFile: resolveOwn(`${templatePath}/yarn.lock`),
    testsSetup: resolveModule(resolveOwn, `${templatePath}/src/setupTests`),
    proxySetup: resolveOwn(`${templatePath}/src/setupProxy.js`),
    appNodeModules: resolveOwn('node_modules'),
    publicUrlOrPath,
    // These properties only exist before ejecting:
    ownPath: resolveOwn('.'),
    ownNodeModules: resolveOwn('node_modules'),
    appTypeDeclarations: resolveOwn(`${templatePath}/src/react-app-env.d.ts`),
    ownTypeDeclarations: resolveOwn('lib/react-app.d.ts'),
    };
    }
    // @remove-on-eject-end

    module.exports.moduleFileExtensions = moduleFileExtensions;
    719 changes: 719 additions & 0 deletions webpack.config.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,719 @@
    // @remove-on-eject-begin
    /**
    * Copyright (c) 2015-present, Facebook, Inc.
    *
    * This source code is licensed under the MIT license found in the
    * LICENSE file in the root directory of this source tree.
    */
    // @remove-on-eject-end
    'use strict';

    const fs = require('fs');
    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');
    // @remove-on-eject-begin
    const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier');
    // @remove-on-eject-end
    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 isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true';

    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';

    // Variable used for enabling profiling in Production
    // passed into alias object. Uses a flag if passed into the build command
    const isEnvProductionProfile =
    isEnvProduction && process.argv.includes('--profile');

    // We will provide `paths.publicUrlOrPath` 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.
    // Get environment variables to inject into our app.
    const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));

    // common function to get style loaders
    const getStyleLoaders = (cssOptions, preProcessor) => {
    const loaders = [
    isEnvDevelopment && require.resolve('style-loader'),
    isEnvProduction && {
    loader: MiniCssExtractPlugin.loader,
    // css is located in `static/css`, use '../../' to locate index.html folder
    // in production `paths.publicUrlOrPath` can be a relative path
    options: paths.publicUrlOrPath.startsWith('.')
    ? { publicPath: '../../' }
    : {},
    },
    {
    loader: require.resolve('css-loader'),
    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',
    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',
    // 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.
    // We inferred the "public path" (such as / or /my-project) from homepage.
    publicPath: paths.publicUrlOrPath,
    // 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}`,
    // this defaults to 'window', but by setting it to 'this' then
    // module chunks which are built will work in web workers as well.
    globalObject: 'this',
    },
    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 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,
    },
    // Added for profiling in devtools
    keep_classnames: isEnvProductionProfile,
    keep_fnames: isEnvProductionProfile,
    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,
    },
    },
    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,
    },
    cssProcessorPluginOptions: {
    preset: ['default', { minifyFontValues: { removeQuotes: 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',
    // Allows for better profiling with ReactDevTools
    ...(isEnvProductionProfile && {
    'react-dom$': 'react-dom/profiling',
    'scheduler/tracing': 'scheduler/tracing-profiling',
    }),
    ...(modules.webpackAliases || {}),
    },
    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,
    // @remove-on-eject-begin
    ignore: isExtendingEslintConfig,
    baseConfig: isExtendingEslintConfig
    ? undefined
    : {
    extends: [require.resolve('eslint-config-react-app')],
    },
    useEslintrc: isExtendingEslintConfig,
    // @remove-on-eject-end
    },
    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'
    ),
    // @remove-on-eject-begin
    babelrc: false,
    configFile: false,
    presets: [require.resolve('babel-preset-react-app')],
    // Make sure we have a unique cache identifier, erring on the
    // side of caution.
    // We remove this when the user ejects because the default
    // is sane and uses Babel options. Instead of options, we use
    // the react-scripts and babel-preset-react-app versions.
    cacheIdentifier: getCacheIdentifier(
    isEnvProduction
    ? 'production'
    : isEnvDevelopment && 'development',
    [
    'babel-plugin-named-asset-import',
    'babel-preset-react-app',
    'react-dev-utils',
    'react-scripts',
    ]
    ),
    // @remove-on-eject-end
    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,
    // @remove-on-eject-begin
    cacheIdentifier: getCacheIdentifier(
    isEnvProduction
    ? 'production'
    : isEnvDevelopment && 'development',
    [
    'babel-plugin-named-asset-import',
    'babel-preset-react-app',
    'react-dev-utils',
    'react-scripts',
    ]
    ),
    // @remove-on-eject-end
    // Babel sourcemaps are needed for debugging into node_modules
    // code. Without the options below, debuggers like VSCode
    // show incorrect code and set breakpoints on the wrong lines.
    sourceMaps: shouldUseSourceMap,
    inputSourceMap: shouldUseSourceMap,
    },
    },
    // "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: {
    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: 3,
    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: 3,
    sourceMap: isEnvProduction && shouldUseSourceMap,
    modules: {
    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="icon" href="%PUBLIC_URL%/favicon.ico">
    // It will be an empty string unless you specify "homepage"
    // in `package.json`, in which case it will be the pathname of that URL.
    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 an asset manifest file with the following content:
    // - "files" key: Mapping of all asset filenames to their corresponding
    // output file so that tools can pick it up without having to parse
    // `index.html`
    // - "entrypoints" key: Array of files which are included in `index.html`,
    // can be used to reconstruct the HTML if necessary
    new ManifestPlugin({
    fileName: 'asset-manifest.json',
    publicPath: paths.publicUrlOrPath,
    generate: (seed, files, entrypoints) => {
    const manifestFiles = files.reduce((manifest, file) => {
    manifest[file.name] = file.path;
    return manifest;
    }, seed);
    const entrypointFiles = entrypoints.main.filter(
    fileName => !fileName.endsWith('.map')
    );

    return {
    files: manifestFiles,
    entrypoints: entrypointFiles,
    };
    },
    }),
    // 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$/),
    // Generate a service worker script that will precache, and keep up to date,
    // the HTML & assets that are part of the webpack build.
    isEnvProduction &&
    new WorkboxWebpackPlugin.GenerateSW({
    clientsClaim: true,
    exclude: [/\.map$/, /asset-manifest\.json$/],
    importWorkboxFrom: 'cdn',
    navigateFallback: paths.publicUrlOrPath + 'index.html',
    navigateFallbackBlacklist: [
    // Exclude URLs starting with /_, as they're likely an API call
    new RegExp('^/_'),
    // Exclude any URLs whose last part seems to be a file extension
    // as they're likely a resource and not a SPA route.
    // URLs containing a "?" character won't be blacklisted as they're likely
    // a route with query params (e.g. auth callbacks).
    new RegExp('/[^/?]+\\.[^/]+$'),
    ],
    }),
    // 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,
    }),
    ].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,
    };
    };