This topic is mainly for the online, webpack should do what optimization.

Before the main introduction, let’s introduce the basic knowledge points. The following points are the summary of some problems I encountered.

First, configure the webpack command

The official website provides comprehensive configuration commands

File configuration is used here

Using configuration files

npx webpack [--config webpack.config.js]
Copy the code

For options in the configuration file, see Configuration.

Second, configure the basic configuration file

The basic configuration file is given, which can be packaged, and the optimization is combed in the future

const path = require('path')
// Use global definitions
const { DefinePlugin } = require('webpack')
// Empty the packaged dist
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// Use HTML templates
const HtmlWebpackPlugin = require('html-webpack-plugin')


module.exports = {
    entry: './src/index'.// Entry file read by webpack
    // Output resource file
    output: {
        filename: 'index.js'.path: path.resolve(__dirname, 'dist')},mode: 'development'.target: 'web'.devServer: {
        hot: true.open: true,},module: {
        rules: [{test: /\.jsx? $/,
                 exclude: /node_modules/,
                 use: ['babel-loader'] {},test: /\.css$/,
                use: ['style-loader'.'css-loader'.'postcss-loader'] {},test: /\.less$/,
                use: ['style-loader'.'css-loader'.'postcss-loader'.'less-loader'] {},test: /\.(png|jpg|webp)/,  
                use: ['file-loader'] {},test: /\.(ttf|woff2?) $/,
                type: 'asset/resource'.generator: {
                    filename: 'font/[name].[hash:3][ext]'}}},plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Plug-in use'.template: './index.html'
        }),
        new DefinePlugin({
            BASE_URL: '". /"]}}),Copy the code

CSS extraction and compression

Use the MiniCssExtractPlugin to extract CSS

This plugin extracts CSS into a separate file, creates a CSS file for each JS file containing CSS, and supports on-demand loading of CSS and SourceMaps.

This plug-in is built on new webPack V5 features and requires WebPack 5 to work properly

Compared to the extract-text-webpack-plugin:

  • Asynchronous loading
  • No duplicate compilation (performance)
  • Easier to use
  • Specifically for CSS development
npm install --save-dev mini-css-extract-plugin
Copy the code
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [{test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'.'postcss-loader'] {},test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'.'postcss-loader'.'less-loader']},],},};Copy the code

Note: less and CSS modules must be configured MiniCssExtractPlugin. Loader, becausetest: /.css$/Matching CSS files will only extract CSS modules. In the same waytest: /.less$/Only less files will be matched and only less files will be extracted. So they all have to be configured.

Use the CSS-Minimizer-webpack-plugin to compress CSS

This plugin uses CSSNano to optimize and compress CSS.

It’s like the optimize-CSS-assets-webpack-plugin, but using query strings in Source maps and Assets is more accurate, enabling caching and concurrent mode

