1. The above

Recently, I met a lot of problems about project packaging and webpack. I learned about Webpack in my spare time. Although UNIVERSITY of Utah began to promote Vite recently, the webpack ecosystem is more perfect and stable. The following is the process of my systematic study of Webpack, and here to share, a rookie, I hope to exchange and learn with the big guys.

2. Webpack introduction

Webpack is a front-end resource builder, a static Module bundler. In webpack’s view, all the front-end resource files (JS /json/ CSS /img/less/…) Will be treated as modules. It will perform static analysis according to module dependencies, and package to generate the corresponding static resources (bundle.js).

3. Core concepts of Webpack

3.1 Entry

The Entry indicates which file webPack starts packing as the Entry point, analyzing and building the internal dependency diagram.

3.2 Output (Output)

Indicates where the output of resource bundles packaged by Webpack goes and how to name them.

3.3 Loader

Loader allows Webpack to handle non-javascript files (Webpack only handles JavaScript itself)

3.4 the Plugins

Plugins can be used to perform a much wider range of tasks. Plug-ins range from packaging optimization and compression to redefining variables in the environment.

3.5 Mode

4. Basic use of Webpack

4.1 the initialization

NPM init where the project filename cannot be Chinese

4.2 Downloading the WebPack

NPM install webpack webpack-cli -g

NPM install webpack webpack-cli -d

4.3 packaging

The development environment

webpack ./src/index.js -o ./dist/buddle.js --mode=development
Copy the code

The production environment

webpack ./src/index.js -o ./dist/buddle.js --mode=production
Copy the code

Packaging success

  • Webpack can handle JS files and JSON files by default. In production environments, extra code obfuscates and compresses the code

4.4 Configuration File

  • . Create a new webpack.config.js file in the root directory
  • . In webpack.config.js
const path=require("path")
module.exports={
    // Import file, import file path
    entry:"./src/index.js"./ / output
    output: {// Output the file name
     filename:"bundle.js".// Output path, where absolute path is required
     // this is equivalent to D:\ download \webpacjks\webpack and \dist
     path:path.resolve(__dirname,'dist'),
     // Set this to clear the contents of the last package,
     clean:true
    },
    // Production mode
   mode:'development'
}
Copy the code

4.5 Entering the package command

webpack
Copy the code

5. Use the loader

5.1 CSS packaging

Style packing can be used: cssLoader,styleloader

Download the dependent

npm i less -D
npm i style-loader css-loader less-loader -D
Copy the code
 {
            // Match a rule with a regular expression
            test: /(\.css|\.less)$/,
            use: [
              // Insert the CSS text format into the HTML with the style tag, then perform the CSS rendering
              // Insert the js style into the style tag
              // The array is parsed from bottom to top, in reverse order
              "style-loader".// Convert CSS to JS
              "css-loader".// Convert less to CSS
              "less-loader"],},Copy the code

5.2 CSS Compatibility

Download two packages postCSs-loader postCSs-env - NPM I postCSs-loader postCSs-preset -envCopy the code
//package.json
"browserslist": {
    "development": [
      "last 1 chrome version"."last 1 firefox version"."last 1 safari version"]."production": [
      "0.2%" >."not dead"."not op_mini all"]}Copy the code
//webpack.config.js
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Set the node environment variable. The default is production
process.env.NODE_ENV = "development";
module.exports = {
  entry: "./src/js/index.js".output: {
    filename: "js/bundle.js".path: resolve(__dirname, "dist"),},module: {
    rules: [{test: /\.css$/,
        use: [

          MiniCssExtractPlugin.loader,
          // Convert CSS to JS
          "css-loader"./ / use postcss - loader
          {
            loader: "postcss-loader".options: {
              postcssOptions: {
                ident: "postcss".plugins: () = > [
                  // Help CSS find the configuration in package.json browserslist by loading the specified CSS style
                  require("postcss-preset-env")(),],},},},],},plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",}).new MiniCssExtractPlugin({
      // Rename the packaged CSS and place it in a file
      filename: "css/built.css",})],mode: "development"};Copy the code

5.3 Loading Resources

To load CSV, XML resources, use CSV-loader, XML-loader

npm i csv-loader xml-loader -D
Copy the code
   {
        // Match a rule with a regular expression
        test: /(\.csv|\.tsv)$/,
        use: ["csv-loader"],}, {// Match a rule with a regular expression
        test: /\.xml$/,
        use: "xml-loader",},// Use the import file main.js import
 import xml from "./assets/index.xml"
import csv from "./assets/inde.csv"

let box2 = document.createElement("div");
box2.innerHTML=csv
document.body.appendChild(box2);

let box3 = document.createElement("div");
box3.innerHTML=xml
document.body.appendChild(box3);

Copy the code

