Ten thousand word long text decryption webpack - basic use / advanced usage / performance optimization you have everything you want!!!

It's not easy to refuse to pay a compliment

preface

In essence, webpack is a static module packaging tool for modern JavaScript applications. When webpack processes an application, it will internally build a dependency graph from one or more entry points, and then combine each module required in your project into one or more bundles, which are static resources for displaying your content.
Main concepts

  1. Entry
  2. Output
  3. loader
  4. Plug in
  5. Mode

1. Basic use

1.1 split configuration and merge

Initialize package json

npm init -y

1.1. 1. Install webpack

yarn add -D webpack webpack-cli

1.1. 2. Install webpack merge

yarn add -D webpack-merge

1.1. 3. Create a new build folder and configuration file

  • build\webpack.common.js
  • build\webpack.dev.js
  • build\webpack.prod.js

webpack.common.js

Public configuration

const path = require('path')

module.exports ={
    entry:path.join(__dirname, '..', 'src/index')
}

webpack.dev.js

When developing

const webpackCommon = require('./webpack.common.js')
const { merge } = require('webpack-merge')

module.exports = merge(webpackCommon, {
    mode: 'development'
})

webpack.prod.js

When packing

const path = require('path')
const webpack = require('webpack')
const webpackCommon = require('./webpack.common.js')
const { merge } = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = merge(webpackCommon, {
    mode: 'production',
    output: {
        filename: '[name].[contenthash:8].js',
        path: path.join(__dirname, '..', 'dist'),
    },
    plugins: [new CleanWebpackPlugin()]
})

1.1.4 Scripts

 "scripts": {
   // Local service
    "dev": "webpack-dev-server --config build/webpack.dev.js",
    "build": "webpack --config build/webpack.prod.js"
  },

1.1. 5 test

New src/index
Execute yarn build

1.2 start local service

1.2. 1. Install webpack dev server

yarn add -D webpack-dev-server

1.2. 2. Configure devServer

webpack.dev.js

   devServer: {
        port: 8080,
        progress: true,  // Show packaged progress bar
        contentBase:path.join(__dirname, '..', 'dist'),  // root directory
        open: true,  // Open browser automatically
        compress: true,  // Start gzip compression

        // Set agent
        proxy: {
            
        }
    }

1.2. 3 start

yarn dev

1.2. 4 test

Install HtmlWebpackPlugin to automatically generate html

yarn add -D html-webpack-plugin

Configure HtmlWebpackPlugin

webpack.common.js

 plugins:[
        new HtmlWebpackPlugin({
            template: path.join(__dirname, '..', 'src/index.html'),
            filename: 'index.html'
        })
    ]

The development environment will generate an html file in memory
In the packaging environment, an html file will be generated under dist
The html file is automatically imported into main js

1.3 processing ES6 (configuration babel)

13.1. install

babel-loader

yarn add -D babel-loader

@babel/core

yarn add -D @babel/core

@babel/preset-env

yarn add -D @babel/preset-env

1.3. 2. Configuration

.babelrc

{
    "presets": ["@babel/preset-env"],
    "plugins": []
}

build\webpack.common.js

  module: {
        rules: [
            {
                test: /\.js$/,
                // Loader: 'Babel loader', / / loader is a single loader, and use is an array of loaders
                use: [
                    'babel-loader',
                ],
                include: path.join(__dirname, '..', 'src'),
                exclude: /node_modules/
            }
        ]
    },

1.4 handling css

1.4. 1 installation

style-loader

css is inserted into the style tag of the page

yarn add -D style-loader

css-loader

yarn add -D css-loader

postcss-loader + autoprefixer

Auto prefix

yarn add -D postcss-loader autoprefixer

1.4. 2 configuration

build\webpack.common.js

{
    test: /\.css$/,
    // The order of loader execution is from back to front
    use: ['style-loader', 'css-loader', 'postcss-loader'] 
},

postcss.config.js

module.exports = {
    plugins: [require('autoprefixer')]
}

1.5 processing pictures

1.5. 1 there are three ways to introduce pictures into general documents:

