For a qualified front-end development engineer, it is only a basic requirement to complete the demand development of business functions, and to be able to find the performance bottleneck in the system in time and accurately, and give appropriate solutions, which is the important basis to distinguish the primary, intermediate and senior front-end engineers.

I won’t go into much detail here about what Webpack is, and if you don’t already know, this article is not for you now.

Webpack link, come back and read on when you’re done

Basic configuration of WebPack5

Let’s start with a basic configuration, based on the WebPack5 webpack.config.js file.

/* * webpack.config.js */ const { resolve } = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); Module. Exports = {// mode mode: "development", // export: "./ SRC /index.js", // output: {filename: "Build.js ", path: resolve(__dirName, "build"), // Customize output static resource file name (image) assetModuleFilename: "Assets /[hash][ext]",}, // Module: {rules: [// Loader configuration {test: /\.css$/, // use the loader to process the file /** * use the array from right to left and from bottom to top */ use: ["style-loader", "css-loader"],}, {test: ["style-loader"],}, {test: /\.less$/, use: [" class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader ", / \. (PNG | SVG | JPG jpeg | | GIF) $/, / / webpack 5 built-in resource type, have been abandoned before the url - loader and file - loader type: "asset/resource,"}, {test: }, {// exclude // exclude // exclude // exclude // exclude // exclude / \. | | js | (HTML CSS less | PNG | SVG | JPG | jpeg | GIF) $/ I type: "asset/resource,"},],}, / / plugins plugins: [// HtmlWebpackPlugin // Creates an empty HTML file by default and automatically introduces all the resources that are packaged. // Requires a structured HTML file. "./ SRC /index.html",}),], /** * Download yarn add webpack-dev-server --dev * Run NPX webpack serve */ devServer: ContentBase: resolve(__dirname, "build"), // Open the browser automatically: true, // port number: 5555, // open gzip compress: true, }, };Copy the code

The above code is the basic code for this article and is the basis for the configuration of the remaining packaging optimizations.

HMR hot update

Hmr-hot Module replacement enables modules to be replaced, added, or removed while the application is running, without the need to reload the entire page.

Advantages:

  1. Retain application state that was lost during a complete page reload.
  2. Update only the changes to save valuable development time.
  3. When CSS/JS changes are made in the source code, they are immediately updated in the browser, which is almost the equivalent of devTools directly changing styles in the browser.

The problem pictures

As you can see from the figure above, when we changed the style, our JS file was re-executed, which was a problem for our project. Our optimization direction was to change that file, and only that file was reloaded.

code

Based on the above problem, we only need to change the code at devServer.

/* * webpack.config.js */ ... module.exports = { ... ContentBase: resolve(__dirname, "build"), // Open the browser automatically: true, // port number port: // Open the gZIP compress: true, // add --> open hot update // The module hot replace function replaces, adds or removes modules while the program is running without reloading the entire page. hot: true, }, };Copy the code

Effect of picture

Devtool source debugging mode

Choose a Source Map format to enhance the debugging process. Different values can significantly affect the speed of build and rebuild.

  1. Source code debugging for the development environment

    Eval-source-map – Is slow to initialize the source map, but provides a faster rebuild time and generates the actual file. The number of lines maps correctly because it maps to the original code. It produces a source map of the best quality for the development environment.

  2. Source debugging for production environments

    (None) (omit the devTool option) – No source map is generated. It’s a good choice.

Rule-oneof Matching Rule

Loader matching rules.

/* * webpack.config.js */ ... module.exports = { ... // Module: {rules: [// Loader configuration {oneOf: [// The following loaders will execute the matching file only once. {test: /\.css$/, // use the loader to process the file /** * use the array from right to left and from bottom to top */ use: ["style-loader", "css-loader"],}, {test: ["style-loader"],}, {test: /\.less$/, use: [" class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader "," class-loader ", "class-loader ", / \. (PNG | SVG | JPG jpeg | | GIF) $/, / / webpack 5 built-in resource type, have been abandoned before the url - loader and file - loader type: "asset/resource,"}, {test: }, {// exclude // exclude // exclude // exclude // exclude // exclude /\.(html|js|css|less|png|svg|jpg|jpeg|gif)$/i, type: "asset/resource", }, ], }, ], }, ... }Copy the code

Written this way, loader matches at packaging time will be faster.

The file cache

In the production environment, we can cache our packaged CSS and JS resources into the browser to speed up our second page entry. So we need to configure webpack.config.js, and configure caching of js files and CSS files and image files.

First we need to download the following loader:

yarn add babel-loader @babel/core @babel/preset-env mini-css-extract-plugin --dev

Optimization steps

  1. Extract the CSS file from the package file into a separate file.
  2. Use Babel caching for JS files.

Extract CSS and cache file resources

/* * webpack.config.js */ ... // add const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { ... // Production mode: "production", output: {filename: "Built.[Contenthash :10].js",... },... {test: /\.css$/, // Replace style-loader with use: [MiniCssExtractPlugin.loader, "css-loader"], }, { test: /\.less$/, use: [/ / will replace MiniCssExtractPlugin style - loader loader, "CSS - loader", "less - loader,"], / / new js loader {},... the test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], // Enable the Babel cache // For the second build, the previous cache will be read // to cache the loader's execution result. CacheDirectory: true,},},},],},],}, // New MiniCssExtractPlugin({filename: "CSS /built.[Contenthash :10].css",}),],};Copy the code
  1. Hash: A unique hash value is generated each time the WePack is built.

    • Problem: Because js and CSS use the same hash value.
    • If repackaged, all caches will be invalidated. (Maybe I only changed one file)
  2. Chunkhash: Indicates the hash value generated based on the chunk. If the package is from the same chunk, then the hash value is the same.

    • Problem: The hash values of js and CSS are the same
    • Since CSS was introduced in JS, it belongs to the same chunk
  3. Contenthash: Generates a hash value based on the contents of the file.

    • Different files must have different hash values, which makes caching easier to use when code is running online.

Add jSloader and set cache

/* * webpack.config.js */ ... module.exports = { ... // Module: {rules: [// loader configuration {oneOf: [... // add js loader {test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], // Enable the Babel cache // For the second build, the previous cache will be read // to cache the loader's execution result. CacheDirectory: true,},},},],},... };Copy the code

Next we write the test code. Create a new server.js file and create a new server to test. Download the Express framework.

yarn add express --dev

/* * server.js */ const express = require("express"); const server = express(); Server.use (express.static("build", {maxAge: 1000 * 3600})); Server.listen (5555, () => {console.log(" Server started successfully! ") , "http://localhost:5555/"); });Copy the code

Check the cache step

  1. Do webPack webpack
  2. Start the server node server.js
  3. http://localhost:5555/

Effect of picture

Tree Shaking removes unwanted code

Use the premise

  1. You must use ES6 modularity
  2. Opening up the production environment

Advantages: When packaging the production environment, we can ignore our unused code and remove our unused code from the package file, reducing the size of the package file.

As long as we meet the previous two premises, WebPack automatically removes invalid code while packaging.

Add test files

/*
* testTreeShaking.js
*/
export const test1 = () => {
  console.log("test1");
};

export const test2 = () => {
  console.log("test2");
};
Copy the code

Modify the file

/* * index.js */ ... import { test1 } from "./testTreeShaking"; test1(); // The test2 function is not introduced. Ignored when packing.Copy the code
/* * webpack.config.js */ ... module.exports = { ... // Modify the packaging mode mode: 'production',... };Copy the code

In the package. The json configuration

/* * ackage.json */ "sideEffects": "SideEffects ": ["*.css", "*.less"] ["*.css", "*.less"]Copy the code

Webpack package, view the package file as shown below:

As you can see, the test2 function is not packaged into the package file.

Code Split Code Split

There are three types of code segmentation:

  1. Multiple entry files are automatically code split
  2. Optimization. splitChunks controls code splitting
  3. Optimization.splitchunks + import() for code segmentation

Advantage: Code splitting can effectively prevent js files from being too large.

Multiple entry files are automatically code split

/* * webpack.config.js */ ... module.exports = { ... / SRC/testtreeshaking. js", test: "./ SRC/testtreeshaking. js",}... };Copy the code

Webpack packaging check effect, as shown below:

Optimization. splitChunks controls code splitting

/* * webpack.config.js */ ... module.exports = { ... // new code optimization: {/* 1. Node_modules can be packaged as a chunk. Automatically analyze whether there are public files in the multi-entry chunk. If any is packaged as a single chunk */ splitChunks: {// This indicates which chunks will be selected for optimization. When a string is provided, valid values are all, async, and initial. // Setting to all can be particularly powerful because it means that chunks can be shared between asynchronous and non-asynchronous chunks. chunks: "all", }, }, ... };Copy the code

Webpack packaging check effect, as shown below:

Optimization.splitchunks + import() for code segmentation

/* * webpack.config.js */ ... module.exports = { ... // new code optimization: {/* 1. Node_modules can be packaged as a chunk. Automatically analyze whether there are public files in the multi-entry chunk. If any is packaged as a single chunk */ splitChunks: {// This indicates which chunks will be selected for optimization. When a string is provided, valid values are all, async, and initial. // Setting to all can be particularly powerful because it means that chunks can be shared between asynchronous and non-asynchronous chunks. chunks: "all", }, }, ... };Copy the code
/* * index.js */ /* Use javascript code to package a file as a chunk import: */ import("./testTreeShaking").then((res) => {console.log("res", res); res.test1(); });Copy the code

Webpack packaging check effect, as shown below:

Lazy file loading Preloads files

The difference between

  1. Use reloading of files
  2. The browser is loaded first when it is idle

Modify the file

/* *index.html */ ... <button id=" BTN "> Load testTreeShaking file </button>...Copy the code
/* *index.js */ console.log(" load index file ");Copy the code
/* *testTreeShaking.js */ export const test1 = () => { console.log("test1"); }; export const test2 = () => { console.log("test2"); }; Console. log(" load index file ");Copy the code

Lazy file loading

/* *index.js */ console.log(" load index file "); Document.getelementbyid (" BTN ").onclick = function () {document.getelementByid (" BTN ").onclick = function () { Import ("./testTreeShaking").then(({test1}) => {test1(); }); };Copy the code

Lazy loading renderings

preload

/* *index.js */ console.log(" load index file "); Document.getelementbyid (" BTN ").onclick = function () {// prefetch: // Normal loading can be considered parallel loading (multiple files loaded at the same time) // Prefetch: Import (/* webpackPrefetch: true */ "./testTreeShaking").then(({ test1 }) => { test1(); }); };Copy the code

Preloading renderings

PWA progressive Web applications

PWA can be used for many things. The most important of these is the ability for the application to continue running functionality while offline. This is done using a Web technology called Service Workers.

Taobao PWA renderings

Add the workbox-webpack-plugin, then adjust the webpack.config.js file:

yarn add workbox-webpack-plugin --dev

Modify the webpack. Config. Js

/* * webpack.config.js */ ... // add const WorkboxWebpackPlugin = require("workbox-webpack-plugin"); // add const WorkboxWebpackPlugin = require("workbox-webpack-plugin"); module.exports = { ... / / plugins plugins: [new plug-ins... / / new WorkboxWebpackPlugin GenerateSW ({/ * 1. Help serviceworker quick start 2. Delete the old serviceworker generated a serviceworker Configuration file ~ */ clientsClaim: true, skipWaiting: true,}),],};Copy the code

Registration Service Worker

/* * index.js */ /* the code must run on the server --> nodejs --> NPM server */ / register serviceWorker // handle compatibility issues if ("serviceWorker" in Navigator) { window.addEventListener("load", () => {navigator.serviceworker.register ("/service-worker.js").then() => {console.log("sw register successfully ~"); }). Catch (() => {console.log("sw registration failed ~"); }); }); }Copy the code

Next we will copy the previous server.js file and use it directly:

  1. You pack it first
  2. Nodeserver.js Starts the server
  3. http://localhost:5555/

Check the PWA effect image

Multiprocess packaging

yarn add thread-loader --dev

Modify the webpack.config.js file:

/* * webpack.config .js */ ... module.exports = { ... // Module: {rules: [// loader configuration {oneOf: [... // add js loader {test: /\.js$/, exclude: /node_modules/, use: [/* add code to enable multiprocess packaging. It takes about 600ms to start a process, and there is a process communication cost. Multiprocess packaging is required only if the work takes a long time. {// Number of workers generated, default is (number of CPU cores - 1), or, // rollback to 1 workers if require(' OS ').cpus() is undefined: },},...],},],},... };Copy the code

You can see the effect by running WebPack, which takes more than 600ms to launch and is suitable for projects with larger code volumes.

Multiprocess packaging renderings are not enabled

Start multiprocess packaging renderings

externals

Instead of packaging imported packages into bundles, you retrieve external dependencies at runtime.

Modify the webpack.config.js file to add the externals attribute

/*
* webpack.config.js
*/
...
module.exports = {
...
  externals: {
    jquery: "jQuery",
  },
};
Copy the code

Select JQ’s CDN link and add it to index.html

Free CDN address

/* * index.html */ <! DOCTYPE html> <html lang="zn"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, Initial-scale =1.0" /> <title> WebPack optimization </title> <! New code -- -- -- > < script SRC = "https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js" > < / script > < / head > < body > < h1 > webpack Packaging optimization < / h1 > < div class = "color_1" > < / div > < div class = "color_2" > < / div > < img SRC = ". / img/zp. JPG "/ > < / body > < / HTML >Copy the code
/*
* index.js
*/
import $ from "jquery";
console.log("$", $);
Copy the code

Webpack packaging for testing.

Effect of picture

Dll Dynamic link library

“We’re able to split bundles, and we’re able to significantly speed up the build process.” The term “DLL” stands for the dynamic link library originally introduced by Microsoft.

Add webpack.dll.js file to configure DllPlugin separately.

/* * webpack.dll.js */ const { resolve } = require("path"); const webpack = require("webpack"); Module. Exports = {entry: {// module.exports = {name] --> dllFile // ['jquery', 'lodash'] --> jquery lodash dllFile: ["jquery", "lodash"], }, output: { filename: "[name].js", path: resolve(__dirname, "dll"), library: "[name]_[hash]", // what is the name of the package library that is exposed to the outside}, plugins: New Webpack.dllPlugin ({name: "[name]_[hash]", // map the library's exposed content name path: Resolve (__dirname, "DLL /manifest.json"),], mode: "production",};Copy the code

Run webpack –config webpack.dll.js to execute this file, and generate the following file:

Modify the webpack. Config. Js file configuration DllReferencePlugin AddAssetHtmlWebpackPlugin.

Download yarn add –dev add-asset-html-webpack-plugin

/* * webpack.config.js */ ... // add const webpack = require("webpack"); const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin"); module.exports = { ... Plugins: [new code /... / / / tell webpack which libraries do not participate in the packaging, use at the same time also have to change the name of the ~ new webpack. DllReferencePlugin ({manifest: Resolve (__dirname, "DLL/manifest. Json"),}), / / will be output to a file, packaging, and automatically bring the resources in the HTML new AddAssetHtmlWebpackPlugin ({filepath: Resolve (__dirName, "DLL/dllfile.js "), outputPath:" DLL ", // If set, will be used as the output directory of the file. "DLL ", // if set, will be used as a public path for script or link tags.Copy the code

Modify the index.js file to test:

/*
* index.js
*/
...
import $ from "jquery";
console.log("$--->jquery", $);
import _ from "lodash";
console.log("_---->lodash", _);
Copy the code

Run WebPack for packaging. Generate the following files:

Check the running effect

This is the end of the theory of WebPack packaging optimization, in fact, there are many points about packaging, welcome to comment in the comments section, we grow together!!

If you want to see the source code, click here to get it

Next is the packaging practice.