5.4 Loading Data

To load jSON5, YAML, and TOMl files, you need yamL-loader, TOML-loader, and jSON5-loader

npm i yaml toml json5-D
Copy the code
//1. Configure in webpack.config.js
{
        test: /\.yaml$/,
        type: "json".parser: {parse: yaml.parse
        }
      },
      {
        test: /\.toml$/,
        type: "json".parser: {
          parse:toml.parse
        }
      },
      
      
 / / 2. The main. Use js
 import yaml from "./assets/index.yaml"
import toml from "./assets/index.toml"
console.log(yaml.languages);
console.log(toml.data);
Copy the code

5.5 the Babel – loader

Convert JS es6 syntax to ES5 syntax

npm i babel-loader @babel/core @babel/preset-env @babel/polyfill core-js -D

npm i @babel/runtime -D

npm i @babel/plugin-transform-runtime -D

Copy the code
// module->rules in webpack.config.js
  {
        test: /\.js$/,
        exclude: /node_modules/,
        use:{
          loader: "babel-loader".options: {
            presets: ["@babel/preset-env"].plugins:[
              [
                '@babel/plugin-transform-runtime'[]},}},Copy the code

6. The use of plugins

6.1 HTML – webpack – the plugin

The installation

 npm i html-webpack-plugin -D
Copy the code
//webapck.config.js
const {resolve}=require('path')
// Import HTML plugins
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
    entry:'./src/main.js'.output: {filename:'bundle.js'.path:resolve(__dirname,'./dist')},mode:'production'.plugins: [new HtmlWebpackPlugin({
            // Here is the path where the HTML file needs to be packaged
            template:'./index.html'.// The name of the packaged HTML file
            filename:'bundle.html'.// Where to put the imported JS, the default is in the head
            inject:'body'}})]Copy the code

6.2 the mini – CSS – extract – the plugin

Out of the CSS

npm i mini-css-extract-plugin -D
Copy the code
// First introduce the plug-in
const MiniCssExtarctPlugin = require("mini-css-extract-plugin");

// instantiate the plug-in
 plugins: [
    new MiniCssExtarctPlugin({
      // The packaged name
      filename: "style/[contenthash].css",})],// Use plugins
  module: {
    // Configure the module resources here, but make sure the images are under assets
    rules: [{// Match a rule with a regular expression
        test: /(\.css|\.less)$/,
        use: [
          // Insert the CSS text format into the HTML with the style tag, then perform the CSS rendering
          // Insert the js style into the style tag
          // Use plugins
          MiniCssExtarctPlugin.loader,
          // Convert CSS to JS
          "css-loader".// Convert less to CSS
          "less-loader",],},},Copy the code

6.3 CSS – minimizer – webpack – the plugin

Compressing obfuscated CSS

npm i css-minimizer-webpack-plugin -D
Copy the code
// Import plug-ins
const CssminimizerWebpackPlugin=require("css-minimizer-webpack-plugin")

// Register plugins. This optimization is at the same level as module plugins, where plugins are not placed in plugins
  optimization: {minimizer: [new CssminimizerWebpackPlugin()
    ]
  }
  
// Change the development environment
  mode: "production"
Copy the code

6.4 terser webpack — the plugin

By default webpack is allowed to confuse JS, but CSS -minimizer-webpack-plugin is not allowed. Another plugin, Terser-webpack-plugin, is required

npm i terser-webpack-plugin -D
Copy the code
  optimization: {
      minimizer: [new CssminimizerWebpackPlugin(),  new TerserWebpackPlugin()],
    },
Copy the code

6.5 webpack – bundle – analyzer

You can analyze webPack dependency modules

> npm i webpack-bundle-analyzer -D
Copy the code
const{ BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')
 plugins: [
    new BundleAnalyzerPlugin()
  ],
Copy the code

7. Webpack performance optimization

7.1 Code Separation

7.1.1 code – spliting

This way is to configure multiple entries and modify the output package file. This way can be packaged into multiple entries and separate the code, but if the project introduces very large packages like Lodash and jquery, as long as it is used once, each entry package will be packaged, resulting in repeated packaging and bloated code

module.exports = {
  entry: {
  // Multi-entry packing
    index:"./src/main.js".another:"./src/js/load.js"
  },
  output: {
  // The name must be dynamic
    filename: "[name].bundle.js".path: resolve(__dirname, "./dist"),
    clean: true,},mode: "production",}Copy the code

7.1.2 Removing public Chunk

To reduce the waste of resources, separate the public package from each entry package to form a new chunk

Method 1: Configure Entry

  entry: {
    index: {import:"./src/main.js".dependOn:'shared'
    },
    // Public package
    another: {import:"./src/js/load.js".dependOn:'shared'
    },
    shared:'lodash'
  },
Copy the code

Mode 2: Configuration optimization

optimization: {
    minimizer: [new CssminimizerWebpackPlugin()],
    // Put common code in a chunk, such as Lodash, jquery packaged separately
    splitChunks: {chunks:'all'}},Copy the code

7.1.3 Dynamic Import

//asyncCpmponent.js
function asyncCpmponent() {
    // Dynamic import
  return import("lodash").then(({ default: _}) = > {
    const element = document.createElement("div");
    element.innerHTML = _.join(["wo"."shi"."ws"]."");
    return element;
  });
}

asyncCpmponent().then((element) = >{
    document.body.appendChild(element)
})

// Import the file in the entry
import "./js/asyncCpmponent.js"
Copy the code

7.2 the source map

When an error occurs, the developer can pinpoint the error code

7.3 watch mode

Every time you run the code, you can detect that js has changed and the WebPCK will restart

/ / input
webpack --watch
/ / instead of
webpack
Copy the code

7.3 webpack – dev – server

The browser can automatically update our files when they change. Webpack-dev-server doesn’t really output physical files, it just puts all the files in memory and executes

npm i webpack-dev-server -D
Copy the code

Start with NPX WebPack Serve. If you start with WebPack Serve, ensure that the local global Webpack version is the latest version

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: "./main.js".output: {
    filename: "buddle.js".path: resolve(__dirname, "./dist"),
    clean: true,},mode: "development".devtool: "source-map".plugins: [
    new HtmlWebpackPlugin({
      template: "./index.html".filename: "index.html",})],devServer: {static:resolve(__dirname,"./dist"),
      // Set whether to compress the code on the server side, reduce the size of the data transferred, and gzip compression
      compress:true.// Change the port number
      port:3000.// Configure the request header file
      headers: {"wx-token":'fvfet4htghrjt123'
      },
      // Local service proxy
      proxy: {'/api':'http://localhost:8080',},/ / configure HTTPS
    // https:true,

      //http2
      https:true.// Redirect when browser access has no routing address, or no proxy is configured
      historyApiFallback:true}};Copy the code

7.4 a lazy loading

The module is not loaded when the page is loaded, while the current module is loaded when the operation is performed

//math.js
export const minus=(a,b) = >a-b
export const add=(a,b) = >a+b
Copy the code
/ / the main use js
let btn = document.createElement("button");
btn.innerHTML = "Click trigger add event";
btn.addEventListener("click".() = > {
// You can change the packaged package name in the comments section
  import(/*webpackChunkName:'math*/"./js/math.js").then(({ add }) = > {
    console.log(add(6.7));
  });
});
document.body.appendChild(btn);
Copy the code

7.5 preload

Pack the module when the browser is idle

7.6 the cache

Optimized by hitting the cache index, the files generated by WebPack are cached by the customer service and updated as updates are obtained

7.6.1 Babel cache

On the second build, the previous cache is read

 {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader".options: {
          presets: [["@babel/preset-env",
              {
                useBuiltIns: "usage".corejs: { version: 3 },
                targets: { chrome: "60".firefox: "50" ,ie:'9'}},]].// Set js's Babel to true when packing
          cacheDirectory:true}},Copy the code

7.6.2 File Resource Caching

Add a 10-bit hash value to the packaged JS

Focus on

● Hash: EACH wepack build generates a unique hash value. Problem: Because JS and CSS use the same hash value. If repackaged, all caches will be invalidated. ● Chunkhash: Hash value generated by chunk. If the package comes from the same chunk, the hash value will be the same. Problem: JS and CSS will still have the same hash value. CSS is in the same chunk because it was introduced in JS. Different files must have different hash values

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/* Cache: Babel cache cacheDirectory: true --> Make the second package build faster file resource cache Hash: generates a unique hash value for each Wepack build. Problem: Because JS and CSS use the same hash value. If repackaged, all caches will be invalidated. Chunkhash: Hash value generated by chunk. If the package comes from the same chunk, the hash value will be the same. Problem: JS and CSS have the same hash value. Since CSS is introduced in JS, it belongs to the same chunk as CONTenthash. Different files must have different hash values -> It is better to use */ to make code run online and cache

// Define the nodeJS environment variable: Determines which environment to use browserslist
process.env.NODE_ENV = 'production';

/ / reuse loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    // You also need to define browserslist in package.json
    loader: 'postcss-loader'.options: {
      ident: 'postcss'.plugins: () = > [require('postcss-preset-env') (the)]}}];module.exports = {
  entry: './src/js/index.js'.output: {
    filename: 'js/built.[contenthash:10].js'.path: resolve(__dirname, 'build')},module: {
    rules: [{// In package.json eslintConfig --> Airbnb
        test: /\.js$/,
        exclude: /node_modules/.// Priority execution
        enforce: 'pre'.loader: 'eslint-loader'.options: {
          fix: true}}, {// The following loader will only match one
        // Note: No two configurations can handle the same type of file
        oneOf: [{test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']},/* Normally, only one loader can process a file. When a file is to be processed by multiple Loaders, it is important to specify the order in which loader executes: esLint before Babel */
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader'.options: {
              presets: [['@babel/preset-env',
                  {
                    useBuiltIns: 'usage'.corejs: { version: 3 },
                    targets: {
                      chrome: '60'.firefox: '50'}}]],// Enable the Babel cache
              // On the second build, the previous cache is read
              cacheDirectory: true}}, {test: /\.(jpg|png|gif)/,
            loader: 'url-loader'.options: {
              limit: 8 * 1024.name: '[hash:10].[ext]'.outputPath: 'imgs'.esModule: false}}, {test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader'.options: {
              outputPath: 'media'}}]}]},plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html'.minify: {
        collapseWhitespace: true.removeComments: true}})].mode: 'production'.devtool: 'source-map'
};