js file through import imgSrc from '/ photo’; img.src = imgSrc introduced
It is introduced as a background image in the css file
Import directly in html file

1.5. 2 installation

file-loader

yarn add -D file-loader

url-loader

yarn add -D url-loader

1.5. 3 configuration

build-base-conf\webpack.dev.js

 // Directly import image url
            {
                test: /\.(png|jpg|jpeg|gif)$/,
                use: 'file-loader'
            }

build-base-conf\webpack.prod.js

 // Picture - consider base64 encoding
{
  test: /\.(png|jpg|jpeg|gif)$/,
    use: {
      loader: 'url-loader',
        options: {
          // Pictures less than 5kb are output in base64 format
          // Otherwise, the form of file loader is still used to produce url format
          limit: 5 * 1024,

            // Package to img directory
            outputPath: '/img1/',

              // Set the cdn address of the picture (it can also be set uniformly in the external output, which will act on all static resources)
              // publicPath: 'http://cdn.abc.com'
        }
        }
    },

2 advanced features

2.1 configure multiple entrances

2.1. 1. Configure entry

entry: {
        index: path.join(srcPath, 'index.js'),
        other: path.join(srcPath, 'other.js')
    },

index and other here are the names of chunk

2.1. 2. Configure the corresponding outlet

build-base-conf\webpack.prod.js

  output: {
        filename: 'bundle.[contentHash:8].js',  // When packaging code, add hash stamp
        path: distPath,
        // publicPath: 'http://cdn.abc.com '/ / modify the prefix of all static file URLs (such as CDN domain name), which is temporarily unavailable here
    },

Note that you only need to add configuration in prod here,
dev does not need

2.1. 3. Configure the corresponding template

new HtmlWebpackPlugin({
            template: path.join(__dirname, '..', 'src/index.html'),
            filename: 'index.html',
            // Chunks indicates which chunks (i.e. index and other above) are to be referenced on the page. All chunks are referenced by default
            chunks: ['index']  // Only index. Is referenced js
        }),
        // Multi entry - generate other html
        new HtmlWebpackPlugin({
            template: path.join(__dirname, '..', 'src/other.html'),
            filename: 'other.html',
            chunks: ['other']  // Reference only other js
        })

2.2 removing CSS (packaging)

2.2. 1 installation

mini-css-extract-plugin

yarn add -D mini-css-extract-plugin

2.2. 2 configuration

build\webpack.prod.js

loader

// Pull off css
{
  test: /\.css$/,
    use: [
      MiniCssExtractPlugin.loader,  // Note that style loader is no longer used here
      'css-loader',
      'postcss-loader'
    ]
},

plugins

 new MiniCssExtractPlugin({
        filename: 'css/main.[contenthash:8].css'
    })

2.3 compressing css (packaging)

2.3. 1 installation

optimize-css-assets-webpack-plugin

yarn add optimize-css-assets-webpack-plugin

2.3. 2 configuration

build-min-extract-css\webpack.prod.js

 optimization: {
        // Compress css
        minimizer: [ new OptimizeCSSAssetsPlugin({})],
    }

2.4 extracting public codes

Extract public code
When developing projects with multiple pages, we sometimes reference some public modules in several pages. These public modules are downloaded many times, which will cause a waste of resources. If these public modules are extracted and downloaded only once, they can be cached, so as to avoid wasting resources due to repeated downloading, So how to extract the public part from the webpack? The method is as follows:

2.4. 1 common module extraction

give an example:

The project includes A.js, B.js and page1 js, page2. JS these four JS files,
page1.js and Page2 JS also refers to A.js and B.js,
At this time, I want to separate A.js and B.js and merge them into a public JS, and then automatically introduce this public JS into page1 and Page2,

 splitChunks: {
   cacheGroups: {
     //Common module extraction
     common: {
       chunks: 'initial',
         minSize: 0, //Greater than 0 bytes
           minChunks: 2 //The minimum number of times this code block is referenced when pulling away public code
     }
   }
 }

2.4. 2. Third party module extraction

