Some common custom configurations of create react app

Time:2021-3-11

Create react app is an officially supported method for creating react single page applications. It provides a modern build setup with zero configuration.
Although out of the box, we still need to make some modifications in the development. Here is a summary of some common configurations.

Error in yarn installation dependent package

Run in project directoryyarn,The error is as follows

yarn install v1.7.0
[1/4] Resolving packages...
[2/4] Fetching packages...
info There appears to be trouble with your network connection. Retrying...
error An unexpected error occurred: "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz: connect ETIMEDOUT 104.16.21.35:443".
info If you think this is a bug, please open a bug report with the information provided in "F:\\await\\react-rabc\\yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

The prompt is very obvious, the network connection time-out, we change the source address to go

NPM set to Taobao source

npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist

Yarn is set as Taobao source

yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global

If sass is used in the project, you need to download node sass. The download of this dependent package is quite slow. You can set the source address separately

yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass
npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass

Delete lastnode_modules, just download it again

Error in ie10, map not defined

yarn add react-app-polyfill

Import the first line of the entry file

// This must be the first line in src/index.js
import 'react-app-polyfill/ie9'

react-app-polyfill

Webpack add alias

config/modules.jsIn filewebpackAliasesOfaliasIs to resolve thetsconfig.jsonperhapsjsconfig.jsonTo return, it’s a bit complicated

Can be directly in thewebpack.config.jsOfresolve.aliasAdd a new field at the end of the field

resolve: {
  // ...
  alias: {
    // ...
    '@': path.resolve(__dirname, '../src')
  }
}

Solve cross domain, reverse proxy configuration

1. Installation dependency

yarn add http-proxy-middleware

2. InsrcNew under directorysetupProxy.jsfile

const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: ' http://localhost : 6000 '// request interface address
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      }
    })
  )
}

Project main file path configuration

It includes project entry file, static directory, project construction output directory and configurationproxyFile

stayconfig/paths.jsFile configuration, pick out a few of the most commonly used

module.exports = {
  Dotenv: resolveapp ('. Env') // project environment variable file
  Appbuild: resolveapp ('dist ') // project build output directory, default build
  Apppublic: resolveapp ('public ') // static directory
  appHtml: resolveApp('public/index.html'), // index.html
  Appindexjs: resolvemodule (resolveapp, 'Src / index') // project entry file
  proxySetup: resolveApp('src/ setupProxy.js '// configure proxy file
}

Turn off auto open browser configuration

stayscripts/start.jsFile, comment outopenBrowser(urls.localUrlForBrowser)That’s it,
Or use environment variablesBROWSER

{
  "script": {
    "start": "cross-env BROWSER=none node scripts/start.js"
  }
}

Modify webpackoutput.publicPath

If the project is not deployed in the static server root directory, it will be used directly in thepackage.jsonMedium configurationhomepagefield

{
  "homepage": "/e-admin/"
}

Or use environment variablesPUBLIC_URL

{
  "script": {
    "build": "cross-env PUBLIC_URL=/e-admin/ node scripts/build.js"
  }
}

modifypublicPathAfter that, if the route useshistoryMode, you need to do other configuration

  • react-router-domOfRouterassemblybasenameattribute

    <BrowserRouter
      basename="/e-admin"
    >
      <App />
    </BrowserRouter>

    If usedhistory

    const history = createBrowserHistory({
      basename: '/e-admin'
    })
  • Static server (using nginx) for redirection configuration ($try)_ files)

    #Because browserhistory is used in the front end, the route fallback to index.html
    location /e-admin {
      try_files $uri $uri/ /e-admin/index.html;
    }

Production environment shutdown

Generally, when deploying to the production environment, sourcemap will be closed to avoid too large a package file
seewebpack.config.jsYou can see the following code:

const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

Can be used on the command lineGENERATE_SOURCEMAPThis environment variable

{
  "script": {
    "build": "cross-env GENERATE_SOURCEMAP=false node scripts/build.js"
  }
}

Eslint configuration

Can be directly in thepackage.jsonIneslintConfigField configuration.

Create a new file in the root directory.eslint.js(or.eslintrc)Configuration file, and then set it on the command lineEXTEND_ESLINT

{
  "script": {
    "start": "cross-env EXTEND_ESLINT=true node scripts/start.js"
  }
}

Because each platform sets environment variables in different ways, we usecross-envTo smooth out the difference

Decorators configuration

There will be many high-level components and Redux in the developmentconnectTo wrap components, useDecoratorsThe writing will be more intuitive

  • Install firstbabelplug-in unit