Copy the code

7.6.3 Caching of third-party libraries

Cache the node_modules folder

    optimization: {
      minimizer: [new CssminimizerWebpackPlugin(),  new TerserWebpackPlugin()],
      splitChunks: {cacheGroups: {vendor: {// Here is the path where the third-party package needs to be cached
            test:/[\\/]node_modules[\\/]/.// The file name after chunk packaging
            name:'vendors'.// all chunks
            chunks:'all'}}}},Copy the code

Generate the following files

7.7 HMR

If one module changes, only the current module is packaged, not all modules, and hot module replacement is needed to keep the code consistent with the page. If you change the code, the page will change in time

  devServer:{
    contentBase:resolve(__dirname,'build'),
    // Start GZIP compression
    compress:true.// Local boot port number
    port:3000.// Automatically open the browser
    open:true./ / open HMR
    hot:true
}
Copy the code

  • Style files CSS /less files: HMR functionality can be used by default because style-loader is implemented internally

  • HTML files: By default, the HMR function is disabled and the HTML files cannot be hot updated

  • Js file: the HMR function can not be used by default

Js HMR:

//index.js
if (module.hot) {
  // Once module.hot is true, HMR is enabled. --> Make the HMR function code work
  module.hot.accept('./print.js'.function() {
    // The print.js method listens for changes in the print.js file, and when changes occur, other modules are not repackaged and built.
    // The following callback functions are executed
    print();
  });
}
Copy the code