Third party modules are sometimes introduced into the page, such as import $from 'jquery'; You need references in page1 and page2. In this case, you can use vendor to extract jquery as follows:

   optimization: {
        // Split code block
        splitChunks: {
            chunks: 'all',
            /**
             * initial The entry chunk does not process files imported asynchronously
                async Asynchronous chunk, which only processes files imported asynchronously
                all All chunk s
             */

            // Cache grouping
            cacheGroups: {
                // Third party module
                vendor: {
                    name: 'vendor', // chunk name
                    priority: 1, // Higher authority, priority withdrawal, important!!!
                    test: /node_modules/,
                    minSize: 0,  // Size limit
                    minChunks: 1  // How many times at least
                },

                // Common module
                common: {
                    name: 'common', // chunk name
                    priority: 0, // priority
                    minSize: 0,  // Size limit of common module
                    minChunks: 2  // How many times has the common module been reused at least
                }
            }
        }

    }

Note: you need to configure the weight priority here, because the first common configuration will be executed when pulling away. When you see that jquery is also public at the entrance, it will be pulled away together, and the wendor configuration will not be executed again. Therefore, after adding the weight, the third-party module will be pulled away first, and then the public common will be pulled away, so that the third-party and public will be pulled away.

3 performance optimization

3.1 optimize Babal loader (reduce construction objectives)

3.1. 1 reason

The file conversion operation of Loader is very time-consuming, so it is necessary to let as few files as possible be processed by Loader

3.1. 2 configuration

{
    test: /\.js$/,
    use: [
        'babel-loader?cacheDirectory',//Enable conversion result cache
    ],
    include: path.resolve(__dirname, 'src'),//Babel loader is only used for files in src directory
    exclude: path.resolve(__dirname,' ./node_modules'),//Exclude node_ Files in the modules directory
},

3.2 happyPack multi process packaging

3.2. 1 installation

yarn add -D happypack

3.2. 2 configuration

Plugins

new HappyPack({
            // Using a unique ID to represent the current HappyPack is used to process a specific type of file, which corresponds to the use in rules
            id: "babel",
            loaders: ["babel-loader?cacheDirectory"], //The default setting is loader processing
            threads: 5, //Use shared pool processing
        }),
        new HappyPack({
            id: 'styles',
            loaders: ['css-loader', 'postcss-loader'],
            threads: 5, //Represents opening several sub processes to process this type of file
            verbose: true //Allow output of days
        }),

rules

     {
                test: /\.(js|jsx)$/,
                use: [MiniCssExtractPlugin.loader, "HappyPack/loader?id=babel"],
                exclude: path.resolve(__dirname, " ./node_modules"),
            },
            {
                test: /\.css$/,
                use: 'happypack/loader?id=styles',
                include: path.join(__dirname, '..', 'src')

            },

3.3 ParallelUglifyPlugin optimized compression

By default, webpack provides UglifyJS plug-in to compress JS code, but it uses single thread compression code, that is, multiple JS files need to be compressed, and it needs to compress files one by one.
Therefore, the speed of packaging compressed code in the formal environment is very slow (because compressing JS code requires parsing the code into an AST syntax tree abstracted by Object, and then applying various rules to analyze and process AST, resulting in a very time-consuming process).

3.3. 1 installation

yarn add -D webpack-parallel-uglify-plugin

3.3. 2 configuration

 new ParallelUglifyPlugin({
      // The parameters passed to UglifyJS are as follows:
      uglifyJS: {
        output: {
          /*
           Whether to output readable code, that is, spaces and tabs will be retained. The default is output. In order to achieve better compression effect,
           Can be set to false
          */
          beautify: false,
          /*
           Whether to keep the comments in the code. It is reserved by default. In order to achieve better compression effect, it can be set to false
          */
          comments: false
        },
        compress: {

          /*
           Whether to delete all console statements in the code. The default is not to delete. When enabled, all console statements will be deleted
          */
          drop_console: true,

          /*
           Whether to embed variables that have been defined but only used once, such as var x = 1; y = x, converted to y = 5, default to not
           Conversion. In order to achieve better compression effect, it can be set to false
          */
          collapse_vars: true,

          /*
           Whether to extract static values that occur multiple times but are not defined as variables to reference, such as x = 'xxx'; y = 'xxx' converted to
           var a = 'xxxx'; x = a; y = a; The default is no conversion. In order to achieve better compression effect, it can be set to false
          */
          reduce_vars: true
        }
      }
 	}
 )

