1. Development environment dependency

2. Initialize the project and associate the remote Git repository

  • Create the project directory locally

After entering the directory, NPM initializes the project

yarn init -y
Copy the code
  • Initialize the Git repository

The following commands

Git remote add origin <url>Copy the code

Note 1: The following error occurs when a project is associated with a remote warehouse

fatal: not a git repository (or any of the parent directories): .git
Copy the code

The following figure

Git init () : git init (); git init () : git init ();

Note 2: The following error is reported when pushing the project to the remote repository while completing project association with the remote repository

error: src refspec master does not match any
Copy the code

The diagram below:

The error is caused by the fact that there are no files in the directory and an empty directory cannot be submitted.

My local project does not have Add and COMMIT. After commit, I can push the local repository project to the associated remote repository

But if it’s an empty directory and you want to push the project to a remote warehouse, here’s the solution

Touch READMEgitadd READMEgit commit -m 'git push origin masterCopy the code

3. The webpack configuration

3.1 Basic Configuration Settings

  • Create folders under the project rootsrcCreate file insideindex.jsAs an entry file for WebPack

The code is as follows:

import React from 'react';
import reactDom from 'react-dom';

const App = () => (
  <div>
    test page
  </div>
);
reactDom.render(<App/>, document.getElementById('root'));
Copy the code

Note: after creating the JS file, the format error will be displayed, as shown below

Solutions:

Menu bar File=> Settings => Languages & Frameworks => JavaScript => JavaScript language version

Set the JavaScript version to React JSX.

  • Creating a template File/public/index.htmlThe webPack packed file will be added to this file

The following code

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, Initial - scale = 1.0 "> < title > Document < / title > < / head > < body > < div id =" root "> < / div > < / body > < / HTML >Copy the code
  • createwebpackConfiguration files in the development environment/webpack/webpack.config.dev.js

The code is as follows:

const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'development', entry: path.resolve(__dirname, '.. /src/index.js'), output: { path: path.resolve(__dirname, '.. /build'), filename: 'js/[name].[hash].bundle.js', }, module: { rules: [ { test: /\.(mjs|js|jsx)$/, exclude: /node_modules/, use: ['babel-loader'], } ], }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, '../public/index.html'), }) ], resolve: { extensions: ['.mjs', '.js', '.jsx'], }, };Copy the code
  • createwebpackConfiguration files in the production environment/webpack/webpack.config.prod.js

The code is as follows:

const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'production', entry: path.resolve(__dirname, '.. /src/index.js'), output: { path: path.resolve(__dirname, '.. /build'), filename: 'js/[name].[hash].bundle.js', }, module: { rules: [ { test: /\.(mjs|js|jsx)$/, exclude: /node_modules/, use: ['babel-loader'], } ], }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, '../public/index.html'), }) ], resolve: { extensions: ['.mjs', '.js', '.jsx'], }, };Copy the code

3.2 Installing the basic plug-in package

1. Dependency packages and plug-ins related to WebPack

  • Webpack: Basic WebPack package

  • Webpack-cli: Webpack CLI tool package

  • html-webpack-plugin: Webpack plugin, used to add packaged files to the specified HTML, that is, can generate a separate HTML file, but also the corresponding script and style are automatically inserted into the appropriate location, no manual introduction, but also supports the function of hashing, to prevent the browser cache when updating

  • Webpack-dev-server: a webpack development environment tool that provides web services for Webpack projects, allowing us to access compiled files in the browser via HTTP

  • Babel-loader: weboack loader, used to compile packaged JS files

  • @babel/core: Babel dependency package, parsing JS code into AST

  • @babel/preset-react: presets related to webpack React

  • @babel/preset-env: Weboack react related presets so that the latest JS related syntax can be used

    yarn add webpack webpack-cli html-webpack-plugin webpack-dev-server babel-loader @babel/core @babel/preset-react @babel/preset-env -D

  • Create the Babel configuration file.babelrc

The code is as follows:

{
  "presets": [
    "@babel/preset-react",
    "@babel/preset-env"
  ]
}
Copy the code

2. React Dependency packages and packages

  • react
  • react-dom

The installation command is as follows:

yarn add react react-dom -S
Copy the code

3. Modify the script command of package.json

  • Modify thepackage.json: Add NPM script, dev startup command, build production environment package command

As follows:

"scripts": {
    "dev": "webpack-dev-server --config ./webpack/webpack.config.dev.js --open",
    "build": "webpack --config ./webpack/webpack.config.prod.js"
}
Copy the code

3.3 HTmL-webpack-plugin Easy to use

We can specify an HTML template

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html'),
    })
  ]
};
Copy the code

2. Title use, we can specify template title

The code inside the specified HTML template is as follows

<title><%= htmlWebpackPlugin.options.title %></title>
Copy the code