7.8 Web Workers

The JavaScript language uses a single-threaded model, which means that all tasks can only be done on one thread, one thing at a time. The first task is not finished, the next task has to wait. With the enhancement of computer computing ability, especially the emergence of multi-core CPU, single thread brings great inconvenience and can not give full play to the computing ability of the computer.

The function of Web Worker is to create a multithreaded environment for JavaScript, allowing the main thread to create Worker threads and assign some tasks to the latter to run. While the main thread is running, the Worker thread is running in the background without interfering with each other. Wait until the Worker thread completes the calculation and returns the result to the main thread. The advantage of this is that when computationally intensive or high-latency tasks are taken on by Worker threads, the main thread (usually responsible for UI interactions) will flow smoothly and will not be blocked or slowed down.

Once a Worker thread is created, it is always running and is not interrupted by activity on the main thread, such as a user clicking a button or submitting a form. This facilitates communication that responds to the main thread at any time. However, this also causes the Worker to consume resources, so it should not be overused and should be closed once it is used.

Based on using

//app.js
const worker=new Worker(new URL("./work.js".import.meta.url))
worker.postMessage({
    question:'hello ws'
})
worker.onmessage=message= >{
    console.log(message.data.name);
}
Copy the code
//work.js
self.onmessage=message= >{
// This accepts data posted from app.js
    console.log(message)
    self.postMessage({
        name:'ws'})}Copy the code

7.9 the tree – shaking

Tree shaking in Webapck is a very good performance optimization operation, it is not introduced in the project and not used packages are all packaged into the packaged file, is a good performance optimization

// Configure in webpack.connfig.js
optimization: {usedExports:true
}

Copy the code

7.10 sideEffects

Tell WebPack that currently written code has no side effects, and that webPack cannot tree-shaking remove files with side effects

//package.json

// All files have side effects, do not delete files
sideEffect:true

// All files have no side effects, delete files
sideEffect:false