3.4 automatic refresh

  With the help of automatic means, when the local source code file is monitored to change, the running code is automatically reconstructed, and then the browser refresh is controlled. Webpack These functions are built-in, and a variety of schemes are provided for us to choose from.

3.4. 1. Configuration of automatic refresh in the project:

module.export = {
  watch: true,
  watchOptions: {
    // Files or folders not listening
    ignored: /node_modules/,
    // After listening to the change, it will wait for 300ms to execute the action to prevent the file from being updated too fast, resulting in too high recompilation frequency  
    aggregateTimeout: 300,  
    // Judging whether the file has changed is realized by constantly asking the system whether the specified file has changed
    poll: 1000
  }
}

3.4. 2 Principle

  • The principle of monitoring a file change in Webpack is to obtain the last editing time of the file regularly (which can be set in watchOptions.poll), and save the latest last editing time each time. If it is found that the currently obtained and last saved last editing time are inconsistent, the file is considered to have changed
  • When a file is found to have changed, it will not immediately tell the listener, but cache it first, collect the changes for a period of time (which can be set in watchOptions.aggregateTimeout), and then tell the listener at one time. Prevent high-frequency input text that may cause file changes during code editing

3.5 module hot update

_ _ DevServer also supports a method called module hot replacement (Hot Module Replacement) technology can achieve super sensitive real-time preview without refreshing the whole web page. The principle is that when a source code changes, you only need to recompile the changed module, and then use the new output module to replace the corresponding old module in the browser. Module hot replacement technology improves the development efficiency and experience to a great extent.
Configuration of module hot replacement in the project:

 const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');

 devServer:{
        host:'localhost',
        port:'8080',
        open:true//Automatically pull up the browser
        // Only hot is set, and only cssHMR takes effect
        hot:true,//Thermal loading
        //hotOnly:true
    },
    plugins:[
    //Hot update plug-in
        new webpack.HotModuleReplacementPlugin()
    ]

HotModuleReplacementPlugin Generate a mainifest(One json The structure describes the change modules (list)
and update file(One js (the file contains the modified code content)

JS file

if (module.hot) {
    module.hot.accept('./print.js', function() { //Tell webpack to accept the hot replacement module
        console.log('Accepting the updated printMe module!');
        printMe();
    })
}
// Effective for Js 

3.6 performance analysis

3.6.1 webpack-bundle-analyzer

]

// config/webpack.common.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

const commonConfig = {
  // ...
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerPort: 8889, // Specify the port number
      openAnalyzer: false,
    }),
  ]
  // ...
}

3.6.2 speed-measure-webpack-plugin

// config/webpack.common.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
// ...
module.exports = (production) => {
  if (production) {
    const endProdConfig = merge(commonConfig, prodConfig);
    return smp.wrap(endProdConfig);
  } else {
    const endDevConfig = merge(commonConfig, devConfig);
    return smp.wrap(endDevConfig);
  }
};

Postscript

2020-10-10 webpack 5.0.0 has been released, but that doesn't mean it's complete, bug free, or even fully functional. Like webpack 4
Similarly, we continue development by fixing problems and adding new features. There may be many bug fixes in the coming days. New features may also appear.

Try using persistent caching to improve build performance. Try to improve long-term caching with better algorithms and defaults. Try to improve the package size with better Tree Shaking and code generation.
Try to improve compatibility with network platforms. Try to clean up internal structures that are in a strange state when implementing v4 functions without introducing any destructive changes.
This paper attempts to prepare for future functions by introducing breakthrough changes now, so that it can be maintained on the v5 version for as long as possible. Migration guide

Keywords: Javascript Front-end Webpack

Added by idealbrain on Mon, 20 Dec 2021 15:29:57 +0200