A practical guide to webpack build automation

Click here to view the project source code address

my personal blog

npm VS Yarn

In this project, we use Yarn to manage the project's tripartite dependencies, but don't worry, Yarn and NPM do not conflict, nor do they replace NPM. The usage is basically the same, and you only need to understand the following points.

Third-party library version management

Both npm and Yarn use package.jsonto track project dependencies, version numbers are not always accurate, because you can define a range of version numbers, different update ranges of npm may cause package.jsondifferent versions of packages to be installed on machines with the same files, which may lead to some discrepancies exceptions and conflicts.

Does npm have a solution? In npm, you can use npm shrinkwrapto generate a version lock file npm-shrinkwrap.json, npm installwhich will be read package.jsonbefore reading , but when the package version is updated, the version lock file will not be updated automatically, we have to manually execute the npm shrinkwrapcommand again to update it.

So what are the advantages of Yarn? Every time an installation library package is added or updated, Yarn will create (or update) yarn.locka file, which ensures that all machines have the same version of the package installed, while package.jsonsupporting the allowable version range defined in . The difference with npm is that Yarn will always update automatically yarn.lock, while npm needs to be updated manually.

concurrent installation

npm usually installs dependencies one by one in sequence, while Yarn supports parallel loading and installation of multiple third-party library packages, all of which are faster and more efficient.

Offline cache

When using Yarn to manage the package, the third-party library package is stored on the local disk, and the next installation will directly use the local file instead of downloading it again, which also makes the installation speed better than npm on the other hand.

In short, Yarn and npm use almost the same way, but its version management is more convenient, the installation speed is faster, and it has more advantages, but in fact all its three-party library package load addresses and npm are unified.

Webpack

We use the Webpack packaging tool as an automated construction tool for the project, and manage JavaScript, CSS, images and other resources as JavaScript modules (using the Webpack loader to process the conversion) for unified management. About Webpack bloggers have summarized two articles before, you can refer to:

  1. Webpack builds a SPA application development environment
  2. Webpack modularly manages resources such as CSS and images

With the foreshadowing of the previous article, this article does not intend to introduce the working principle and specific configuration of Webpack, but plans to think about how to better organize Webpack, how to use Webpack to report project development and packaging efficiency from the perspective of project development and testing, and packaging.

Webpack configuration file

webpack.config.jsFirst we create a configuration file in the root directory :

module.exports = function () {
  let env
  let _DEV_ = true // 开发环境
  let _PROD_ = false // 生产环境
  
  switch (process.env.NODE_ENV) {
    case 'dev':
      env = 'dev'
      _DEV_ = true
      _PROD_ = false
      break
    case 'production':
      env = 'prod'
      _DEV_ = false
      _PROD_ = true
      break
    default:
      env = 'dev'
      _DEV_ = true
      _PROD_ = false
  }
  // 根据环境参数动态决定引入对应配置文件
  return require(`./webpack/${env}.conf.js`)({
    ROOTPATH: __dirname,
    _DEV_,
    _PROD_
  })
}

process.env.NODE_ENVDynamically decide to load the corresponding configuration file according to the environment parameters:

  1. dev: Load webpack/env.conf.jsconfiguration file;
  2. prod: Load webpack/prod.conf.jsconfiguration file;

We created a directory under the project root directory webpack, which created three configuration files:

  1. base.conf.js: Basic configuration file, the configuration required in both development and production environments;
  2. dev.conf.js: Development environment configuration file;
  3. prod.conf.js: Production environment packaging configuration file;

Development environment configuration

The development environment configuration file defines some build configurations for development, and then introduces the basic configuration file, uses webpack-mergethe third-party library, merges the development environment configuration into the basic configuration object, and then returns to the development environment to package and build the configuration object as a parameter for Webpack packaging and construction:

const webpackMerge = require('webpack-merge')
const PUBLICPATH = '/assets/'
const PORT = '9090'
let options = { /* ... */ }
module.exports = function (args) {
  options.ROOTPATH = args.ROOTPATH
  options.env = args.env
  return webpackMerge(require('./base.conf')(options), {
    devtool: 'source-map',
    devServer: {
      contentBase: path.join(args.ROOTPATH, './src'),
      historyApiFallback: true,
      inline: true,
      hot: true,
      port: PORT,
      proxy: {
        '*': `http://localhost:${PORT}/${PUBLICPATH}/`
      }
    },
    plugins: []
  })
}

Production environment configuration

The production environment configuration file defines the build configuration used in the production environment, and then also introduces the basic configuration file, uses webpack-mergethe third-party library, merges the production environment configuration into the basic configuration, and then returns the configuration object as a parameter for Webpack packaging and construction:

let options = { /* ... */}
module.exports = function (args) {
  options.ROOTPATH = args.ROOTPATH
  options.env = args.env
  return webpackMerge(require('./base.conf')(options), {
    plugins: [
      new webpack.DefinePlugin({
        'process.env': 'production'
      }),
      // 生成独立css文件
      new ExtractTextPlugin({
        filename: 'css/[name].css'
      }),
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false
        }
      })
    ]
  })
}

instruction

Then it is to configure executable instructions for different environments. We use the npm scriptsmethod to configure the executable instructions in the package.jsonfile:

{
  "scripts": {
    "start": "cross-env NODE_ENV=dev webpack-dev-server",
    "build": "cross-env NODE_ENV=production webpack"
  }
}
  1. start: Run the command in the development environment, use the third- cross-envparty library to set process.env.NODE_ENVas dev, and open the webpack open server locally, which is convenient for opening;
  2. build: The production environment runs the command, using the third- cross-envparty library to set process.env.NODE_ENVas production, will package the output code and resource files;

Finally, execute the yarn startand yarn buildinstructions separately to execute the development and production builds and packages respectively.

Babel

A general-purpose compiler with customizable configuration needs to explicitly specify what babel is expected to do, by installing **plugins (plugins) or presets (presets, that is, a set of plug-ins)** to instruct Babel to do things.

configuration file

First, you need to create a configuration file, that is, create a .babelrcfile . Then enter the following to start:

{
  "presets": [],
  "plugins": []
}

This configuration file can then be extended to specify the functionality of Babel in this project.

babel-preset-es2015

We expect to use the newer ES6 version syntax in the project, but since there are still many JavaScript environments that are not very compatible with ES6, Babel is required to compile ES6 code into ES5 syntax code to ensure the scope of application.

Execute the following command to install the "es2015" Babel preset:

yarn add --dev babel-preset-es2015

Modify the .babelrcconfiguration file:

{
  "presets": [
    "es2015"
  ],
  "plugins": []
}

babel-preset-stage-num

In addition, there are still some proposals for JavaScript, which are in progress, and may become part of the standard in the near future. Therefore, these drafts are currently proposed, the content is updated until it finally becomes a standard, and the process of adding into the standard library is divided into 5 (0-4) stage. According to the status and content of the proposal, it is updated in various stages (stage 0 to stage 3), and finally in stage 4, the proposal is officially accepted by the standard. Of course, the proposal that is not accepted will not enter stage 4.

Here are the pack presets in 4 different stages:

  • babel-preset-stage-0
  • babel-preset-stage-1
  • babel-preset-stage-2
  • babel-preset-stage-3

Note: The stage-4 preset does not exist, it is actually the es2015preset .

Each of the above presets contains a subsequent post-stage preset, and may also contain additional features. For example, babel-preset-stage-0contains babel-preset-stage-1, babel-preset-stage-2, babel-preset-stage-3, babel-preset-stage-1and contains babel-preset-stage-2, and so babel-preset-stage-3on.

Click here to view the detailed feature content document about each stage preset

We chose the presets that support the most comprehensive features:

yarn add --dev babel-preset-stage-0

In the .babelrcconfig file add:

{
  "presets": [
    "es2015",
    "stage-0"
  ],
  "plugins": []
}

babel-preset-react