// The specified file has side effects. The specified file is not deleted
sideEffect: ['*.css]

Copy the code

7.11 PWA

When the network is down, pages can still be loaded, which is equivalent to caching pages and optimizing them

Add serviceWork 7.11.1

/ / install workbox - webpack - the plugin
npm i workbox-webpack-plugin -D
Copy the code
//webpack.config.js
const { resolve } = require("path");
const WorkboxPlugin=require("workbox-webpack-plugin")
module.exports = {
  entry: "./main.js".output: {
    filename: "buddle.js".path: resolve(__dirname, "./dist"),
    clean: true,},mode: "development".devtool: "source-map".plugins: [
     new  WorkboxPlugin.GenerateSW({
      / / enable serviceWorks
      clientsClaim:true.// Jump out of current serviceWorks and disallow old serviceWorks
      skipWaiting:true})]};Copy the code

7.11.2 registered serviceWork

//main.js
if('serviceWorker' in navigator){
    window.addEventListener('load'.() = >{
    // Service-worker. js is a packaged file, so we need to run webapck to package it
        navigator.serviceWorker.register('/service-worker.js')
        .then(res= >{
            console.log('Registration successful'+res);
        }).catch(err= >{
            console.log('Registration failed'+err); })})}Copy the code

npx webpack serve

Turning off the service still prints, so the page content is cached by the browser

7.12 DLL

Use DLL technology for some libraries (third-party libraries: jquery, React, vue…) Packaged separately, when you run Webpack, the default is to look for the webpack.config.js configuration file

* You need to run the webpack.dlL. js file

// Create webpack.dll. Js in the SRC folder
const { resolve } = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    [name] --> jquery
    // ['jquery'] --> The library is jquery
    jquery: ['jquery'],},output: {
    filename: '[name].js'.path: resolve(__dirname, 'dll'),
    library: '[name]_[hash]' // What is the name of the contents exposed in the packaged library
  },
  plugins: [
    // Package to generate a manifest.json --> provide and jquery mapping
    new webpack.DllPlugin({
      name: '[name]_[hash]'.// The exposed content name of the mapping library
      path: resolve(__dirname, 'dll/manifest.json') // Output file path})].mode: 'production'
};

Copy the code
Run webpack --config webpack.dill.jsCopy the code
/ / download
npm i add-asset-html-webpack-plugin -D
Copy the code
//webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js'.output: {
    filename: 'built.js'.path: resolve(__dirname, 'build')},plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // Tell Webpack which libraries are not included in the package, and change their names when used
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname, 'dll/manifest.json')}),// Package a file and import the resource automatically in HTML
    new AddAssetHtmlWebpackPlugin({
      filepath: resolve(__dirname, 'dll/jquery.js')})],mode: 'production'
};

Copy the code

directory

7.13 shimming

Shimming can globally import third-party packages so that they can be used without having to import packages in files, and in some modules this does not refer to window. In commonJs modules this does not refer to window, so you need to change the reference of this to import third-party packages

7.13.1 Setting Global Variables

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
// WebPack is introduced here
const webpack=require('webpack')
module.exports = {
  entry: "./src/main.js".output: {
    filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),},mode: "development".plugins: [
    new HtmlWebpackPlugin({
      // Here is the path where the HTML file needs to be packaged
      template: "./index.html".// The name of the packaged HTML file
      filename: "bundle.html".// Where to put the imported JS, the default is in the head
      inject: "body",}).new webpack.ProvidePlugin({
        _:'lodash'})]};Copy the code
//src/main.js
// This can be used without introducing Lodash
console.log(_.join(['ws'.'love'.'qy'].'_'))
Copy the code

7.13.2 Fine particle size

If this is included in an imported third-party package, it may not point to the window, so you need to change the this point

Use imports – loader

 npm i  imports-loader -D
Copy the code
module: {rules:[
         {
            test: require.resolve('./src/main.js'),
            use: 'imports-loader? wrapper=window',}}]Copy the code

7.13.3 Global exposure

Use exports – loader

 npm i  exports-loader -D
Copy the code
  module: {rules:[
         {
            test: require.resolve('./src/main.js'),
            use: 'imports-loader? wrapper=window'}, {test: require.resolve('./src/golobalWays.js'),
            // Use the exports-loader, which is of type commonJs, to expose attributes one by one,
            // Expose an object with multiple. The second argument is the object's property value/method, and the third argument is the object's property/method name
            use: 'exports-loader? type=commonjs&exports=ws,multiple|files.output|output',}}]Copy the code

8. Resource module

File directory

Resource is used to package exported images in PNG and JPG formats, inline is used to export images in BASE64 formats such as SVG, and source is used to export source code