The code for the webpack configuration file is as follows

const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); Module. exports = {plugins: [new HtmlWebpackPlugin({title: 'test ', template: path.resolve(__dirname, '../public/index.html'), }) ] };Copy the code

3. **filename**

const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); Module. exports = {plugins: [new HtmlWebpackPlugin({title: 'test ', template: Path.resolve (__dirname, '../public/index.html'), filename: 'index.html' // package filename})]};Copy the code

4. Flexible use of html-webpack-plugin config

Sometimes, we not only for their own use of scaffolding, may also provide for the use of other business, the configurability of HTML files may be important, such as: your company have a special department to provide M pages of public head/tail, buried JSSDK JSSDK and sharing, and so on, but not every business needs.

A function may correspond to multiple JS or CSS files. If the business modifies the public/index.html file each time, it is also quite troublesome. First they have to figure out what files each feature needs to import before they can make changes to index.html.

At this time, we can add a configuration file. Businesses can select functions they need by setting true or false, and then generate HTML files for each business according to the content of the configuration file.

First, we add a new config.js file (whatever name you like) to the public directory and set its contents to:

/ / public/config. Js in addition to the following configuration, it can also have many other configuration, for example, the path of the pulicPath etc module. Exports = {dev: {template: {title: 'Test 1', header: false, footer: false}}, build: {template: {title: {' test 2', header: true, footer: false}}Copy the code

Now, modify webpack.config.dev.js and webpack.config.prod.js:

//webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];

modue.exports = {
    //...
    mode: isDev ? 'development' : 'production'
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html', //打包后的文件名
            config: config.template
        })
    ]
}
Copy the code

Accordingly, we need to modify our public/index.html file (js and CSS for illustration only) :

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, Initial - scale = 1.0 "> < meta HTTP - equiv =" X - UA - Compatible "content =" ie = edge "> < % if (htmlWebpackPlugin. Options. Config. The header)  { %> <link rel="stylesheet" type="text/css" href="//common/css/header.css"> <% } %> <title><%= (htmlWebpackPlugin.options.config.title) %></title> </head> <body> </body> <% if(htmlWebpackPlugin.options.config.header) { %> <script src="//common/header.min.js" type="text/javascript"></script> <% } %> </html>Copy the code

Note: process.env does not have NODE_ENV by default, so let’s configure our package.json scripts here

For Compatibility with Windows and Mac, let’s first install cross-env

yarn add cross-env -D


{
    "scripts": {
        "dev": "cross-env NODE_ENV=development webpack-dev-server --config ./webpack/webpack.config.dev.js --open",
        "build": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.prod.js",
     }
}
Copy the code

Note: Here we configure the webPack configuration file for the development environment, and the WebPack configuration file for the production environment

Run YARN Run dev and run YARN run build. Compare build/index.html, and you can see the file index.html generated by YARN Run Build. CSS and JS are imported into the file. And the corresponding title content is also different.

3.4 test

1. Run yarn Run dev to test whether the project can run properly

2. Run yarn Run build to test whether the project can be packaged and compiled properly. The compiled directory structure is as follows

. ├ ─ ─ index. The HTML └ ─ ─ js └ ─ ─ main. 0 b16f9b82b7fb2c9ba57. Bundle. JsCopy the code

Note: webpack-dev-server is compatible with the webpack version, which is “webpack”: “4.39.2”, and “webpack-cli”: “3.3.7”, webpack-dev-server version is “webpack-dev-server”: “3.8.0”, the service can be started normally, but the following error occurs:

TypeError: Cannot read property 'headers' of null
Copy the code

The following picture shows an error:

If the webpack-dev-server version is changed to “webpack-dev-server”: “3.7.0”, the above error will not occur again.

4. Work with CSS/SCSS style files

4.1 Installing Dependencies

Webpack cannot handle CSS directly, you need to use loader. If it is.css, the loader we need usually has: Postcss-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader: postCSs-loader Use less-loader):

Installation-related dependencies:

  • Css-loader and Sas-loader handle CSS styles and SCSS styles
  • Style-loader Styles processed by CSS-loader and sas-loader are processed into style labels in the DOM by style-loader
  • Mini-css-extract-plugin extracts CSS files separately, which may be because packaging into a JS file is too large, affecting the loading speed, or may be for caching. If using this plug-in, it will replace the function of style-loader

The command is as follows:

yarn add style-loader sass-loader css-loader mini-css-extract-plugin node-sass -D
Copy the code

4.2 WebPack Configuration Modification

The Webpack code configuration is as follows:

Const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { //... module: { rules: [ { test: /\.(sc|c)ss$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { hmr: process.env.NODE_ENV === 'development' } }, { loader: 'css-loader', options: { importLoaders: 1 } }, 'sass-loader' ], exclude: /node_modules/ } ] } }Copy the code

Note: the mini-CSs-extract-plugin version is compatible with configuration issues, if the webpack configuration file in the mini-CSs-extract-plugin configuration is as follows:

The installed mini-CSs-extract-plugin version is “mini-CSs-extract-plugin “: “^1.3.1”

The following error message is displayed after the service is started:

The configuration of the Mini-CSS-extract-plugin is as follows:

If the service is started, the following error is reported:

The above problems are incompatible with the mini-CSS-extract-Plugin version. If the “Mini-CSs-extract-Plugin “: “1.2.1” is used, the above problems will not occur.

5. Image/font file processing

Use url-loader to process images/fonts. Url-loader relies on file-loader. Url-loader can specify that the DataURL is returned when the file size is smaller than the specified limit

5.1 WebPack configuration file modification

//webpack.config.dev.jsmodule.exports = {
  module: {
    rules: [              
     {
       test: /\.(png|jpg|gif|woff|svg|eot|ttf)$/,
       use: [{
         loader: 'url-loader',
         options: {
           limit: 10000,
           esModule: false
           name: '[name]_[hash:6].[ext]',
           outputPath: 'assets'
         },
       }],
       exclude: /node_modules/
     },
    ],
  },
};
Copy the code

5.2 Installing Dependencies

The installation command is as follows:

yarn add url-loader file-loader -D
Copy the code

Note: If the image file path is output as [object-module] after the project is run or packaged, you need to set esModule: false

6. More about webPack configuration

6.1 Clear the Build directory before each package

1. Install dependencies:

yarn add clean-webpack-plugin -D
Copy the code

2. The code of the webpack configuration file is as follows:

//webpack.config.dev.js const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { //... Plugins: [// Do not need to pass arguments, it can find outputPath new CleanWebpackPlugin()]}Copy the code

3. A certain folder in the build directory is not cleared

The clean – webpack – plugin cleanOnceBeforeBuildPatterns provides us with parameters

The code for the Webpack configuration file is as follows:

//webpack.config.dev.js module.exports = { //... Plugins: [new CleanWebpackPlugin ({cleanOnceBeforeBuildPatterns: [' * * / * ', '. DLL ', '. DLL / * * '] / / not to delete the DLL files in the directory})]}Copy the code

6.2 Copying Static Resources to Public

Scenario: Sometimes, we need to use existing JS files, CSS files (local files), but do not need webpack compilation. For example, we introduced js or CSS files in the public directory in public/index.html. At this point, if you package directly, then after the build, there will be no corresponding JS/CSS.

For this problem, we can copy to the build directory by copy-webpack-plugin and then configure the CleanWebpackPlugin without emptying the corresponding files or folders.

1. Install dependencies

yarn add copy-webpack-plugin -D
Copy the code

2. The code of the webpack configuration file is as follows:

//webpack.config.dev.js const CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = { //... plugins: [ new CleanWebpackPlugin( cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, 'build', 'js')], ), new CopyWebpackPlugin([ { from: 'public/js/*.js', to: Path. resolve(__dirname, 'build', 'js'), flatten: true,},Copy the code

Note: Flatten, set to true, copies only files, not all folder paths

3. CopyWebpackPlugin also provides ignore if we want to copy many files in a directory but want to filter out one or more files.

The code for the Webpack configuration file is as follows:

//webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
    //...
    plugins: [
        new CopyWebpackPlugin([
            {
                from: 'public/js/*.js',
                to: path.resolve(__dirname, 'build', 'js'),
                flatten: true,
            }
        ], {
            ignore: ['other.js']
        })
    ]
}
Copy the code

6.3 ProvidePlugin for automatically loading modules

The ProvidePlugin can be used anywhere in a project without import or require.

ProvidePlugin is a built-in plug-in for WebPack and can be used as follows:

new webpack.ProvidePlugin({
  identifier1: 'module1',
  identifier2: ['module2', 'property2']
});
Copy the code

The default path to find is the current folder./** and node_modules. You can specify the full path.

1. Webpack configuration code is as follows:

const webpack = require('webpack');
module.exports = {
    //...
    plugins: [
        new webpack.ProvidePlugin({
            React: 'react',
            Component: ['react', 'Component'],
            Vue: ['vue/dist/vue.esm.js', 'default'],
            $: 'jquery',
            _map: ['lodash', 'map']
        })
    ]
}
Copy the code

This allows you to use $and _map as you like in your project, and write React components without the need to import React and Component. You can also configure the React Hooks here if you want.

Note: The Vue configuration is followed by a default, because export Default is used in vue.esm.js. In this case, default must be specified. React uses module.exports, so don’t write default.

2. Global variables define Settings in esLint related configuration files

If your project has ESLint enabled, modify the esLint configuration file to add the following configuration:

Settings in the.eslintrc.js configuration file:

{ "globals": { "React": true, "Vue": true, //.... }}Copy the code

6.4 Define DefinePlugin for global variables

DefinePlugin allows you to create a global constant that can be configured at compile time. This can be very useful when the development mode and the release mode are built to allow different behaviors. DefinePlugin is a built-in plug-in for WebPack.

1. Usage Scenarios:

  • If logging is not performed in a development build but in a release build, global constants can be used to determine whether logging is performed.

  • We use pre-release or local domain names in development and online domain names in production. We can define environment variables in Webpack and use them in code.

2. Usage

Each key passed into DefinePlugin is an identifier or more than one that uses. Concatenated identifier.

  • ifvalueIt’s a string. It’s going to be treated ascodeCode snippet
  • ifvalueIt’s not a string, it’s gonna bestringify, is converted to strings (including functions)
  • ifvalueIs an object, the normal object definition. All of its keys will be defined the same way
  • ifkeyThere aretypeofIt only applies totypeofCall the definition. That is, if you’re in akeyIn front of the addedtypeofPhi is going to be defined as phitypeofcall

3. The code is as follows:

+ const { DefinePlugin } = require('webpack');

+ const definePlugin = new DefinePlugin({
+   _DEV_: false,
+   GLOBAL_SERVICE: {
+     HOST: JSON.stringify('https://www.qianyin925.com:4000'),
+     GRAPHQL_URL: JSON.stringify('/graphql'),
+   },
+ });

module.exports = {
  plugins: [
+   definePlugin,
  ]
};
Copy the code

6.5 resolve configuration

Resolve configures how WebPack finds files for modules.

Webpack has built-in JavaScript modular syntax parsing capabilities, which are found by default using rules agreed in the modular standard, but you can modify the default rules to suit your needs.

1. module

Resolve. modules configures the directory in which webpack will look for third-party modules. By default, node_modules is only used. This can be simplified by configuring resolve.modules.

//webpack.config.dev.js module.exports = { //.... Resolve: {modules: ['./ SRC /components', 'node_modules'] // From left to right}}Copy the code

After this configuration, we import Dialog from ‘Dialog’ and look for./ SRC /components/ Dialog, no longer using the relative path import. If you can’t find it under./ SRC /components, you’ll look for it under node_modules.

2. alias

The resolve.alias configuration item maps the original import path to a new import path by alias, for example:

//webpack.config.dev.js module.exports = { //.... resolve: { alias: { "@": path.resolve(__dirname, '.. / SRC '), 'react-native': '@my/react-native '}}}Copy the code

3. extensions

Web. Js,.wx.js, for example, in a web project, we want to find.web. Js first, if not, then.js. We can configure it like this:

//webpack.config.dev.js module.exports = { //.... Resolve: {extensions: ['web.js', '.js'] // You can also configure.json,.css}}Copy the code

For example, introduce the following code:

import dialog from '.. /dialog';Copy the code

First look for.. /dialog.web.js, if not present, look for.. / dialog. Js. This is very useful in multi-terminal code where you would otherwise have to import files for different platforms (at the expense of speed).

If the import statement does not have a file suffix, it will automatically add the suffix configured in the extensions to try to access the file. Therefore, put the suffix in front of the file and make the array not too long to reduce the attempts. If extensions are not configured, only the appropriate JS file will be found by default.

4. enforceExtension

If resolve.enforceExtension is configured to true, import statements cannot default file suffixes.

5. mainFields

Some third-party modules provide multiple pieces of code, such as bootstrap. You can view the package.json file of bootstrap:

{
    "style": "dist/css/bootstrap.css",
    "sass": "scss/bootstrap.scss",
    "main": "dist/js/bootstrap",
}
Copy the code

Resolve. MainFields default configuration is [‘browser’, ‘main’], which first looks for the brower field in the corresponding dependency package.json, and if not, looks for the main field.

For example: import ‘bootstrap’ By default, find the file specified in the main field of the corresponding dependency package.json, dist/js/bootstrap.

But suppose we want import ‘bootsrap’ to find CSS files by default, we can configure resolve.mainFields to be:

//webpack.config.dev.js
module.exports = {
    //....
    resolve: {
        mainFields: ['style', 'main'] 
    }
}
Copy the code

6.6 Cross-env Setting environment variables

Advantages: Compatible with multiple platforms

1. Package. json script command Settings are as follows:

{
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config ./webpack/webpack.config.dev.js --open",
    "build": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.prod.js"  }
}
Copy the code

2. The installation command is as follows:

yarn add cross-env -D
Copy the code

6.7 Raw-loader Used to Load text contents (. TXT and. Md files)

A loader that can be used to load files as strings, using UTF-8 encoding.

1. The installation command is as follows:

yarn add raw-loader -D
Copy the code

2. The webpack configuration file is as follows:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(text|md)$/,
        use: 'raw-loader',
      },
    ]
  }
};
Copy the code

The introduction is as follows:

For example, in file.js

import txt from './file.txt';
Copy the code

6.8 Differentiate the use of Webpack-Merge in different environments

For the webpack.config.js configuration file, when we need to distinguish between a development environment and a production environment, it is good practice to create multiple configuration files, such as: Webpack.config.base. js, webpack.config.dev.js, webpack.config.prod.js.

  • webpack.config.base.jsDefine common configurations
  • webpack.config.dev.js: Defines the configuration of the development environment
  • webpack.config.prod.js: Defines the configuration of the production environment

Webpack-merge is designed for Webpacks and provides a merge function that joins arrays and merges objects.

1. The webpack-merge installation command is as follows:

yarn add webpack-merge -D
Copy the code

2. The following is an example of webpack-merge:

const merge = require('webpack-merge'); Merge ({devtool: 'cheap-module-eval-source-map', module: {rules: [{a: 1}]}, plugins: [1,2,3]}, {devtool: 'none', mode: "production", the module: {rules: [{} a: 2, 1} {b:]}, plugins: [4 and 6],}); / / to the result of the combined {devtool: 'none', mode: "production", the module: {rules: [{a: 1}, {2} a:, 1} {b:]}, plugins: [6]}Copy the code

Where, webpack.config.base.js is the generic Webpack configuration.

Take webpack.config.dev.js as an example:

//webpack.config.dev.js const merge = require('webpack-merge'); const baseWebpackConfig = require('./webpack.config.base'); module.exports = merge(baseWebpackConfig, { mode: 'development' //... Other configurations});Copy the code

The script command corresponding to package.json is modified as follows:

//package.json
{
    "scripts": {
        "dev": "cross-env NODE_ENV=development webpack-dev-server --config ./webpack/webpack.config.dev.js --open",
        "build": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.prod.js"
    },
}
Copy the code

Smart merges the same matching rules when merging loaders. The webpack-Merge documentation provides a detailed example.

6.9 WebPack Solves cross-domain problems

Assuming that the front-end is at port 3000 and the server is at port 4000, we implement cross-domain through webPack configuration.

1. If you have a backend server on localhost:4000, you can enable the proxy as follows:

proxy: {
  "/api": "http://localhost:3000"
}
Copy the code

Request to the/API/users will now be agent to request http://localhost:4000/api/users

2. If you don’t want to pass/API all the time, you need to rewrite the path:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    pathRewrite: {"^/api" : ""}
  }
}
Copy the code

3. By default, backend servers running over HTTPS and using invalid certificates are not accepted. If you want to accept, modify the configuration as follows:

proxy: {
  "/api": {
    target: "https://other-server.example.com",
    secure: false
  }
}
Copy the code

4. In the parameter list of proxy, there is a changeOrigin parameter, which is a Boolean value. If set to true, the local server will receive your request and send it on your behalf

proxy: {
  "/api": {
    target: "https://other-server.example.com",
    secure: false,
    changeOrigin: true
  }
}
Copy the code

6.10 hot update

1. Set the hot value of devServer to true

2. And add new webpack in plugins. HotModuleReplacementPlugin ()

The code is as follows:

//webpack.config.dev.js const webpack = require('webpack'); module.exports = { //.... DevServer: {hot: true}, plugins: [new webpack. HotModuleReplacementPlugin () / / hot update plugins]}Copy the code

6.11 Multi-Page Application Packaging Mode

1. Scenario: Our application is not necessarily a single page application, but a multi-page application, so how to use WebPack for packaging?

To make the generated directory look clean, do not generate a separate map file.

The code is as follows:

//webpack.config.dev.js const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { index: './src/index.js', login: './src/login.js' }, output: { path: path.resolve(__dirname, 'dist'), filename: '[name].[hash:6].js' }, //... plugins: [ new HtmlWebpackPlugin({ template: './public/index.html', filename: New HtmlWebpackPlugin({template: './public/login.html', filename: 'login.html' // Packaged file name}),]}Copy the code

Note: if you need to configure multiple htmlwebpackplugins, the filename field cannot be default, otherwise the index.html will be generated by default. If you want the HTML filename to have a hash, you can simply change the fliename field, for example: Filename: ‘ ‘login. [hash: 6]. HTML.

2. Generate directories as follows:

. ├ ─ ─ build │ ├ ─ ─ 2.463 CCF. Js │ ├ ─ ─ assets │ │ └ ─ ─ thor_e09b5c. Jpeg │ ├ ─ ─ CSS │ │ ├ ─ ─ index. The CSS │ │ └ ─ ─ the login. The CSS │ ├ ─ ─ ├─ ├─ ├─ ├─ login.txt ├.txt ├─ login.txtCopy the code

But if you look at index.html and login.html, both of them introduce index.f7d21a.js and login.f7d21a.js, which is usually not what we want, we want, Only index.f7d21a.js is imported into index.html and login.html is imported into login.f7d21a.js.

The HtmlWebpackPlugin provides a value of chunks that can accept an array. Configuring this parameter only introduces the js specified in the array into the HTML file. If you need to introduce multiple JS files, only a few of which do not want to, you can also specify excludeChunks. It takes an array.

The code is as follows:

//webpack.config.dev.js module.exports = { //... Plugins: [new HtmlWebpackPlugin({template: './public/index.html', filename: 'index.html', // packed filename chunks: ['index']}), new HtmlWebpackPlugin({template: './public/login.html', filename: 'login.html', // packed filename chunks: ['login'] }), ] }Copy the code

6.12 devtool

There are some Settings in devtool that help us map the compiled code back to the original source. Different values can significantly affect the speed of builds and rebuilds.

For me, it’s just a matter of being able to locate the line of source code. Therefore, considering the build speed, I set devtool to be cheap-module-eval-source-map in development mode.

//webpack.config.js module.exports = {devtool: 'cheap-module-eval-source-map'} //webpack.config.js module.exports = {devtool: 'cheap-module-eval-source-map'}Copy the code

7. Optimize the webPack configuration of the project

Webpack packaging optimization: multi-process packaging, multi-process compression, resource CDN, dynamic polyfill

7.1 Speed-measure-webpack-plugin for quantitative indicators

The speed-measure-webpack-plugin can measure the time spent by each plug-in and loader, that is, the speed measurement plug-in. After being used, information similar to the following will be obtained during construction:

In this way, the information before and after can be compared to determine the effect of optimization.

The installation command is as follows:

yarn add speed-measure-webpack-plugin -D
Copy the code

The speed-measure-webpack-plugin configuration information is as follows:

//webpack.config.dev.js const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin(); const config = { //... Module.exports = smp.wrap(config);Copy the code

If the webpack-merge plug-in is used to differentiate different environments, the speed-measure-webpack-plugin configuration information is as follows:

//webpack.config.base.js const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin(); const config = { //... Module.exports = smp.wrap(config);Copy the code

7.2 WebPack-Bundle-Analyzer for Volume Analysis

After analyzing the packaging speed, let’s analyze the size of each file and module after packaging. The plugin used is webpack-bundle-Analyzer, which displays the size on port 8888 when it is built.

Use webpack-bundle-Analyzer to see which packages are larger. This dependency is used when the project is packaged.

1. Install dependency commands:

yarn add webpack-bundle-analyzer -D
Copy the code

2. The configuration file code is as follows:

//webpack.config.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.config.base');
module.exports = merge(baseWebpackConfig, {
    //....
    plugins: [
        //...
        new BundleAnalyzerPlugin(),
    ]
})
Copy the code

3. Run the yarn run build command to package the port that automatically starts http://127.0.0.1:8888/. The following figure is displayed:

7.3 Optimization of WebPack packaging speed

1. Optimize the scene:

In the process of webpack construction, one of the direct influences on the construction efficiency is the compilation of files, and another is the classification and packaging of files. File compilation is time-consuming, and files can only be processed one by one in the Node environment, so this optimization needs to be addressed. So how to optimize the packaging speed?

2. Use older versions of WebPack and Node.js

The new version of webpack4 uses the v8 engine for optimizations, which include:

  • For of v. forEach
  • Map and Set replace Object
  • Includes replacement indexOf ()
  • By default, md4 hash algorithm is used instead of MD5 algorithm, because MD4 is faster than MD5 algorithm
  • Webpack AST can be passed directly from the Loader to the AST, reducing parsing time
  • Use string methods instead of regular expressions

Later versions of Node.js make further improvements to the native JS API and JS data structure

3. Multi-process/multi-instance build (resource parallel parsing)

In the process of webpack construction, we need to use Loader to convert JS, CSS, pictures, fonts and other files, and the amount of file data to convert is also very large, and these conversion operations cannot concurrently process files, but need to process files one by one. What we need is to split this part of the task into multiple sub-processes to process it in parallel, and the sub-processes send the results to the main process when they are finished, thus reducing the total build time.

alternative

  • Thread-loader (official release)
  • parallel-webpack
  • HappyPack

HappyPack

Note: Since HappyPack authors are less interested in JS, maintenance will be less in the future. Webpack4 and later recommend thread-Loader

How it works: Every time WebPack parses a module, HappyPack assigns it and its dependencies to the worker process. HappyPack splits modules into modules. For example, if we have multiple modules, these modules are handed to HappyPack. First, after the WebPack Compiler (hook) run method, the process will arrive at HappyPack. After initialization, a thread pool will be created. The pool will allocate the modules in the build task. For example, a module and its dependencies will be allocated to one of the HappyPack threads. Each thread in the thread pool processes the module and its dependencies. After processing, there is a communication process that transfers the processed resources to one of the main processes of HappyPack to complete a build process.

Copy the same pages from the SRC directory

Perform packaging without introducing HappyPack

HappyPack installation command:

yarn add happypack -D
Copy the code

Note: HappyPack5.0 is required if used in webpack4.

Change rules to happypack/loader

The Webpack file is set as follows

rules: [
      {
        test: /\.(mjs|js|jsx)$/,        use: 'HappyPack/loader?id=js',
        exclude: /node_modules/
      },
]
Copy the code

Add happypack-loader to the plugin

Plugins: [new HappyPack({id: 'js', // and rule id=js threadPool: HappyPack.ThreadPool({size: 4}), loader: [{loader: 'babel-loader', options: { presets: ["@babel/preset-env", "@babel/preset-react"], plugins: [ [ "@babel/plugin-transform-runtime", {"corejs": 3} ] ] } } ] }) ]Copy the code

thread-loader

Working Principle: Similar to HappyPack, each time webPack parses a module, Thread-Loader assigns it and its dependencies to worker processes.

The installation command is as follows:

yarn add thread-loader -D
Copy the code

Add thread-loader to rule. Thread-loader can be configured to workers (number of processes).

rules: [
      {
        test: /\.(mjs|js|jsx)$/,        
        use: {
            'babel-loader',
            {
                loader: 'thread-loader',
                options: {
                    workers: 3
                }
            }
        },
        exclude: /node_modules/
      },
]
Copy the code

7.4 Code Compression for Multiple Processes or Instances (Parallel Compression)

There is a code compression phase after the code is built and before the output, this phase can also be parallel compression to optimize the build speed;

Options:

  • webpack-parallel-uglify-plugin
  • Uglifyjs-webpack-plugin (es6 syntax not supported)
  • Terser-webpack-plugin **(Recommended for WebPack 4.0, supports compression of ES6 code)**

The introduction code is as follows:

const TerserPlugin = require('terser-webpack-plugin');
Copy the code

Optimization configuration is as follows:

Optimization: {minimize: true, minimizer: [new TerserPlugin({// code compression plugin parallel: 4, // open parallel compression}),],}, minimize: {minimize: true, minimizer: [new TerserPlugin({// code compression plugin parallel: 4, // open parallel compression}),},Copy the code

Note: After the WebPack configuration file is set up, the service will be reported

TypeError: Cannot read property 'javascript' of undefined
Copy the code

Error message, the original version problem

Terser-webpack-plugin: “^4.2.3” can be installed if webpack4 is used, and terser-webpack-plugin5.0 or later is used for Webpack5. The version of Webpack I am currently installing is “webpack”: “4.39.2”

Install “terser-webpack-plugin”: “^4.2.3”. If you install “terser-webpack-plugin”: “^5.0.3”, the following error will be reported:

7.5 Using cache to improve secondary packaging speed

  • Babel-loader enables caching
  • Terser-webpack-plugin enables caching
  • Use cache-loader or hard-source-webpack-plugin

1. Set cacheDirectory of babel-loader to true to enable caching

new HappyPack({
  loaders: ['babel-loader?cacheDirectory=true'],
})
Copy the code

2. Set the cache of terser-webpack-plugin: true to enable caching

Optimization: {minimize: true, minimizer: [new TerserPlugin({// parallel: 4, // enable parallel: true,}),],}, minimize: {minimize: true, minimizer: [new TerserPlugin({// parallel: 4, // enable parallel: true,}),},Copy the code

3. HardSourceWebpackPlugin provides intermediate cache for modules

HardSourceWebpackPlugin provides an intermediate cache for modules. The default cache path is node_modules/. Cache /hard-source.

With the hard-source-webpack-plugin, the first build time doesn’t change much, but the second build time can be saved by about 80%.

The installation command is as follows:

yarn add hard-source-webpack-plugin -D
Copy the code

The webpack configuration file is modified as follows:

//webpack.config.base.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
    //...
    plugins: [
        new HardSourceWebpackPlugin()
    ]
}
Copy the code

The first packaging time after the change is as follows (still faster than the packaging speed before no caching) :

The time for repackaging without changing the content is as follows:

7.5 Narrow the build goals

Build as few modules as possible, for example babel-loader does not resolve node_modules

  • Optimize the resolve.modules configuration (reduce the module search hierarchy)
  • Optimize the resolve.mainfields configuration
  • Optimize the resolve.extensions configuration

7.6 Optimization of packing volume

Mainly optimize the resource volume of packaged images, JS and CSS files

1. Image compression

Using the Imagemin of Node library, configure image-webpack-Loader to optimize the image. During the construction of the plug-in, image resources will be recognized and optimized

Imagemin advantage analysis

  • Imagemin has many customization options
  • More third-party optimization plug-ins can be introduced, for examplepngquant
  • Multiple image formats can be introduced

Imagemin compression principle

  • Pngquant is a PNG compressor that significantly reduces file size by converting images to a more efficient 8-bit PNG format with alpha channels (typically 60%-80% smaller than 24/32-bit PNG files). Alpha channels are the transparency and semi-transparency of an image;

  • Pngcrush: Its main purpose is to reduce the size of PNG IDAT data streams by trying different compression levels and PNG filtering methods;

  • Optipng: Its involvement was inspired by PngCrush. Optipng can recompress image files to a smaller size without losing any information;

  • Tingpng: Also converts 24-bit PNG files into smaller 8-bit images with indexes, while all non-essential metadata is stripped away;

The installation command is as follows:

yarn add image-webpack-loader -D
Copy the code

Note: If yarn or NPM is used, an error message is displayed even if a ladder is used. You are advised to install the plug-in using CNPM.

The webpack configuration file is as follows:

rules: [ { test: /.(png|jpg|gif|jpeg)$/, use: [ { loader: 'file-loader', options: { name: '[name]_[hash:8].[ext]', }, }, { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true, quality: 65, }, // optipng.enabled: false will disable optipng optipng: { enabled: false, }, pngquant: { quality: [0.65, 0.9], speed: 4,}, GIFsicle: {interlaced: false,}, // The webp option will enable webp webp: {lace: 75,},},},],}]Copy the code

Comparison Before and after using the image-webpack-loader plug-in:

Before use:

After using dependencies:

Compared with the file size before and after using image-webpack-loader, the file size can be significantly reduced and the image of large files can be compressed.

Note: Note the installation sequence of dependencies. If you install webpack-dev-server first and then install image-webpack-loader, there is no problem. If you install webpack-dev-server and remove webpack-dev-server, then install webpack-dev-server and start the service, errors will be reported in image-webpack-loader mozjpeg, GIFsicle, etc. Remove image-webpack-loader and reinstall the image-webpack-loader.

If the installation of image-webpack-loader fails, CNPM is used. This step means that CNPM is installed and the global registry is set as the image of Ali. Ali is faster in China.

The command is as follows:

npm install cnpm -g --registry=https://registry.npm.taobao.org
Copy the code

Install image-webpack-loader using CNPM and you’ll find it installed quickly

cnpm install --save-dev  image-webpack-loader
Copy the code

Note: If you have tried to install image-webpack-loader using YARN or NPM, remove the image-webpack-loader before installing it using CNPM.

2. Delete unused CSS

Plug-ins can be used to walk through the code and identify the CSS classes that have been used

The installation command is as follows:

yarn add purgecss-webpack-plugin -D
Copy the code

Note: If yarn or NPM is used, an error message is displayed even if a ladder is used. You are advised to install the plug-in using CNPM.

The webpack configuration file is as follows:

const path = require('path');
const glob = require('glob');
const PurgecssPlugin = require('purgecss-webpack-plugin');
const PATHS = {
    src: path.join(__dirname, 'src')
}

plugins: [
    new PurgecssPlugin({
        paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
    })
]
Copy the code

Set multiple paths:

If you need to set multiple paths, use the NPM package glob-all to replace glob and then use the following syntax:

new PurgecssPlugin({
  paths: glob.sync([
    // ...
  ])
}),
Copy the code

7.7 Use of Babel-Polyfill

8. Introduce Antd and configure load on demand

Add the plug-in babel-plugin-import for the.babelrc configuration to enable antD loading on demand.

8.1 modification. Babelrc

Note: When configuring the plug-in, you can set the instantiation name import-antd so that you can use the same plug-in multiple times, if you also need to use babel-plugin-import for other component libraries

{
+ "plugins": [
+   ["import", {
+     "libraryName": "antd",
+     "libraryDirectory": "es",
+     "style": "css"
+   }, "import-antd"]
+ ],
  "presets": [
    "@babel/preset-react",
    "@babel/preset-env"
  ]
}
Copy the code

8.2 Dependent Installation

yarn add antd
yarn add babel-plugin-import -D
Copy the code

8.3 Code introduction examples

import React from 'react'; import reactDom from 'react-dom'; + import { Button } from 'antd'; Const App = () = > (< div > + < Button type = "primary" > Button < / Button > < / div >). reactDom.render(<App/>, document.getElementById('root'));Copy the code

Note: The following error is reported when running the project after antD is introduced:

ERROR in ./node_modules/antd/es/button/style/index.css 5:0
Module parse failed: Unexpected token (5:0)
Copy the code

Exclude: /node_modules/ exclude: /node_modules/ exclude: /node_modules/ /