Our project expects to use React to develop, so we need to expand to support React/JSX syntax and install the presets:

yarn add --dev babel-preset-react

.babelrcIn the configuration file add:

{
  "presets": [
    "es2015",
    "stage-0",
    "react"
  ],
  "plugins": []
}

babel-polyfill

So far, using Babel, our project can support almost all ES6 and ES7 syntaxes, but it is powerless for the new JavaScript API, such as Symbolthis new API, which cannot be achieved through syntax conversion, so we need another way to solve.

Polyfill is proposed in the industry to add extra code to make the current operating environment support native APIs that do not exist, and to expand the scope of use of APIs that are still in the advancement stage.

yarn add babel-polyfill

There is no need to add --devparameters here.

Then import it in the file entry:

import "babel-polyfill";

babel-runtime

As mentioned above, Babel supports us to develop code with ES6 and other updated grammars by transforming the grammar. At this time, Babel will inject auxiliary code into the header of each processed file, which will generate a lot of redundant and repetitive content, resulting in code The volume has skyrocketed, so we need to extract these auxiliary codes into a unified environment. Babel provides the runtime environment.

To implement the Babel runtime environment, you need to install babel-plugin-transform-runtimeand babel-runtime:

yarn add --dev babel-plugin-transform-runtime babel-runtime

Then update .babelrc:

{
  "plugins": [
    "transform-runtime",
  ]
}

On-demand loading (babel-plugin-import)

Many times, we do not need self-made UI for business development, and choose some open source component libraries to quickly develop and implement products, such as antd, weui, material-ui, etc. We can choose to directly load all modules of the third-party library in advance, but many times we hope It can realize on-demand loading and reduce the volume of the initial code package. At this time, we can declare in the babel configuration file to load the third-party library on demand. Of course, we must first install the plug-in babel-plugin-import:

yarn add --dev babel-plugin-import

Then .babelrcadd the configuration in the configuration file:

{
  "plugins": [
    "import",
    {
      "style": "../styles", // 加载样式解析方式,(值为true时,可能是less/Sass),此处值设为相对libraryName具体模块请求路径值
      "libraryDirectory": "", // 加载包的目录,(默认是lib,即node_modules/lib/)
      "libraryName": "material-ui" // 加载三方组件库名,当然另外需要安装该三方库
    }
  ]
}

At this point, the webapck loader cannot be added when processing CSS exclude: /node_modules/.

other plugins

We can also customize the installation of plugins according to the actual needs and hobbies of the project. For more information, see the official plugin documentation .

babel-pliugin-transform-s2015-classesA plugin extension is recommended here to implement the extendsinheritance feature of JavaScript built-in class objects, refer to the document ES2015 classes transform .

yarn add --dev babel-plugin-transform-es2015-classes

.babelrcAdd plugins content to the file:

{
  "plugins": [
    "transform-runtime",
    "transform-es2015-classes",
    [
      "import",
      {
        "style": "css",
        "libraryDirectory": "",
        "libraryName": "material-ui"
      }
    ]
  ]
}

Grammar Check (Eslint)

In order to ensure code quality, it is very important to unify the code style, and it is obviously not satisfactory to rely on the oral agreement of the team. Therefore, it is usually necessary to perform code syntax detection at the automated construction level. There are many syntax detection tools such as jslint and eslint, which are currently used The highest rate is eslint, so our project also introduces eslint, first install the dependencies:

yarn add --dev eslint

For more details, refer to the configuration documentation , the main ones are briefly described below.

configuration file

Then create an eslint configuration file in the project root directory .eslintrc, the content is an object:

{}

Parser (parser)

In addition, ESLint uses Espree as its parser by default, you can specify a different parser in the configuration file, such as babel-eslint, esprima, etc. Our project uses babel-eslint:

yarn add --dev babel-eslint

parserAdd the properties in the configuration file :

{
  "parser": "babel-eslint"
}

eslint-plugin-babel