//webpack.config.js
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: "./src/main.js".output: {
    filename: "bundle.js".path: resolve(__dirname, "./dist"),
    clean: true.// You can also enter the name of the packaged assets file
    assetModuleFilename: "images/[contenthash][ext]",},mode: "production".plugins: [
    new HtmlWebpackPlugin({
      // Here is the path where the HTML file needs to be packaged
      template: "./index.html".// The name of the packaged HTML file
      filename: "bundle.html".// Where to put the imported JS, the default is in the head
      inject: "body",})],devServer: {
    contentBase: resolve(__dirname, "dist"),
    // Start GZIP compression
    compress: true.// Local boot port number
    port: 3000.// Automatically open the browser
    open: true,},module: {
    // Configure the module resources here, but make sure the images are under assets
    rules: [{test: /\.png$/,
        type: "asset/resource".generator: {
          filename: "images/[contenthash][ext]",}}, {// Inline will not be packaged into the dist directory
        test: /\.svg$/,
        type: "asset/inline"}, {//source is used to read data
        test: /\.txt$/,
        type: "asset/source"}, {//source is used to read data
        test: /\.jpg$/,
        type: "asset".parser: {
        // Beyond this maximum value, base64 is converted
          dataUrlCondition: {
            maxSize: 25 * 1024,},},},],},};Copy the code

After the configuration is complete, import resources as modules

//main.js
const { add } = require("./js/add.js");
import img from "./assets/line.png";
import svg from "./assets/egg.svg";
import txt from "./assets/index.txt"
console.log(add(1.6));

//resource
let img1 = document.createElement("img");
img1.src = img;
document.body.appendChild(img1);

//inline
let img2 = document.createElement("img");
img2.src = svg;
document.body.appendChild(img2);

//source
let box = document.createElement("h1");
box.textContent=txt
document.body.appendChild(box);
Copy the code

By default, WebPack will load the resource size. When the resource size is less than 8K, it will generate a base64 link, which is inline mode. If the resource size is greater than 8K, it will switch to resource mode. This 8K is adjustable and requires a parser to be configured under webpack.config.js-module-rules

How to load the iconfont font

You can load fonts in Webpack using the type: Resource configuration

//1. Configure it under module->rules
 {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: "asset/resource"
      }
      
//2. Add it to the CSS
@font-face {
    font-family: 'iconfont'; src: url(.. /assets/iconfont.ttf) format('truetype');
}
.icon{
    font-family: 'iconfont';
    font-size: 30px;
}

//3. Use fonts in main.js
/ / introduction
import './style/index.css'
let box1 = document.createElement("h1");
/ / use
box1.className='icon'
box1.innerHTML='&#xe8ab'
document.body.appendChild(box1);

Copy the code

9. Split production and development environments

9.1 Common Path

output: {
    filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),
    clean: true.// You can also enter the name of the packaged assets file
    assetModuleFilename: "images/[contenthash][ext]".// Configure the public path
    publicPath:'http://localhost:8080/'
  },
Copy the code

When you pack it, the path will add this path

9.2 Environment Variables

You need to know whether the user is in production or development

module.exports = (env) = > {
  return {
  entry: {
      index: "./src/main.js".another: "./src/js/load.js",},output: {
      filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),
      clean: true.// You can also enter the name of the packaged assets file
      assetModuleFilename: "images/[contenthash][ext]".publicPath: "http://localhost:8080/",},// Determine what environment the user entered
    mode: env.production ? "production" : "development",}}Copy the code

9.3 WebPack File Splitting

// The public module webpack.common.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtarctPlugin = require("mini-css-extract-plugin");
const toml = require("toml");
const yaml = require("yaml");
module.exports = {
  entry: {
    index: "./src/main.js".another: "./src/js/load.js",},output: {
    path: path.resolve(__dirname, ".. /dist"),
    clean: true.// You can also enter the name of the packaged assets file
    assetModuleFilename: "images/[contenthash][ext]",},plugins: [
    new HtmlWebpackPlugin({
      // Here is the path where the HTML file needs to be packaged
      template: "./index.html".// The name of the packaged HTML file
      filename: "bundle.html".// Where to put the imported JS, the default is in the head
      inject: "body",}).new MiniCssExtarctPlugin({
      // The packaged name
      filename: "style/[contenthash].css",})],module: {
    // Configure the module resources here, but make sure the images are under assets
    rules: [{// Match a rule with a regular expression
        test: /(\.css|\.less)$/,
        use: [
          // Insert the CSS text format into the HTML with the style tag, then perform the CSS rendering
          // Insert the js style into the style tag
          // The array is parsed from bottom to top, in reverse order
          MiniCssExtarctPlugin.loader,
          // Convert CSS to JS
          "css-loader".// Convert less to CSS
          "less-loader",]}, {// Match a rule with a regular expression
        test: /(\.csv|\.tsv)$/,
        use: ["csv-loader"],}, {// Match a rule with a regular expression
        test: /\.xml$/,
        use: "xml-loader"}, {test: /\.png$/,
        type: "asset/resource".generator: {
          filename: "images/[contenthash][ext]",}}, {// Inline will not be packaged into the dist directory
        test: /\.svg$/,
        type: "asset/inline"}, {//source is used to read data
        test: /\.txt$/,
        type: "asset/source"}, {//source is used to read data
        test: /\.jpg$/,
        type: "asset".parser: {
          dataUrlCondition: {
            maxSize: 25 * 1024,},},}, {test: /\.yaml$/,
        type: "json".parser: {
          parse: yaml.parse,
        },
      },
      {
        test: /\.toml$/,
        type: "json".parser: {
          parse: toml.parse,
        },
      },

      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: "asset/resource"}, {test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: "asset/resource"}, {test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader".options: {
            presets: ["@babel/preset-env"].plugins: [["@babel/plugin-transform-runtime"],},},},],},optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendors".chunks: "all",},},},},};Copy the code