yarn add @babel/plugin-proposal-decorators
  • babelConfiguration, inpluginsAdd in
{
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ]
  ]
}
  • After completing the above configuration, the compiler will not report an error. The code can run normally, but the editor (this is using vscode) reports an error. We need to do additional configuration

    • Create a new file in the root directoryjsconfig.jsonfile

      {
        "compilerOptions": {
          "experimentalDecorators": true
        }
      }
    • openVSCodeOfsetting.jsonFile, add the following properties

      "javascript.implicitProjectConfig.experimentalDecorators": true

The Babel configuration of create react app is in the package.json Can be placed in the root directory (. Babelrc or babel.config.js )

Differentiate the environment

Development environment, test environment, pre production environment, production environment, and many configuration items (such as interface address) are different. At this time, we need to determine the configuration items according to the environment.
Create react app default supportdevelopmenttestproductionIt’s heretestIt is used to do code testing, not to build a test environment. We need a variety of packaging environments.
Here we first distinguish three environments:

  • Development environment dev
  • Test environment alpha
  • Production environment prod

1. Then create three new files in the root directory.env.env.alpha.env.prodThe contents of the document are as follows:

// .env
NODE_ENV=development
REACT_APP_MODE=dev

// .env.alpha
NODE_ENV=production
REACT_APP_MODE=alpha

// .env.prod
NODE_ENV=production
REACT_APP_MODE=prod

2. Modificationpackage.jsonCommand script for

{
  "script": {
    "build:alpha": "cross-env MODE_ENV=alpha node scripts/build.js",
    "build:prod": "cross-env MODE_ENV=prod node scripts/build.js"
  }
}

3. Modificationconfig/env.jsfile

// const NODE_ENV = process.env.NODE_ENV;
const NODE_ENV = process.env.MODE_ENV || process.env.NODE_ENV;

4. Then it can be used in the business codeprocess.env.REACT_APP_MODETo distinguish the environment

// axios.baseURL
const baseURL = {
  dev: 'http://localhost:3000',
  alpha: 'http://alpha.xxx.com',
  prod: 'http://xxx.com'
}[process.env.REACT_APP_MODE]

It is a common method to distinguish different environments according to different commands.
According tonpmIn commandREACT_APP_MODETo decide which one to use.env.[xxx]Environment variables, injected into the compiled code.

be careful:

  • It should be noted that env.js Node in the file_ Env replaced with mode_ Env, resulting in the original node_ Env is missing, which should be added in. Env. [XXX] file
  • The environment variable of. Env. [XXX] is set as react_ APP_ Start with XXX

Compile progress bar configuration

  • Installation dependency

    yarn add webpackbar
  • modifywebpack.config.jsfile

    const WebpackBar = require('webpackbar')
    plugins: [
      // ...
      new webpack.ProgressPlugin(),
      new WebpackBar()
    ]

webpack.ProgressPlugin()yeswebpackBuilt in plug-ins, webpack.ProgressPlugin ,WebpackBarUsed to display compilation time

Package to start gzip compression

  • Installation dependency

    yarn add compression-webpack-plugin
  • modifywebpack.config.jsfile

    const CompressionPlugin = require('compression-webpack-plugin')
    const isGzip = process.env.GENERATE_GZIP_FILE === 'true'
    plugins: [
      // ...
      isEnvProduction && isGzip && new CompressionPlugin({
        File name: '[path]. GZ [query]', // the asset property of the new version has been changed to file name
        algorithm: 'gzip',
        test: /\.js$|\.css$/,
        threshold: 10240,
        minRatio: 0.8
      })
    ]
  • By setting environment variablesGENERATE_GZIP_FILE=trueTo enablegzipcompress

Please make sure that the gzip configuration item is enabled on the static server and that nginx configures gzip_ Static on; option

The following is not turned ongzipAnd ongzipThe results of the experiment are as follows

  • Gzip not started

    Some common custom configurations of create react app

  • Open gzip

    Some common custom configurations of create react app

Generation report.html Visual packaging analysis

  • Installation dependency

    yarn add webpack-bundle-analyzer
  • modifywebpack.config.jsfile

    const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
    const isBundleAnalyzer = process.env.GENERATE_BUNDLE_ANALYZER_REPORT === 'true'
    plugins: [
      // ...
      isEnvProduction && isBundleAnalyzer && new BundleAnalyzerPlugin()
    ]
  • By setting environment variablesGENERATE_BUNDLE_ANALYZER_REPORT=trueTo generatereport

Introducing antd

antdJS code of ES module supports tree Shading Based on ES modules by default, that is, it is introduced on demand, but there are some differences in the introduction of styles

1. Direct import, style directly with the compiledantd.css

import { Button } from 'antd'
import 'antd/dist/antd.css'

function App() {
  return (
    < button type = "primary" > button < / button >
  )
}

It’s simple and crude, but it can’t modify some global colors uniformly