Eslint also supports optional installation of plug-ins to expand eslint. For example eslint-plugin-babel, this plug-in and babel-eslintcollaboration make eslint work better with babel. For more information, please refer to the reference document .

yarn add --dev eslint-plugin-babel

Add the declaration to the configuration file:

{
  "plugins": [
    "babel"
  ],
}

aslant-plugin-react

By default, eslint detects JavaScript language syntax. For frameworks such as React/JSX that contain their own custom syntax and syntactic sugar, additional extension and installation of plugins are required to be used in combination with eslint. Therefore, using eslint to detect React-specific syntax requires the installation of eslint-plugin-reactplugins . :

yarn add --dev eslint-plugin-react

Add configuration file:

{
  "plugins": [
    "babel",
    "react"
  ]
}

Extends

In addition to custom grammar checking rules, we can use the integrated extension package provided by Eslint to use shared grammar detection configuration objects, such as eslint-config-standardand eslint-config-standard-react:

yarn add --dev eslint-config-standard eslint-config-standard-react eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node eslint-plugin-react

Note: The eslint-plugin-react mentioned in the previous section is included here to support the eslint-config-standard-react configuration package.

Then .eslintrcadd the extension to the configuration file:

{
  "extends": [
    "standard",
    "standard-react"
  ]
}

If you don't want to use such integrated syntax detection rules, you can remove the content in the configuration file and remove the dependencies:

yarn remove eslint-config-standard eslint-config-standard-react eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node eslint-plugin-react

Grammar rules (rules)

To add grammar rules, just declare them in the rulesproperties object, like:

{
  "rules": {
    "strict": 0,
    "semi": 2, // 强制语句末尾添加符号,否则报错
    "quotes": [
      1,
      "single"
    ],
  }
}

Rule structure

When declaring grammar detection rules, you need to set the rule ID to one of the following values:

  • "off"or 0- close the rule
  • "warn"or 1- turn on the rule, use a warning-level error: warn(does not cause the program to exit)
  • "error"or 2- turn on the rule, use the error level error: error(when triggered, the program will exit)
{
  "rules": {
  	eqeqeq: 0, // or "off"
  	curly: 2 // or "error"
  }
}

Some rules may also have additional configuration options, which can be specified using an array, such as:

{
  "rules": {
    "eqeqeq": "off",
    "curly": "error",
    "quotes": ["warn", "single"] // 开启使用单引号,若使用双引号将发出警告
  }
}

instruction

To perform syntax detection, you only need to execute ./node_modules/.bin/eslint src(the project installs eslint locally, not globally, you need to specify the command script path), it will traverse and check srcthe syntax of all source files in the directory and output the result, of course, we finally need to put the instruction according to npm scriptsCanonical insert package.jsonfile:

{
  "scripts": {
    "lint": "eslint --cache --fix src"
  }
}

When executing directives with npm scripts, whether the project is installed locally or globally, the directive script path can be omitted, as npm will automatically match the available paths.

Documentation

Documents can help other developers to quickly understand the content and progress of the entire project, and also help to find the content and trace the source when bugs are fixed. Therefore, documents are necessary, so I found JSdoc and documentation through research. js helps automate the production of API documentation.

documentation

Like JSdoc , documentation also automatically builds project documentation based on code comments, provided that our code comments must follow its specification guidelines. For details, refer to the JSdoc documentation .

We first install documentation.js :

yarn add --dev documentation

instruction

Then the command can be executed:

./node_modules/.bin/documentation build src/app.js -f md > API.md

You will find that the API.md file is output in the root directory.

npm scriptsWe configure the execution script in the package.json file :

"scripts": {
  "doc": "./node_modules/.bin/documentation build src/app.js -f md > API.md"
}

When the documentation is installed locally in the project, the path needs to be specified when executing the command directly on the command line terminal ./node_modules/.bin/documentation. If it is installed globally, only the command can be used directly documentation. To execute the steps in package.json, you can directly abbreviate it, and npm will automatically match it for us.

Click here to view the project source code address

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324387477&siteId=291194637