Webpack overview

What is a Webpack

Webpack is a moudule bundler for modern JS applications. Webpack is one of the most popular module packaging tools available today. 英 文 名 称 : webpack.docschina.org/

Why use Webpack

  • New features such as ES Modules have environmental compatibility issues
  • Too many module files and frequent network requests affect efficiency
  • All front-end resources need to be modular

The first two problems can be achieved using a series of modular tools, while all front-end resource modularization cannot be achieved with a general modular tool. We needed a tool to solve these problems in a unified way, and it was the WebPack packaging tool.

In summary, we use the WebPack packaging tool to address the modularity of the front-end’s overall resources, not just JavaScript modularity.

Core Webpack concepts

  • Entry
  • Output
  • Loader
  • Plugins
  • Mode
  • Module
  • Dependency Graph

Entry: The first source file accessed during packaging. The default is SRC /index.js (which can be specified in the configuration file), and Webpack loads the dependencies for the entire project through the portal.

Output: The name of the packaged Output file, dist/main.js by default (can be specified through the configuration file)

Loader: a tool designed to process a class of files (not JS). Webpack default can only identify JS file, want to handle other types of files, need corresponding loader, such as (CSS – loader | HTML – loader | file – loader). The suffix is -loader. Commonly used loaders: www.webpackjs.com/loaders/

Plugins: Implements functions other than loader.

  • Plugin is the backbone of WebPack and is used to implement rich functionality
  • The name is xxx-webpack-plugin(for example, html-webpack-plugin) with the suffix -webpack-plugin
  • Common plug-in: www.webpackjs.com/plugins/

Loaders and Plugins are essentially NPM packages.

Mode: The key used to distinguish the environment. Different environments have different packaging logic, so you need to differentiate. Three modes:

  • Development (automatically optimize packaging speed, add some assistance in debugging process)
  • Production (automatic optimization of packaging results)
  • None (Runs raw packaging without doing any extra processing)

Module: In Webpack, the concept of Module is relatively broad, everything is a Module.

  • JS module
  • A CSS
  • A picture
  • A font file

Details: www.webpackjs.com/concepts/mo…

Dependency Graph: Webpack loads file dependencies for the entire project starting from the entry file. The Dependency Graph is the Dependency Graph.

Webpack best practices

Initialize the project

mkdir myproject

cd myproject

npm init -y
Copy the code

Install Webpack

#Partial installation is recommended
npm install -D webpack webpack-cli
#Global installation, not recommended, will lock the webpack in your project to the specified version,
#And in projects that use different versions of WebPack, it can lead to build failures
npm install -G webpack webpack-cli
Copy the code

Create the entry file myproject/ SRC /index.js

Perform packaging (mode must be specified, NPM version must be at least 5)

npx webpack ./src/index.js --output-path ./dist --mode=development
Copy the code

Webpack version

Webpack4 was released in February 2018

Webpackage 5 was released in October 2020

Pay attention to installation commands (Default installation 5)

npm install webpack -D # webpack5

npm install webpack@4 -D #webpack4

Adding a Configuration File

If all parameters are set using the command line, the command line will be very long, hard to type, and error prone. Therefore, it is easier to use the default Settings file. In the future, we will also configure in the configuration file to achieve the desired effect.

  • Configuration files are used to simplify command-line options

    Before the configuration:

    npx webpack ./src/index.js --output-path ./dist --mode=development
    Copy the code

    After the configuration:

    npx webpack
    Copy the code
  • The default configuration file name is webpack.config.js

    • Webpack.config. js is organized under the CommonJS specification
    • Most of the process of working with Webpack is dealing with configuration files

Configuration details: www.webpackjs.com/configurati…

Common configuration items:

  • Mode (mode)
  • Entry
  • Output = output
  • Module (module configuration a different type of file configuration a loader configuration)
  • Plugins
  • Devserver (Development server configuration)

Best practice in the project, create a file, myproject/webpack config. Js

Content as follows:

const path = require('path')

module.exports = {
  mode: 'development'.entry: './src/index.js'.output: {
    filename: 'bundle.js'.path: path.join(__dirname, 'output')},module: {
    rules: [// Add the loader processing rule here
      / / {
      // test: /\.css$/i,
      // use: ['style-loader', 'css-loader']
      / /}]},// Development server
  devServer: {},// Plug-in configuration
  plugins: []}Copy the code

To implement packaging, rerun the packaging command:

npx webpack
Copy the code

Webpack basis

Packaging CSS

Packaging logic

  • Non-js file packaging, the corresponding loader
    • Css-loader converts CSS to JS (outputs CSS to a packaged JS file)
    • Mount the JS code containing the CSS content to the page<style>The label of
  • The introduction of CSS
    // Call the CSS module in the js file
    import "./css/main.css"
    Copy the code
  • Install the loader
    npm i css-loader style-loader -D
    Copy the code
  • Configuration webpack. Config. Js
    • Matching suffix name:
    // Indicates that the re matches case-insensitive files ending in.css
    test: /\.css$/i.Copy the code
    • Specify loader:
    // The loader called first comes later
    use: ['style-loader'.'css-loader']
    Copy the code