$ npm install css-minimizer-webpack-plugin --save-dev
Copy the code
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
  module: {
    rules: [{test: /.s? css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"."sass-loader"],},],},optimization: {
    minimizer: [
      // In webpack@5, you can use '... 'syntax to extend existing minimizer (i.e.,' terser-webpack-plugin '), uncomment the next line
      / / `... `,
      new CssMinimizerPlugin(),
    ],
  },
  plugins: [new MiniCssExtractPlugin()],
};
Copy the code

Note: The compression plug-in function is enabled only in the production environment and does not take effect when mode is set to Development. If you also want to enable CSS optimization in your development environment, use theoptimization.minimizeSet totrue.

Three, Optimization

Scope hositing/devtool/terser: 5K not configured

Devtool/Terser: 4K not configured

Terser /: 3k not configured

Both have 725B configuration

Both are configured to enable tree-shaking: 534B

1. Use the scope collieries

Start Scope collieries:

optimization: {
    concatenateModules: true,},Copy the code

As Scope needs to analyze the dependencies between modules, the source code must adopt ES6 modular statement, or it will not take effect.

Before using scope:

After using scope:

The implementation principle of Scope is actually very simple: analyze the dependency relationship between modules and combine the scattered modules into a function as much as possible, but on the premise that code redundancy cannot be caused. Therefore, only modules that have been referenced once can be merged.

The benefits of this are:

  • Code size is smaller because function declaration statements generate a lot of code;
  • Because the code creates fewer scoped functions at run time, the memory overhead is smaller

To learn about Socpe Hositing, view this article, 4-14 starting Scope Webpack. This indicates that the mode should be turned on during production.

2. sideEffects

Webpack Side effects open:

optimization: {
    sideEffects: true,},Copy the code

This configuration means that WebPack turns on the detection of side effects files.

Json file in the project root directory:

// package.json
"sideEffects": false.Copy the code

“SideEffects “: false, indicating that all files have no sideEffects and can safely discard unused code.

After testing, the detection of side effects appears to be file level.

Here is a file that, if it exports many variables and contains Export Defualt, changes to the file will be treated as if the external file imported one of the exported variables, and none of the code in the file will be deleted.

Only exported variables without any references are marked as side effects by Webpack and the entire file code is removed when packaged.

By extension, if only one of the export codes is referenced externally, then it is a file with no side effects. How can the rest codes be removed?

Use tree-shaking to shake off unused exports. Note that non-export code will not be shaken, such as window. XXX =’ XXX ‘will remain.

In addition to Webpack to check which files have no side effects, you can configure them manually.

"sideEffects": [
    '/src/js/login.js',
    'src/js/api.js'
],
Copy the code

The value in the array is the file path, indicating that the files have no side effects and need not be culled.

CSS introduced in items is generally treated as code with side effects. If you don’t do something special, they’re all thrown out.

import '.. /font/iconfont.css'
Copy the code

Manually configure sideEffects look effect can refer to this article webpack optimized configuration of sideEffects | fragrance tofu の blog

3. Tree-shaking

Js tree – shaking

Js tree shaking is divided into 4 steps:

  1. Code to use ES6 modular writing method to write our business code.

    Tree Shaking can be used to weed out dead code that doesn’t work in JavaScript. It relies on the static ES6 modularity syntax.

  2. Configure Babel to retain ES6 modular statements.

{
  "presets": [["env",
      {
        "modules": false // "modules": false means to turn off Babel's module conversion function and retain the original ES6 modularity syntax.}}]]Copy the code
  1. UsedExports Set this parameter to true

    Mark methods that don’t work

  2. Use JS compression software

Webpack V5 comes out of the box with the latest version of the Terser-Webpack-plugin. If you are using WebPack V5 or later and want to customize the configuration, you still need to install the Terser-webpack-plugin. If you use Webpack V4, you must install the version of Terser-webpack-Plugin V4.

$ npm install terser-webpack-plugin --save-dev
Copy the code
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  optimization: {
    minimize: true.minimizer: [new TerserPlugin()],
  },
};
Copy the code

These steps are basically tree-shaking, but for further refinement see # 4-10 Using Tree shaking

CSS tree – shaking
$ npm install purgecss-webpack-plugin glob -D
Copy the code
const PurgecssPlugin = require('purgecss-webpack-plugin');

module.exports = {
  // Where to configure plug-ins
  plugins: [
    // Create an instance (step 3)
    new PurgecssPlugin({
      // Configure the file to parse (step 4)
      paths: glob.sync(`${path.resolve(__dirname, 'src')}/ * * / * `, {
        nodir: true.// Filter folder results (step 5)})}),]};Copy the code

See: Webpack front-end packaging tools – use purgecss Webpack – plugin remove excess CSS | Roya ‘s Blog

Multiple entry packing

Multi-entry packaging can reduce the packaging volume of the home page.

Multi-entry file packaging:

module.exports = {
  mode: 'none'.entry: {
    index: './src/index.js'.album: './src/album.js'
  },
  // entry: './src/index.js',
  output: {
    filename: '[name].bundle.js'}}Copy the code

splitChunks

The splitChunks function is simply described as controlling webPack to split different files according to the splitChunks Settings when merging files.

Basic usage:

module.exports = {
  / /...
  optimization: {
    splitChunks: {
      chunks: 'async'.minSize: 30000.minChunks: 1.maxAsyncRequests: 5.maxInitialRequests: 3.automaticNameDelimiter: '~'.name: true.cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2.priority: -20.reuseExistingChunk: true}}}}};Copy the code

There is too much to cover here. Refer to the next article.

Or this series:

Understand Webpack 4.splitChunks – Desire to dream – Blog garden

Understand Webpack 4.splitChunks for cacheGroups – Dreaming – Blog garden

Load/magic notes on demand

Loading on demand is simple:

const render = () = > {
    console.log('Hash can't change')
    const mainElement = document.querySelector('.main')
    const hash = window.location.hash || '#post'
    mainElement.innerHTML = ' '
    if (hash === '#post') {
        // Load as needed
        import(/* webpackChunkName: 'post' */'./post').then(post= > {
            console.log(post, 'post... ');
            post['default'](mainElement)
        })
    } else {
        // Load as needed
        import(/* webpackChunkName: 'post' */'./album/album').then(album= > {
            album['default'](mainElement)
        })
    }
}
Copy the code

When webPack is packaged, the files dynamically imported by import() are packaged separately. The first load does not require the network to request this file, thus reducing the size of the first load file.

If the magic comment names are the same, they will be packed together.

Output file name Hash

There are three types of hash in production files

The first is common hash

module.exports = {
  mode: 'none'.entry: './src/index.js'.output: {
    filename: '[name]-[hash].bundle.js'}}Copy the code

Latitude is project-level. If the content of any file in the project changes, the hash value of the generated file changes entirely.

Second: chunkhash

module.exports = {
  mode: 'none'.entry: './src/index.js'.output: {
    filename: '[name]-[chunkhash].bundle.js'}}Copy the code

Changing the contents of the file changes the hash value of the corresponding chunk (all chunks packaged, including CSS and JS).

Contenthash

module.exports = {
  mode: 'none'.entry: './src/index.js'.output: {
    filename: '[name]-[contenthash].bundle.js'}}Copy the code

If the file is changed, the hash of the generated file will change. If the content of the CSS file is changed, the hash value of the PACKED CSS will change.

All Contenthash modes are the best way to cache.