Development Environment Configuration

//webpack.config.dev.js
const { resolve } = require("path");
module.exports = {
  output: {
    filename: "scripts/[name].js",},mode: "development".devServer: {
    contentBase: resolve(__dirname, "dist"),
    // Start GZIP compression
    compress: true.// Local boot port number
    port: 3000.// Automatically open the browser
    open: true,},devtool: "inline-source-map"};Copy the code

Production Environment Configuration

//webpack.config.prod.js
const CssminimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
module.exports = {
  output: {
    filename: "scripts/[name].[contenthash].js".publicPath: "http://localhost:3000/",},mode: "production".optimization: {
    minimizer: [new CssminimizerWebpackPlugin(), new TerserWebpackPlugin()],
  },

  performance: {
    hints: false,}};Copy the code

Combine public, production, and development environments using Webpack-Merage

npm i webpack-merage -D

const { merge } = require("webpack-merge");
const commonfig = require("./webpack.config.common");
const devfig = require("./webpack.config.dev");
const prodconfig = require("./webpack.config.prod");

module.exports = (env) = > {
  switch (true) {
    case env.development:
      return merge(commonfig, devfig);
    case env.production:
      return merge(commonfig, prodconfig);
    default:
      return new Error("error"); }};Copy the code

Change the package.json run path

 "scripts": {
    "start": "webpack serve --config ./config/webpack.config.js --env development"."build": "webpack -c ./config/webpack.config.js --env production"
  },
Copy the code

10. Webpack configuration

10.1 Alias the Wepack file path

  resolve: {
    // Configure the path
    alias: {
      "@": resolve(__dirname, "./serve"),},// Configure the extension so that the extension can be omitted from the project
    extensions: [".json".".js".".vue"],},Copy the code

10.2 External WebPack extensions

When we need to reduce the size of the bundle, we need to import files using CDN, such as jquery.

//webpack.config.js
// Indicates that the script tag is inserted
  externalsType: "script".externals: {
    // The first element is the link that needs to be placed in the HTML
    // The second element is an object that script exposes to the browser, in this case $
    jquery: ["https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"."$"],},Copy the code

11. Build a multi-page app

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: {
    Lodash is a public package that needs to be removed to form a chunk
    main: {
      import: "./src/main.js".dependOn: "lodash".filename: "files1/[name].[contenthash].js",},main1: {
      import: "./src/main1.js".dependOn: "lodash".filename: "files2/[name].[contenthash].js",},lodash: {
      import: "lodash".filename: "commonFile/[name].[contenthash].js",}},output: {
    // Enter the folder directory
    path: resolve(__dirname, "./buddle"),
    // The last directory can be cleaned up after packaging again
    clean: true,},mode: "development".plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index1.html".// The title here can be retrieved directly in HTML via ejS templates
      title: "Multi-page applications".// Where to put the defined script, body or head
      inject: "body".// Which JS packages are loaded on the current page
      chunks: ["main"."lodash"].// Set the file name after packaging
      filename: "files1/index1.html",}).new HtmlWebpackPlugin({
      template: "./src/index2.html".// The title here can be retrieved directly in HTML via ejS templates
      title: "Multi-page applications".// Where to put the defined script, body or head
      inject: "body".// Which JS packages are loaded on the current page
      chunks: ["main1"."lodash"].// Set the file name after packaging
      filename: "files2/index2.html",})]};Copy the code
// This is unique to the html-webpack-plugin<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
    
</body>
</html>
Copy the code

12. Module federation

12.1 Basic Introduction

Microfront-end introduces the concept of microservices into front-end development. Rather than developing an application or site as a whole, the focus is on breaking it down into smaller pieces that are individually programmed and then tied together at run time.

In this way, other parts of the application can be developed using different technologies and developed by separate teams. , splitting development in this way avoids the maintenance costs associated with traditional units.