2. Introductionless

  • Installation dependency

    yarn add less less-loader
  • wepack.config.jsConfiguration, defaultrulesAlready includedcssandsassFirst, find the following regular

    // style files regexes
    const cssRegex = /\.css$/;
    const cssModuleRegex = /\.module\.css$/;
    const sassRegex = /\.(scss|sass)$/;
    const sassModuleRegex = /\.module\.(scss|sass)$/;
    //Plus regular matching of less files
    const lessRegex = /\.less$/;
    const lessModuleRegex = /\.module\.less$/;

    And then addloaderConfiguration, insass-loaderAddless-loaderConfiguration of

    // 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'
      ),
    },
    //Add the less loader configuration below
    {
      test: lessRegex,
      exclude: lessModuleRegex,
      use: getStyleLoaders(
        {
          importLoaders: 2,
          sourceMap: isEnvProduction && shouldUseSourceMap,
        },
        'less-loader'
      ),
      sideEffects: true,
    },
    // Adds support for CSS Modules, but using less
    // using the extension .module.less
    {
      test: lessModuleRegex,
      use: getStyleLoaders(
        {
          importLoaders: 2,
          sourceMap: isEnvProduction && shouldUseSourceMap,
          modules: {
              getLocalIdent: getCSSModuleLocalIdent
          }
        },
        'less-loader'
      ),
    },

    findgetStyleLoadersMethods: the following modifications were made

    //To replace the code in if (preprocessor) {} is actually to judge whether it is a 'less loader' and generate options for less
    if (preProcessor) {
      let preProcessorRule = {
        loader: require.resolve(preProcessor),
        options: {
          sourceMap: true
        }
      }
      if (preProcessor === 'less-loader') {
        preProcessorRule = {
          loader: require.resolve(preProcessor),
          options: {
            sourceMap: true,
            Lessoptions: {// if you use [email protected] You need to remove the lessoptions level
              javascriptEnabled: true,
              modifyVars: {
                'primary color': 'FFF' // global dominant color
                'link color': 'FFF' // link color
              }
            }
          }
        }
      }
      loaders.push(
        {
          loader: require.resolve('resolve-url-loader'),
          options: {
            sourceMap: isEnvProduction && shouldUseSourceMap,
          },
        },
        preProcessorRule
      );
    }
  • takeimport 'antd/dist/antd.css'change intoimport 'antd/dist/antd.less'

    After the above configuration, you can modify it directlylessVariable to modify the global color, spacing, etc., all variables

    Of course, if thelessVariables are troublesome. You can create a separate variable directlylessFile to override the default variable

    @import '~antd/lib/style/themes/default.less';
    @import '~antd/dist/antd.less';
    @import 'customer-theme- file.less '; // used to override the default variable

    However, this method will load all the styles of components, and can’t load them on demand

3. Load on demand

  • Installation dependency

    yarn add babel-plugin-import
  • Babel configuration

    "plugins": [
      [
        "babel-plugin-import",
        {
          "libraryName": "antd",
          "libraryDirectory": "es",
          "style": true
        }
      ]
    ]
  • Removeimport 'antd/dist/antd.less'The introduction of components will now be accompanied by the introduction of the corresponding component style

Global less variable

If used in the projectlessperhapssass, then there may be some global variables that need to be used in the style file. If you do not make any configuration, you need to import the variable file into the style file that uses the variable@import './var.less'

We need to usesass-resources-loaderInject variables and blending methods into the global, so that you can use variables directly in each style file.

Specific configuration:
1. ModificationgetStyleLoadersmethod

const getStyleLoaders = (cssOptions, preProcessor, restLoaders) => {
  //Change const to let, and then re assign the value according to the third parameter of the function
  let loaders = [
    // ...
  ]
  // ...
  if (Array.isArray(restLoaders) && restLoaders.length) {
    loaders = loaders.concat(restLoaders)
  }
  return loaders
}

2. Modificationless-loaderto configure

{
  test: lessRegex,
  exclude: lessModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 2,
      sourceMap: isEnvProduction && shouldUseSourceMap,
    },
    'less-loader',
    //Add a third parameter
    [
      {
        loader: 'sass-resources-loader',
        options: {
          resources: [
            path.resolve(__dirname, '../src/assets/styles/var.less')
          ]
        }
      }
    ]
  ),
  sideEffects: true,
},
{
  test: lessModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 2,
      sourceMap: isEnvProduction && shouldUseSourceMap,
      modules: {
        getLocalIdent: getCSSModuleLocalIdent,
      }
    },
    'less-loader',
    //Add a third parameter
    [
      {
        loader: 'sass-resources-loader',
        options: {
          resources: [
            path.resolve(__dirname, '../src/assets/styles/var.less')
          ]
        }
      }
    ]
  ),
}

Used herelessConfiguration, variable file pathsrc/assets/styles/var.lessAfter configuration, it is unnecessary to importvar.lessYou can use variables in each style file.

Project address

Reference link:

  • Create react app official document
  • Create react app Chinese document
  • Ant Design