Pack less

The packaging logic is similar to the above:

  • The introduction of less
    // Call the less module in the js file
    import "./css/main.less"
    Copy the code
  • Install the loader
    npm i less less-loader -D
    Copy the code
  • configuration
    • Matching suffix name:
    // Matches case-insensitive files ending in. Less
    test: /\.less$/i.Copy the code
    • Specify loader:
    // The loader called first comes later
    use: ['style-loader'.'css-loader', less-loader]
    Copy the code

Package as a separate CSS file

Sometimes we don’t want to mount CSS styles into the

  • Installing a plug-in
    npm i mini-css-extract-plugin -D
    Copy the code
  • Introducing plug-ins (in webpack.config.js)
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    Copy the code
  • replacestyle-loader(in webpack.config.js)
    use: [MiniCssExtractPlugin.loader, 'css-loader']
    Copy the code
    • Style-loader: packages the CSS to<style>In the label
    • MiniCssExtractPlugin. Loader: packaged CSS into separate files
  • Configure the plug-in (in webpack.config.js)
    // Plug-in configuration
    plugins: [
      new MiniCssExtractPlugin({
        filename: 'css/[name].css' // Package the file to the CSS folder with the same file name})]Copy the code

    Detailed configuration information about the Mini-CSS-extract-Plugin can be found on the NPMJS website:www.npmjs.com/package/min…

Add style prefix

  • The installation
    npm install postcss-loader autoprefixer -D
    Copy the code
  • Configuration webpack. Config. Js
    use: [MiniCssExtractPlugin.loader,'css-loader'.'postcss-loader']
    Copy the code
  • Configuration postcss. Config. Js
    plugins: [require('autoprefixer')]
    Copy the code
  • The configuration requires compatible browsers
    • Method 1: Specify browserslist in package.json (recommended)
      "browserslist": [
        "last 1 version".// Latest version
        "1%" >            // Represents browsers that are used by more than 1% of the world
      ]
      Copy the code

      For details:www.npmjs.com/packaee/bro…

    • Method two, create a.browserslistrc file in the project root directory
      last 1 version
      > 1%
      Copy the code

Format check

  • The installation

    npm i stylelint stylelint-config-standard stylelint-webpack-plugin -D
    Copy the code
    • stylelint

      There are many validation rules, such as number-teading-zero: line-height:.5; // error line-height: 0.5; // Stvlelint. IO /

    • stylelint-config-standard

      Rule set, which contains validation rules used by many large companies, can be found on Github: github.com/stvlelint/s…

    • stylelint-webpack-plugin

      Stylelint webpack plugin webpack.docschina.org/plugins/stv…

  • The introduction of webpack. Config. Js

    const StylelintPlugin = require('stylelint-webpack-plugin');
    Copy the code
  • Configure the plug-in webpack.config.js

    // Plug-in configuration
    plugins: [
      new StylelintPlugin({
        // Specify the file to be formatted
        files: ['src/css/*.{css,less,sass,scss}'"})"Copy the code
  • Specify a validation rule (specify stylelint in package.json)

    "stylelint": {
      "extends":"stylelint-config-standard"."rules": {// Custom rules
        //"number-teading-zero": "never"}}Copy the code

    Designation is now available in three ways. According to the order of loading:

    • The stylelint property in package.json specifies rules
    • Specify rules in.stylelintrc
    • Specify rules in stylelint.config.js

    Here we recommend the first one

Compress CSS

  • The installation
    npm install optimize-css-assets-webpack-plugin -D
    Copy the code
  • The introduction of webpack. Config. Js
    const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    Copy the code
  • Configure the plug-in webpack.config.js
    plugins: [
      new OptimizeCssAssetsPlugin()
    ]
    Copy the code

Packaging HTML

Packaging HTML files requires the use of the html-webpack-plugin, which is responsible for:

  • Generate HTML files (for server access) and load all packaged resources in HTML
  • Specify HTML templates, set HTML variables, and compress HTML

Use process:

  • The installation
    npm i html-webpack-plugin -D
    Copy the code
  • The introduction of webpack. Config. Js
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    Copy the code
  • Configure the plug-in webpack.config.js
    plugins: [
      new HtmlWebpackPlugin({
      // Specify the packaged HTML name
      filename: 'index.html'.// Create using an HTML template
      // template: './src/index.html',
      // Specifies the variables to be used in the HTML template, which can be called using EJS template engine syntax
      // title: 'webpack Demo',
      // Set HTML compression, usually only when mode: 'production'
      minify: {
          collapseWhitespace: true.keepClosingSlash: true.removeComments: true.removeRedundantAttributes: true.removeScriptTypeAttributes: true.removeStyleLinkTypeAttributes: true.useShortDoctype: true}}),// Package other HTML files
      new HtmlWebpackPlugin({
      // Specify the packaged HTML name
      filename: 'about.html'.// Create using an HTML template
      // template: './src/about.html',
      // Specifies the variables to be used in the HTML template, which can be called using EJS template engine syntax
      // title: 'about Demo'})]Copy the code

Detailed method of use: www.npmjs.com/package/htm…

EJS official website: EJs.bootcss.com

Packaging JS

translation

Translation Purpose:

Convert ES6+ to ES5 to ensure compatibility with older browsers.

  • The installation
    npm install babel-loader @babel/core @babel/preset-env -D
    #If an error'Unrecognized markup exists in source text', use the following command
    # npm install babel-loader '@babel/core' '@babel/preset-env' -D
    Copy the code

    @babel/core contains a set of conversion plugins, and ‘@babel/ PRESET -env’ is a conversion rule set that contains the latest conversion rule for each version.

  • Configuration webpack. Config. Js
    module: {
      rules: [{test: /\.m? js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader'.options: {
              presets: [['@babel/preset-env', { targets: "defaults"}]],plugins: ['@babel/plugin-proposal-class-properties'}}}]}Copy the code

    See:www.npmjs.com/package/bab…

However, @babel/preset-env can only be used to paraphrase basic grammars (promise can’t), and we can use @babel/polyfill to paraphrase all new JS grammars. However, this approach has the disadvantage of translating all the new syntax, making the translated file too large. So, we need to use core-js.

  • @ Babel/polyfill installation

    npm i @babel/polyfill -D
    #If an error'Unrecognized markup exists in source text', use the following command
    # npm i '@babel/polyfill' -D
    Copy the code
  • @babel/polyfill reference (referenced in entry file)

    import '@babel/polyfill'
    Copy the code
  • The core – js installation

    npm i core-js -D
    Copy the code
  • Core-js configuration (in webpack.config.js)

    • annotation@babel/polyfillreference
    // Without commenting out, @babel/polyfill will still translate any new syntax
    // import '@babel/polyfill'
    Copy the code
    • Load useBuiltIns on demand: ‘usage’
    • Corejs: 3 // The version number can be seen in package, JSON
    module: {
      rules: [{test: /\.m? js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader'.options: {
              presets: [['@babel/preset-env', 
                  {
                    useBuiltIns: 'usage'.corejs: 3.//targets: "defaults" 
                    // Manually specify compatible browser versions
                    targets: {
                      Chrome: '58'.ie: '9'.firefox: '60'.safari: '10'.edge: '17'}}]],plugins: ['@babel/plugin-proposal-class-properties'}}}]}Copy the code

JS code format verification

  • The installation

    npm i eslint eslint-config-airbnb-base eslint-webpack-plugin eslint-plugin-import -D
    Copy the code
    • Eslint (tool for validating JS code formats)

      Liverpoolfc.tv: eslint.org/

    • Eslint-config-airbnb-base (the most popular JS code format specification)

      Package is introduced: www.npmjs.com/package/esl…

      Specification details: github.com/airbnb/java…

    • Eslint-webpack-plugin (eslint plugin for Webpack)

      Usage: www.npmjs.com/package/esl…

    • eslint-plugin-import

      Use to read the eslintConfig configuration item in package.json

  • configuration

    • eslint-webpack-plugin

      Introduce in the entry file:

      const ESLintPlugin = require('eslint-webpack-plugin");
      Copy the code

      Configure in webpack.config.js:

      plugins: [
        new ESLintPlugin({
          // Automatically resolve regular code formatting errors
          fix: true})]Copy the code

      Ignore the format verification of the next line of code, just add the following comment //eslint-disable-next-line before the corresponding error line

    • EslintConfig (configured in package.json)

      “eslintConfig”: {“extends”: “airbnb-base”}

Packaging pictures

  • file-loader

    Copy the images to the output directory. Do not copy the images that are not needed.

    • Image file import
    // Import the image file in the relevant JS file
    import img from './file.png'
    Copy the code
    • The installation
    npm i file-loader -D
    Copy the code
    • Configuration (in webpack.config.js)
    module: {
        rules: [{test: /\.(png|jpe? g|gif)$/i,
            loader: 'file-loader'.options: {
              name: '[name].[ext]'.// [name] preserves the original file name, and.[ext] preserves the original suffix
              outputPath: 'images'// Output to a separate directory}}}]Copy the code

    PS: as set above, when exporting images to a separate directory, the CSS file will call the URL () function, which may cause the image cannot be loaded. This is because the path is changed. We only need to set the processing part of less and CSS

    // less
    use: [MiniCssExtractPlugin.loader, 'css-loader'.'postcss-loader'.'less-loader']
    // css
    use: [MiniCssExtractPlugin.loader, 'css-loader'.'postcss-loader']
    Copy the code

    to

    // less
    use: [{loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '.. / '}},'css-loader'.'postcss-loader'.'less-loader'
         ]
    // css
    use: [{loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '.. / '}},'css-loader'.'postcss-loader'
         ] 
    Copy the code

    Configuration details: www.npmjs.com/package/fil…

  • url-loader

    A website contains a variety of large and small files, if each file to request it will cause inefficiency, slow page loading. In this case, we can use urL-loader to process file resources.

    Url-loader can set the following processing principles:

    • Files smaller than a certain size are packaged intoData URLsFormat of the URL
    • If a file is larger than a certain size, the file loader is invoked to process it

    Data URLs are special URL protocols that represent files. The contents of the file are in the URL. In this way, you can reduce browser requests. The format of Data URLs is as follows:

    Let me give you two quick examples.

    The contents of the HTML file can be expressed as:

    data:text/html; charset=UTF-8,<h1>html content<h1>Copy the code

    The content of the image file can be expressed as:

    data:image/png; base64,iVBORwKGgoAAANSUhE... SuQmCCCopy the code

    How to install and configure url-loader? Here are the answers:

    • The installation
    npm i url-loader -D
    Copy the code
    • Configuration (in webpack.config.js)

    Replace the file-loader configuration part with the following configuration:

    module: {
      rules: [{test: /\.(png|jpe? g|gif)$/i,
          loader: 'url-loader'.options: {
            limit: 10 * 1024.// Files smaller than 10KB are converted to Data URLs strings
            // files larger than 10KB are processed by calling file-loader
            name: '[name].[ext]'.// [name] preserves the original file name, and.[ext] preserves the original suffix
            outputPath: 'images'// Output to a separate directory}}}]Copy the code

    Configuration details: www.npmjs.com/package/url…

  • html-loader

    When the image tag in the HTML code has a SRC attribute, we find that the SRC content in the packaged HTML file is not processed, which will cause the image cannot be loaded. Therefore, we need htML-loader to handle it. The html-loader is used to export THE HTML content as a string, which is imported into the IMG and processed by the URL-loader.

    • The installation
    npm i html-loader -D
    Copy the code
    • Configuration (in webpack.config.js)
    module: {
      rules: [{test: /\.(png|jpe? g|gif)$/i,
          loader: 'url-loader'.options: {
            limit: 10 * 1024.// Files smaller than 10KB are converted to Data URLs strings
            // files larger than 10KB are processed by calling file-loader
            name: '[name].[ext]'.// [name] preserves the original file name, and.[ext] preserves the original suffix
            outputPath: 'images'.// Output to a separate directory
            // Url-loader uses ES Modules by default, but htMl-loader uses CommonJS to import images, which will cause parsing errors
            // Resolve: Disable ES Modules of urL-loader and force CommonJS to be used
            esModule: false}}, {test: /\.(htm|html)$/i,
          loader: 'html-loader'.options: {
            // Webpack4 just set esModule: false in url-loader
            // Webpack5 also needs to be set in html-loader
            esModule: false}}}]Copy the code

    Configuration details: www.npmjs.com/package/htm…

    Html-loader applies to static HTML. Html-loader conflicts with htMl-webpack-plugin for HTML-required EJS syntax and cannot implement EJS syntax.

  • Conflicts between html-loader and html-webpack-plugin

    Cause: the html-webpack-plugin will check whether any other loader processes THE HTML file. After the html-loader processes the HTML file, the html-webpack-plugin will not process the HTML file, resulting in the invalid EJS syntax effect.

    Solution: Do not use HTMl-loader, in HTML image reference to use EJS syntax representation.

    <img src="<%= requires('./images/telephone.png') %>" alt="telephone.png">
    Copy the code

Summary: Static HTML can be processed by HTMl-loader. If EJS syntax is required, htML-Loader should be disabled, image reference path in HTML file should be changed to EJS syntax representation, and htML-webpack-plugin should be used to process static HTML

Packaged font

  • The font file

    It can be downloaded from alibaba vector library: www.iconfont.cn/

  • file-loader

    File -loader is also used to package font files.

    • The installation
    npm i file-loader -D
    Copy the code
    • Configuration (in webpack.config.js)
    module: {
        rules: [{test:/\.(eot|svg|ttf|woff|woff2)$/i,
            loader: 'file-loader'.options: {
              name: 'fonts/[name].[ext]'.Fonts, [name] for the original file name,.[ext] for the original suffix}}}]Copy the code

    PS: If the font file is exported to a separate directory, the CSS file will call the url() function, which may cause the font file cannot be loaded. This is because the path is changed. We only need to set the processing part of less and CSS

    // less
    use: [MiniCssExtractPlugin.loader, 'css-loader'.'postcss-loader'.'less-loader']
    // css
    use: [MiniCssExtractPlugin.loader, 'css-loader'.'postcss-loader']
    Copy the code

    to

    // less
    use: [{loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '.. / '}},'css-loader'.'postcss-loader'.'less-loader'
         ]
    // css
    use: [{loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '.. / '}},'css-loader'.'postcss-loader'
         ] 
    Copy the code

Copy files that do not need processing

copy-webpack-plugin

Other files that do not need to be processed can be copied directly to the output directory using copy-webpack-plugin.

Details: www.npmjs.com/package/cop…

  • The installation
    npm install copy-webpack-plugin -D
    Copy the code
  • Configuration (in webpack.config.js)
    const CopyPlugin = require("copy-webpack-plugin");
    
    module.exports = {
      plugins: [
        new CopyPlugin({
          patterns: [{from: "source".to: "dest" },// from source file/folder path to target file/folder path
            { from: "other".to: "public"},],}),],};Copy the code

Delete history files before packaging

clean-webpack-plugin

Details of use: www.npmjs.com/package/cle…

  • The installation
    npm install clean-webpack-plugin -D
    Copy the code
  • Configuration (in webpack.config.js)
    const { CleanWebpackPlugin } = require('clean-webpack-plugin'); Module.exports = {plugins: [new CleanWebpackPlugin(),],};Copy the code

Asset Modules

The resource module, a new feature of webpack5, is a module type that allows resource files to be used without the need to configure additional loaders.

Resource files include: fonts, images, ICONS, HTML, and more.

Features: Images and fonts can be loaded without file-loader or URl-loader

The official document: webpack.docschina.org/guides/asse…

  • Asset/Resource sends a single file and exports the URL (previously implemented with file-loader)

  • Asset /inline Exports a resource’s dataURL (previously implemented using url-loader)

  • Asset /source Exports source code for the resource (previously implemented using raw-loader)

  • Asset automatically selects between exporting a dataURL and sending a separate file (previously implemented using url-loader)

    • Configuration (in webpack.config.js)

      Some configurations of file-loader and url-loader will be modified. The test file does not need to be changed.

      // Package the font configuration
      {
        test:/\.(eot|svg|ttf|woff|woff2)$/i,
        type: asset,
        parser: {
          dataUrlCondition: {
            // If not set, maxSize defaults to 8KB
            // Call asset/resource over 8KB
            < 8KB call asset/inline
            maxSize: 8 * 1024}},generator: {
          filename: 'fonts/[name][ext]'[ext] [ext] [ext] [ext] [ext] [ext]}},// Package the image configuration
      {
        test: /\.(png|jpe? g|gif)$/i,
        type: asset,
        // Omit the maxsize setting here, use the default 8KB, if you need to change the font related part of the above Settings
        generator: {
          filename: 'images/[name][ext]'// Output images to a separate directory, unlike file-loader, leaving the suffix [ext] instead of.[ext]}},Copy the code

Dev Server

webpack dev server

  • Purpose: To publish Web services and improve development efficiency

  • Details:

    www.npmjs.com/package/web…

    Webpack.docschina.org/configurati…

  • The installation

    npm i webpack-dev-server -D
    Copy the code
  • Configuration (in webpack.config.js)

    // Development server
    devServer: {
      // Specify the path to load the content, usually the packaged output path
      contentBase: resolve(__dirname, 'output'),
      // Enable gzip compression
      compress: true.// Hot update, webpack4
      // hot: true,
      // Automatic update, webpack5, disable HOT
      liveReload: true.// Server port number
      port: 9200
      // Configure proxy to resolve cross-domain problems
      proxy: {
        'api': {/ / said to http://localhost:9200/api for processing
          / / replace such as http://localhost:9200/api/users, replaced by https://api.github.com/api/users
          target:'https://api.github.com'.Path to replace / / domain name, http://localhost:9200/api/users with https://api.github.com/users
          pathRewrite: {
            '^/api': ' '.// indicates '/ API 'at the beginning of the matching path.
          },
          // Do not use localhost:9200 as github host name
          changeOrigin: true}}},// Configure the target
    target: "web".Copy the code
  • Server startup command

    Webpack4:

    npx webpack-dev-server
    Copy the code

    Webpack5:

    npx webpack serve
    Copy the code

    As long as the code content is modified and saved, the webpage effect can be automatically updated instantly in the browser website http://localhost:9200/, which improves the development efficiency.

Webpack advanced

Differentiate packaging environment

In the actual work process, we need to set different packaging configuration according to different environments. For example, the production environment needs to set the code compression, but the development environment does not need to set the code compression, because it is difficult to read the code after compression.

There are two ways to distinguish environments: by environment variables and by configuration files.

  • Distinguished by environment variables

    • Setting environment variables on the command line:

      #Set env.production without assigning default totrue
      # webpack 4
      npx webpack --env.production
      # webpack 5
      npx webpack --env production
      Copy the code
    • Check env in webpack.config.js

      Read the environment variable env.production and specify different configurations based on the environment variable

      // Change the parameter to the arrow function
      module.exports = (env, argv) = > {
        // Development environment configuration
        const config = {
          mode: 'development'.// More configuration...
        }
        if (env.production) {
          // Production environment configuration
          config.mode = 'production'.// More configuration...
        }
        
        return config
      }
      Copy the code
    • Switch back to the development environment configuration package

      #Set env.production to an empty string
      # webpack 4
      npx webpack --env.production=""
      # webpack 5
      npx webpack --env production=""
      
      
      Copy the code

    Details: www.webpackjs.com/guides/envi…

  • Distinguish by configuration file

    1. Install WebPack-Merge (used to merge multiple configurations together).

      npm i webpack-merge -D
      Copy the code

      Details of use: www.npmjs.com/package/web…

    2. Create two configuration files: webpack.dev.conf.js and webpack.prod.conf.js, write the required configuration in the development environment and production environment respectively, extract the common configuration parts of them, create webpack.base.conf.js and write. webpack.base.conf.js

      // Public configuration section
      Copy the code

      webpack.dev.conf.js

      // Development environment configuration section
      const { merge } = require('webpack-merge')
      const baseWebpackConfig = require('./webpack.base.conf')
      
      const devWebpackConfig = merge(baseWebpackConfig, {
        // Configuration for development mode...
      })
      module.exports = devWebpackConfig
      Copy the code

      webpack.prod.conf.js

      // Production environment configuration section
      const { merge } = require('webpack-merge')
      const baseWebpackConfig = require('./webpack.base.conf')
      
      const prodWebpackConfig = merge(baseWebpackConfig, {
        // The configuration of production mode...
      })
      module.exports = prodWebpackConfig
      Copy the code
    3. Specify configuration files for different environments when performing packaging.

      #The development environment
      npx webpack --config webpack.dev.conf.js
      #The production environment
      npx webpack --config webpack.prod.conf.js
      Copy the code

      It can also be configured in package.json to simplify the command:

      "scripts": {
          "dev": "npx webpack --config webpack.dev.conf.js"."prod": "npx webpack --config webpack.prod.conf.js"
      },
      Copy the code

      packaging

      #Development environment packaging
      npm run dev
      #Production environment packaging
      npm run prod
      Copy the code

A custom plugin

The Webpack plug-in is a Javascript object with the Apply method. The apply method is invoked by the webpackcompiler and the compiler object is accessible throughout the compile life cycle.

Functionality is extended by mounting functions in lifecycle hooks.

  • The life cycle

    The life cycle is the key point in the whole life process. Program life cycle: initialize -> Mount -> Render -> Show -> Destroy

  • hook

    A hook is a function buried ahead of time where additional functionality is possible. Functions in the lifecycle are hooks. Webpack common hook: www.webpackjs.com/api/compile…

    hook describe type
    environment Environment ready SyncHook
    compile Compile the start SyncHook
    compilation Compile the end SyncHook
    emit Package resources before output AsyncSeriesHook
    afterEmit After the resource is packaged to output AsyncSeriesHook
    done Packaging complete SyncHook

    The code that needs to be manipulated must be added to the emit or previous hook.

The basic flow of a custom plugin:

  1. Create plugin folder in project root directory, create my-plugin.js file and write code
    class MyPlugin {
      constructor(options) {
        console.log('Plug-in options', options)// If you have configuration options, you can do it here
      }
    
      // Must have the apply method
      apply(compiler) {
        compiler.hooks.emit.tap('MyPlugin'.(compilation) = > {
          // compilation is the context for this compilation
          // Here is what you need to do
          console.log('Webpack build process begins', compilation)
        })
      }
    }
    
    module.exports = MyPlugin
    Copy the code
  2. Reference and configure in webpack.config.js
    const MyPlugin = require('./plugin/my-plugin')
    
    module.exports = {
      plugins: [
        new MyPlugin({
          // Pass in the configuration item]}}),Copy the code

Details: webpack.docschina.org/concepts/pl…

Custom loader

Loader is essentially an ES Module that exports a function that transforms packaged resources.

Now we make a loader that reads the contents of the markdown(.md) file

  1. Installing related packages

    npm i marked loader-utils -D
    Copy the code

    Marked (convert markdown syntax to HTML), loader-utils (accept loader configuration items)

  2. Create a loader folder in the project root directory, create markdown-loader.js, and write relevant codes

    const { getOptions } = require('loader-utils');
    const marked = require('marked')
    
    // To customize the loader, you are advised to use common functions
    module.exports = function(source) {
      // Get loader configuration options for easy processing
      const options = getOptions(this)
      // Process the input
      const html = marked(source)
      // Generally, loaders need to return JS code unless it is returned to the next loader
      // return 'module.exports = ${(JSON.stringify(html))}'
      // return to the next loader for processing
      return html
    }
    Copy the code
  3. Create a new test.md file in the SRC directory and write the contents

    Topic #I love the ChineseCopy the code
  4. Make the MD file reference in index.js

    import MDtest from './test.md'
    
    console.log(MDtest)
    Copy the code
  5. Reference and configure in webpack.config.js

    {
          test:/\.md$/i,
          use: ['html-loader', {
            loader: './loader/markdown-loader.js'.options] : {}}}Copy the code

If a custom loader is used independently, ensure that the JS code is output at the end. If multiple custom Loaders are used continuously, ensure that the JS code is output by the last loader

Code Spilitting

If you pack all the code together, you can end up with a very large code file, which affects load time; Moreover, much of the code is not needed for initial loading: therefore, we can slice and package the code up and load it on demand, depending on how urgent it is to use it.

There are three ways to separate code:

  • Multiple entry packing
  • Extract common modules
  • Dynamic import

Multi-entry packing method

In webpack. Config. Js:

  • Configure entry (write object later)
    entry: {index:'./src/index.js'.about:'./src/about.js'},
    Copy the code
  • Configure output.filename (cannot be written as a fixed name, otherwise an error is reported)
    output: {
      // filename: 'bundle.js',
      filename: '[name].bundle.js'.path: path.join(__dirname, 'output')},Copy the code
  • Configure HtmlWebpackPlugin (different pages load their own bundles)
    // HtmlWebpackPlugin configureindex. HTML
    // indicates that index.html loads index.bundle.js
    chunks: ['index']
    // HtmlWebpackPlugin configures the about.html section
    // indicates that about.html loads about.bundle.js
    chunks: ['about']
    Copy the code

Extract the public module mode

If multiple pages use a common file (such as jQuery), it doesn’t make sense to package the common file once for each page. A better approach would be to extract public files.

For example: Jingdong has more than 1000000 product pages. If the 1000000 packaged files all contain jQuery, the packaged files will exceed 80G (88KB*1000000).

We just need to set the following in webpack.config.js:

// Extract the public files and pack them separately
optimization: {
  splitChunks: {
    chunks:'all'}},Copy the code

Dynamic import mode

Dynamic import is divided into two modes:

  • Lazy loading

    By default, it is not loaded until the event is triggered. Lazy loading can be implemented with code like the following

    document.getElementById('btn').onclick = () = > {
      // The wp.js file will be imported only after the click event is triggered
      import('./wp').then(
        alert(This is a dynamic import))}Copy the code

    Wp.js can be loaded lazily, but the file name of the wp.js package is not controlled, so we need to add a command to set the loading name.

    document.getElementById('btn').onclick = () = > {
      // The wp.js file will be imported only after the click event is triggered
      // Specify the packaged name of wp.js to be desc.bundle.js with the /* webpackChunkName: 'desc' */ comment
      import(/* webpackChunkName: 'desc' */'./wp').then(
        alert('This is lazy loading.'))}Copy the code
  • preload

    Just add a comment command implementation on top of lazy loading

    document.getElementById('btn').onclick = () = > {
      // The wp.js file will be imported only after the click event is triggered
      // Specify the packaged name of wp.js to be desc.bundle.js with the /* webpackChunkName: 'desc' */ comment
      // Specify preload mode with the /* webpackPrefetch: true */ comment
      import(/* webpackChunkName: 'desc', webpackPrefetch: true */'./wp').then(
        alert('This is preloading.'))}Copy the code

    The effect of preloading is to wait for other resources to load and then load when the browser is idle. This is a nice effect that reduces the loading time required for event triggering compared to lazy loading.

    Cons: Compatibility issues on mobile

Source Map

  • What is a SourceMap

    SourceMap is a mapping technique between source code and built code. The.map file is used to establish a mapping between the built code and the source code.

  • Why sourceMap

    Built code is hard to locate when something goes wrong. With sourceMap, problem code can be quickly sussed

  • How do I generate sourceMap

    Add configuration in webpack.config.js

    // There are 13 mapping modes for webPack4 and 26 mapping modes for Webpack5
    // Different modes correspond to different effects, we choose source-map here, the actual production will not use this mode
    devtool: 'source-map'
    Copy the code

  • How to choose the right mapping pattern (Personal advice – not absolute)

    • Development environment (eval-cheap-module-source-map)
    • The production environment (none | nosources – source – the map)

SourceMap does not take effect. You need to confirm two conditions: 1. 2. Whether to enable source-map Settings in browser (default)

Tree Shaking

Tree Shaking removes dead code and returns the rest. Unreferenced code contains:

  • Declare only unused functions
  • Only the unused code is introduced

As shown above, dependencies are trees, unused code is like redundant leaves, and using Tree Shaking to “shake down the redundant leaves” makes code leaner, smaller, and thus faster to load.

Prerequisite:

  • Tree Shaking is performed using Modules with the ES Modules specification
  • Tree Shaking relies on static parsing in ES Modules

How to use:

  • Production mode: Tree Shaking starts automatically
  • Development mode: usedExports and sideEffects are available

usedExports

  1. Configure usedExports (to flag useless code)

    In webpack. Config. Js

    optimization: {
      // Flag useless code
      usedExports: true,},Copy the code
  2. Use the Terser-webpack-plugin (remove useless code)

    • The installation

      Webpack 5 does not need to be installed. Webpack 4 needs to be installed separately

      npm i terser-webpack-plugin -D
      Copy the code
    • Configuration (in webpack.config.js)

      const TerserPlugin = require('terser-webpack-plugin')
      
      optimization: {
        // Delete the unused Harmony export XXXXX flag
        minimize: true.minimizer: [new TerserPlugin()]
      },
      Copy the code

    Details: www.npmjs.com/package/ter…

Tree Shaking has compatibility issues with Source Map

The eval mode of the Source Map outputs JS as a string (not the ES Modules specification), causing Tree Shaking to fail. Therefore, use the Source Map at the same time, the model can only specify the Source – the Map | inline – Source – the Map | hidden – Source – the Map | nosources – one of the Source – the Map

sideEffects

No side effects: if a module simply imports and exports variables, it has no side effects

Side effects: There are side effects if a module also modifies other modules or something global. Examples include modifying global variables, extending methods on prototypes, and the introduction of CSS.

SideEffects removes unused modules that have no sideEffects.

SideEffects:

  • Enable side effects (configured in webpack.config.js)
    optimization: {
      // Turn on side effects
      sideEffects: true,},Copy the code
  • Identify if the code has side effects (configured in package.json)
    // false, indicating that all code has no side effects (tells Webpack it can safely remove unused exports)
    // true, indicating that all code has side effects
    / / array, tell webpack which modules have side effects, not to delete, such as ` ['. / SRC/wp. Js', '*. CSS'] `
    "sideEffects": false.Copy the code

The cache

Sometimes we change only a small part of the content and then repackage it. If everything was repackaged, it would be very inefficient, but with caching technology, the unchanged content is read directly from the cache and only the changed parts are packaged, which is much more efficient.

The WebPack setup page for caching is relatively simple:

  • Babel cache

    In webpack.config.js, for setting babel-loader, add a cacheDirectory: true property to the options object

    {
      test: /\.m? js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader'.options: {
          // The second and subsequent builds read the previous cache
          cacheDirectory: true.presets: [['@babel/preset-env', 
              { 
                useBuiltIns: 'usage'.corejs: 3.targets: "defaults"}]],plugins: ['@babel/plugin-proposal-class-properties']}}},Copy the code
  • File resource cache

    Using file resource caching technology can greatly reduce the repeated requests of files in actual projects, lighten the server burden and improve efficiency. We only need to request the file content once for the same file resource and then read the file resource from the cache. However, there is a problem: if the code is in the cache, the code will not be updated in real time.

    Solution: Set the code file name to a hash name, and when the name changes, load the latest content.

    Hash name Settings in Webpack: in webpack.config.js,

    output: {
      //filename: 'bundle.js',
      //filename: '[name].bundle.js',
      // [hash], the hash value generated by packaging the entire project
      // [chunkhash], the hash value generated when different chunks are packaged
      // [contenthash], hash value generated when different content is packaged
      filename: '[name].[hash].js'.path: path.join(__dirname, 'output')},Copy the code

Module Resolution (resolve)

By configuring the rules for module resolution with the Resolve configuration item, we can simplify module import code. For example, omitted CSS file suffixes (import ‘./ CSS /style’), simplified file directories (import ‘@/style’), and so on.

Configure in webpack.config.js:

// Parsing rules for modules
resolve: {
  alias: {// Configure the path alias for the module load
    // Use @ instead of SRC directory
    The '@': resolve('src')},// You can omit the.js and.json suffixes when importing modules
  extensions: ['.js'.'.json'].// Specify the default loading path for the module
  modules: [resolve(__dirname, './node_modules'), 'node_modules']},Copy the code

Details: webpackjs.com/configurati…

Excluding dependencies (externals)

Sometimes we need to exclude packaged dependencies to prevent a dependency from being packaged. Generally speaking, some mature third-party libraries do not need to be packaged. For example: jQuery, then we can introduce compression in THE CDN directly into the template file so that we don’t have to package it.

Configure in webpack.config.js:

// Exclude packaging dependencies
externals: {
  'jquery': 'jQuery'
},
Copy the code

To introduce compression directly into the CDN in a template file:

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Copy the code

Details: www.webpackjs.com/configurati…

Module federal

Module federation is a new feature in Webpack 5. It allows multiple applications to share a module, that is, a module that can be called remotely locally. This is a solution for the micro front end.

Module provider configuration (webpack.config.js) to expose the module to the caller:

// Introduce the module federated plug-in
const Mfp = require('webpack').container.ModuleFederationPlugin

module.exports = (env, argv) = > {
  // Plug-in configuration
  plugins: [
    // Module provider
    new Mfp({
      // The name of the application to be used by the caller
      name: 'app1'.// The name of the file introduced by the caller
      filename: 'app1.js'.// Expose the module
      exposes: {
        // Module name: the code path corresponding to the module
        './Sitename': './src/Sitename.js']}}}),Copy the code

Module user configuration (webpack.config.js) :

// Introduce the module federated plug-in
const Mfp = require('webpack').container.ModuleFederationPlugin

module.exports = (env, argv) = > {
  // Plug-in configuration
  plugins: [
    // Import the module
    remotes: {
      // Application alias (set yourself) : "Remote application name @ remote application address/remote export file name"
      // The module cannot be called if the remote application address is not enabled
      appone: 'aap1@localhost:3001/app1.js'}}]Copy the code

The module user calls in the project js file:

// import(application alias/module name).then(module usage code)
import('appone/Sitename').then(res= > {
  res.default()
  / /...
})
Copy the code

Details: webpack.js.org/concepts/mo…