As a side effect, it enables new types of collaboration between back-end and front-end developers, as they can work as a cohesive team to focus on specific parts of the application. For example, you can have a team focus only on the search function or other critical business parts around the core function.

Starting with WebPack 5, there are built-in capabilities for developing microfronts. The modules combine and give you enough functionality to handle the workflow required for the microfront approach.

Mode of module sharing:

12.2 Basic Model

The traditional way of sharing code

Micro front-end

Module federal

Module federation, which allows me to introduce components from project b into project a, is a big new feature of webpack5

12.3 Specific Usage

There is a HomeList component in the home field. There is a header component in the nav field. The requirement is to include the header component of the nav field in the home field. The Serach project introduces the Homelist component in the home project and the Header component in the nav project

1. Expose the Header component in the NAV project

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {ModuleFederationPlugin}=require('webpack').container
module.exports = {
  entry: "./index.js".output: {
    filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),},mode: "development".plugins: [
    new HtmlWebpackPlugin(),
    new ModuleFederationPlugin({
        // Identifies the name of the module federation, which is required if the external needs to import that part of the component
        name:'nav'.// Remote entry, where the current item is online
        filename:'remoteEntry.js'.// Reference components exposed by other applications
        remotes:{

        },
        // The exposed components can be used by other applications
        exposes: {// Key represents the path URL that other applications will use to concatenate this component in the future
            // The last value is the component path that the current application needs to expose
            // The./Header can be used in other modules to find the current module
        './Header':'./src/header.js'
        },
        // Third-party shared modules, such as Lodash,jquery
        shared:{}})],};Copy the code

2. Run the home project using webpack-dev-serve

npx webpack serve –port 3002

3. Introduce the header component of the nav project in the home project and expose its own Homelist component

const HtmlWebpackPlugin = require("html-webpack-plugin");
const {ModuleFederationPlugin}=require('webpack').container
module.exports = {
  entry: "./src/index.js".mode: "development".plugins: [
    new HtmlWebpackPlugin(),
    new ModuleFederationPlugin({
      // Identifies the name of the module federation, which is required if the external needs to import that part of the component
      name:'home'.// Remote entry, where the current item is online
      filename:'remoteEntry.js'.// Reference components exposed by other applications
      remotes: {// In another application, the module federally defines the name after nav
        //nav is the address to import the application
        // remoteentry. js is the filename from which the application is introduced
          nav:'nav@http://localhost:3003/remoteEntry.js'
      },
      // The exposed components can be used by other applications
      exposes: {// Key represents the path URL that other applications will use to concatenate this component in the future
          // The last value is the component path that the current application needs to expose
      './Homelist':'./src/HomeList.js'
      },
      // Third-party shared modules, such as Lodash,jquery
      shared:{}})],};Copy the code
//home/src/index.js
// Asynchronous import is used here
import HomeList from "./HomeList.js";
import("nav/Header").then((Header) = > {
  let box = document.createElement("div");
  box.appendChild(Header.default());
  document.body.appendChild(box);
  box.innerHTML += HomeList(4);
});

Copy the code

4. Run the nav project using webpack-dev-serve with the same port number as the remote that introduced webpack.config.js in the project

npx webpack serve –port 3003

5. The Search project introduces the configuration of the above two projects


const HtmlWebpackPlugin = require("html-webpack-plugin");
const {ModuleFederationPlugin}=require('webpack').container
module.exports = {
  entry: "./src/index.js".mode: "development".plugins: [
    new HtmlWebpackPlugin(),
    new ModuleFederationPlugin({
           // Identifies the name of the module federation, which is required if the external needs to import that part of the component
           name:'search'.// Remote entry, where the current item is online
           filename:'remoteEntry.js'.// Reference components exposed by other applications
           remotes: {// In another application, the module federally defines the name after nav
            //nav is the address to import the application
            // remoteentry. js is the filename from which the application is introduced
              nav:'nav@http://localhost:3003/remoteEntry.js'.home:'home@http://localhost:3002/remoteEntry.js'
          },
           // The exposed components can be used by other applications
           exposes:{
          
           },
           // Third-party shared modules, such as Lodash,jquery
           shared:{}})],};Copy the code
// Reference and use components. Here we introduce two components, promise.all

// Use promise.all to load the two asynchronous components separately
Promise.all([import('nav/Header'), import('home/Homelist')]).then(([
    // Export the default option in the component
    {
        default: Header

    },
    {
        default: Homelist
    }
]) = > {
    document.body.appendChild(Header())
    document.body.innerHTML+=Homelist(6)})Copy the code

6. Run the search project with webpack-dev-serve

npx webpack serve –port 3001

13. To summarize

Through the systematic study of Webpack5, I have mastered many improvements in front-end performance. This article is based on the systematic study of the official website. If there are any deficiencies, please give me your advice