start

Version: “webpack”: “^5.54.0”

Preamble: Be sure to pay attention to the version, Webpack updates too quickly. As a front-end, webpack will always be asked questions during the interview. Here we will build a simple Vue/React project to get a preliminary understanding of Webpack and ask some frequently asked questions during the interview. Code word is not easy, praise support!!

Tip: Modify the configuration file, to see the effect, you need to restart the project

GitHub address: github.com/cwjbjy/webp…

1. Basic installation

(1) Create webPack5 folder, open it with VScode, and run it through terminal:

NPM init -y NPM install -g yarn // If yarn has been installed, do not run yarn add webpack webpack-cli -dCopy the code

(2) Create SRC, dist folder in webPack5

New SRC/main. Js

console.log('Interesting! ')Copy the code

2. Configure the exits and exits

The new build/webpack.com mon. Js

(1) Configuration entry

Multiple entrances can be configured. However, react or Vue is usually used in development. It is a single page Web application (SPA)

//webpack.common.js const path = require('path') module.exports = { entry: path.resolve(__dirname, ".. /src/main.js"), }Copy the code

(2) Configuration exit

There can only be one exit, and the output path is specified as ‘dist’.

//webpack.common.js module.exports = { output: { path:path.resolve(__dirname,'.. /dist'), filename: '[name].bundle.js', clean:trueCopy the code

Now we have the minimum configuration. In package.json, we create a build script that runs the webpack command

"scripts": {
  "build":"webpack --config build/webpack.common.js",
}
Copy the code

It is now ready to run:

npm run build
Copy the code

Main.bundle.js is generated in the dist folder

Directory structure:

plugin

Plugins are used to extend Webpack functionality, including packaging optimization, resource management, and injection of environment variables

Plugins use: Just require() it and add it to the plugins array

1. html-webpack-plugin

The html-webpack-plugin will generate an HTML5 file for you to import all of your WebPack-generated bundles using the Script tag in the body

(1) Installation

yarn add -D html-webpack-plugin
Copy the code

(2) Create public/index.html

<! DOCTYPE html><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 > Document < / title > < / head > < body > < div id =" app "> < div > 123 < / div > < / div > < / body > < / HTML >Copy the code

(3) Configuration

//webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/index.html'),
        filename: 'index.html', 
    }),
  ],
}
Copy the code

(4) Operation

npm run build
Copy the code

You can see that there is an index. HTML file attached to dist, and the generated main.bundle.js package is introduced in the index. HTML via the script tag

2. progress-bar-webpack-plugin

Effect: Adds a compilation progress bar

(1) Installation:

yarn add progress-bar-webpack-plugin -D
Copy the code

(2) Configuration:

//webpack.common.js const chalk = require("chalk"); const ProgressBarPlugin = require("progress-bar-webpack-plugin"); Module. exports = {plugins: new ProgressBarPlugin({format: ` :msg [:bar] ${chalk.green.bold(":percent")} (:elapsed s)`, }), ], };Copy the code

loader

Loader is used to convert the module source code

Loader is configured in rules of module

Loader configuration items include:

  • Test Specifies the regular check (mandatory).

  • Loader Invoke loader name/use Chain invoke loader (two options)

  • Include /exclude Manually add mandatory files or folders or exclude unnecessary files or folders (optional)

  • Options Additional setup options for Loaders (optional)

Tip: Use chain calls, which are parsed from right to left. Pay attention to the sequence of loader calls. Loaders Keep in mind that interviews are often asked what loaders are and what they do

1. The CSS – loader and style – loader

Effect: Loads the CSS

Css-loader: handles @import and URL ()

Style-loader: Infuses CSS into JavaScript and controls CSS through DOM manipulation

(1) Installation

yarn add css-loader style-loader -D
Copy the code

(2) Configure it in webpack.common.js

Module: {rules: [{$/ test: / \. CSS, use: [" style - loader ", "CSS - loader"], / / parsing} from right to left,],},Copy the code

(3) Examples

New SRC/assets/styles/style.css. CSS

body{
    background-color: aqua;
}
Copy the code

Introduced in main.js

import './assets/styles/style.css'
Copy the code

Recompile the NPM run build and open dist/index.html in your browser. You can see that the CSS has taken effect

2. The url – loader and file – loader

Action: Loads images images, fonts, and video resources

File-loader: outputs files to a specified directory

Url-loader: Converts the file to base64 and inlines it into the bundle. If the size exceeds the limit, use file-loader to move the file to the output directory

(1) Installation

yarn add file-loader url-loader -D
Copy the code

(2) Add the configuration under rules

{ test: /\.(png|jpe? g|gif|svg|ico)(\? . *)? $/, // loader: "url-loader", type: 'javascript/auto',// Limit: 1000, name: "static/img/[name].[hash:7].[ext]",},}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/,// Loader: "url-loader", options: {limit: 10000, name: "static/media/[name].[hash:7].[ext]",},}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/, / / loading resource loader: font "url - loader," options: {limit: 10000, name: "static/fonts / [name] [hash: 7] [ext]",},},Copy the code

(3) Expansion

In webpack5, the asset module is built in, replacing file-loader and url-loader

Example: Load image resources

/ / add {under rules test: / \. (PNG | SVG | JPG | jpeg | GIF) $/ I type: "asset", the generator: {filename: "static/img/[name].[hash:7].[ext]", }, },Copy the code

Tip: Although webpack5 has added built-in modules, file-loader and URl-loader are recommended. The create-React-app scaffolding is currently webpack 4.44.2, and the interview will ask which loader is available

3. sass-loader

(1) Installation

yarn add sass-loader node-sass -D 
Copy the code

(2) Modify the original CSS rules to:

{test: / \ | (CSS SCSS | sass) $/, use: [' style - loader ', 'CSS - loader', 'sass - loader'] / / the compiler from right to left},Copy the code

(3) Create the SRC /assets/blue. SCSS file

$blue: blue;
body{
    color: $blue;
} 
Copy the code

(4) Introduce blue.scss in main.js

import './assets/styles/blue.scss'
Copy the code

Recompile, open dist/index.html, and you can see that 123 on the page has turned blue

4. postcss-loader

Function: Loader to process CSS

With Autoprefixer, add vendor prefix (CSS adds browser kernel prefix)

Post CSS-loader, autoprefixer, Browserslist

(1) Installation:

yarn add -D postcss-loader autoprefixer
Copy the code

(2) Modify the original CSS rules:

{
    test: /\.(css|scss|sass)$/,
    use: ['style-loader', 'css-loader', 'sass-loader', {
        loader: "postcss-loader",
        options: {
            postcssOptions: {
                plugins: [
                    "autoprefixer",
                ],
            },
        },
    }]
}
Copy the code

(3) Add browserslist configuration in package.json

"Browserslist ": {"production": ["> production", "not dead", "not op_mini all"], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }Copy the code

Add the following styles to style.css:

/* style.css */ body { background: #999; } #app div{ width: 200px; margin-top: 50px; transform: rotate(45deg); /* This property produces browser kernel prefixes such as -webkit*/}Copy the code

Recompile and open dist/index.html to see the effect

5. babel-loader

Purpose: Parse ES6, JSX

(1) Installation

Babel is now in version 7 and uses @ to distinguish other unofficial packages

Babel is actually several modular packages:

@babel/core: Babel core library

Babel-loader: the Babel plug-in for Webpack, which allows us to run Babel in Webpack

@babel/preset-env: Convert ES6 to backward-compatible JavaScript

@babel/plugin-transform-runtime: helper function for handling async, await, import(), etc

Run the command:

yarn add @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime -D
Copy the code

(2) Configuration

//webpack.common.js
Copy the code

(3) Add additional Babel configuration items

New root directory. Babelrc

{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-transform-runtime"]
}
Copy the code

(4) Pay attention

Babel-loader 8.x corresponds to @babel/core (7.x)

Babel-loader 7.x corresponds to babel-core 6.x

(5) Test

public/index.html

Use the arrow syntax of ES6

<button> button </button> <script> document.querySelector("button").onclick = () => {console.log("es6"); }; </script>Copy the code

Recompile and open dist/index.html. Click to see that the information is printed, indicating that ES6 parsing is successful

6. html-loader

What it does: Exports HTML as a string, processing static resources introduced in HTML

(1) Installation

yarn add html-loader -D
Copy the code

(2) Configuration

{test: /\.html$/ I, loader: "html-loader", options: {esModule: false, // enable false in development environment},},Copy the code

Set up the environment

1. Set up a local server

(1) Installation

yarn add webpack-dev-server -D 
Copy the code

(2) Configure webpack.common.js

Exports = {mode: "development", devServer: {hot: true, // Compress: true,// Enable gzip compression port: 8088, // Enable port number static: {// Host static resource files directory: path.join(__dirname, ".. Public "),}, client: {// Print compilation progress: true,},},})Copy the code

(3) Package. json add startup command

"scripts": {
  "dev":"webpack serve --config build/webpack.common.js",
}
Copy the code

Start with NPM run dev, modify the contents of the JS file, and the browser preview will refresh automatically

(4) Prompt

In webPack :5.38.1, if you use postCSs-loader, you need to configure Browserslist. However, if you configure Browserslist, you can not hot update the bug, so you need to add target: Web (same as devServer).

In WebPack :5.54.0, the 5.38 BUG has been fixed, no need to configure target: Web. A new problem is that in Chrome, if you don’t open F12, changes to the file content will be hot updated (updated as needed), but when you open the F12 console, changes to the content will cause the page to be refreshed with each update. In Firefox, whether F12 is open or not, the page is refreshed with every update

2. Production environment and development environment

Create webpack.dev.js, webpack.prod.js under build

(1) Install webpack-merge

yarn add -D webpack-merge
Copy the code

(2) Modify webpack.common.js

const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry: path.resolve(__dirname, ".. /src/main.js"), output: { path: path.resolve(__dirname, ".. /dist"), filename: "[name].bundle.js", clean: true, plugins: [new HtmlWebpackPlugin({template: path.resolve(__dirname, "../public/index.html"), filename: "index.html", // output file }), ], module: { rules: [ { test: /\.(css|scss|sass)$/, use: [ "style-loader", "css-loader", "sass-loader", { loader: "postcss-loader", options: { postcssOptions: { plugins: ["autoprefixer"], }, }, }, ], }, { test: / \. (PNG | jpe? G | | GIF SVG | ico) (\? *)? $/, loader: "url - loader," type: "javascript/auto", / / solve asset repeat options: {esModule: Limit: 1000, name: "static/img/[name].[hash:7].[ext]",},}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: "url-loader", options: { limit: 10000, name: "static/media/[name].[hash:7].[ext]", }, }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, loader: "url-loader", options: { limit: 10000, name: "static/fonts/[name].[hash:7].[ext]", }, }, { test: /(\.jsx|\.js)$/, use: ["babel-loader"], exclude: /node_modules/, }, ], }, };Copy the code

(3) webpack. Dev. Js

const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const path = require("path"); Module. Exports = merge(common, {mode: "development", devServer: {hot: true, // open: true, // Static: {directory: path.join(__dirname, ".. directory: path.join(__dirname, ".. / public ")}, client: {/ / print on the browser end compilation schedule progress: true,},},});Copy the code

(4) webpack. Prod. Js

const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); module.exports = merge(common, { mode: "production", module: { rules: [ { test: /\.html$/i, loader: "HTML - loader", / / options: {/ / esModule: false, / / in the development environment to enable false / /},},,,}});Copy the code

(5) Modify package.json

"scripts": {
    "dev": "webpack serve --config build/webpack.dev.js",
    "build": "webpack --config build/webpack.prod.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
Copy the code

3. Configure the alias

Resolve is the same level as entry:

/ / webpack.com mon. Js resolve: {extensions: [", ". JSX "js", "json", "vue"], / / omit the file suffix alias: {/ / configure an alias "@" : path.resolve(__dirname, ".. /src"), }, },Copy the code

The separation

1. webpack-bundle-analyzer

It presents bundle content as a convenient, interactive, scalable tree. So that we can understand the separation of code more intuitively

(1) Installation

yarn add webpack-bundle-analyzer -D
Copy the code

(2) Configuration

//webpack.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 

plugins:[
    new BundleAnalyzerPlugin()
]
Copy the code

(3) Run the NPM run build and open a new page to see the relationship between bundles

2. SplitChunks

Role: Split Chunk

// optimization: {splitChunks: {chunks: "all", name: "vendor", cacheGroups: { "echarts.vendor": { name: "echarts.vendor", priority: 40, test: /[\\/]node_modules[\\/](echarts|zrender)[\\/]/, chunks: "all", }, lodash: { name: "lodash", chunks: "async", test: /[\\/]node_modules[\\/]lodash[\\/]/, priority: 40, }, "async-common": { chunks: "async", minChunks: 2, name: "async-commons", priority: 30, }, commons: { name: "commons", chunks: "all", minChunks: 2, priority: 20, }, }, }, },Copy the code

(1) Chunks: all/async

All: Optimizes the package of both dynamic and non-dynamic modules, throwing all the modules into vendors. Bundle.js

Async: Package dynamic modules into Vender and leave non-dynamic modules as they are (not optimized)

(2) cacheGroups

The purpose of cacheGroups is to group chunks and output them according to the criteria given in the cacheGroups

(3) test

The reason for the regular match, [\\/], to represent the path separator is to fit Windows and Linux systems. By (antd | @ ant – design) match multiple folders, to reach certain several files in a chunk

(4) priority

Priority: The default group priority is negative, and the default value of a user-defined group is 0

(5) Non-dynamic import (import directly)

Install echarts

yarn add echarts -S
Copy the code

New SRC/every. Js

import * as echarts from "echarts" var myChart = echarts.init(document.getElementById('main')); Var option = {title: {text: 'ECharts starting example '}, Tooltip: {}, Legend: {data: [' sales ']}, xAxis: {data: [' shirts' and 'sweater', 'snow spins unlined upper garment,' pants', 'high heels',' socks']}, yAxis: {}, series: [{name: 'sales' type:' bar 'data: [5, 20, 36, 10, 10, 20]}}; // Display the chart using the configuration items and data you just specified. myChart.setOption(option);Copy the code

Introduced in main.js

import './echart'
Copy the code

Modify the public/index. HTML

 <div id="main" style="width: 600px; height: 400px"></div>
Copy the code

Run NPM run build and you’ll find echarts.vendor.bundle.js added to dist. This is the echarts package separated by splitChunks

3. Dynamic import (chunks loaded on demand)

Download resources on demand, such as route lazy loading. Improves the loading speed of the first screen

(1) Install LoDash

yarn add lodash -S
Copy the code

(2) Dynamic import through import() syntax

// Add function getComponent() {// Imported by this script return import(" Lodash "). Then (({default: _ }) => { const element = document.createElement("div"); element.innerHTML = _.join(["Hello", "webpack"], " "); return element; }) .catch((error) => "An error occurred while loading the component"); } const button = document.createElement("button"); button.innerHTML = "Click me "; button.onclick = () => { getComponent().then((component) => { document.body.appendChild(component); }); }; document.body.appendChild(button);Copy the code

Add it to webpack.prod.js under cacheGroups (splitChunks above)

lodash: {
  name: "lodash",
  chunks: "async",
  test: /[\\/]node_modules[\\/]lodash[\\/]/,
  priority: 40,
},
Copy the code

Run NPM run build and the lodash.bundle.js package will only be loaded if the button is clicked

4. Mini-css-extract-plugin (Separate CSS)

(1) Installation

yarn add -D mini-css-extract-plugin
Copy the code

(2) Configuration

//webpack.common.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports={
    plugins: [  
         new MiniCssExtractPlugin({
            filename: "static/css/[name].css",
          })
    ],
  module: {
    rules: [
      {
        test: /\.(css|scss|sass)$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          "sass-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: ["autoprefixer"],
              },
            },
          },
        ],
      },
    ],
  },
}
Copy the code

Use MiniCssExtractPlugin. Loader instead of style – loader, cooperate MiniCssExtractPlugin use.

(3) to expand: in webpack: 5.38.1, MiniCssExtractPlugin. The loader must specify additional publicPath, to refer to CSS resource. Because CSS styles are separated into the static/ CSS folder, there are two more hierarchical directories, which will cause the background image path in CSS to be incorrect.

The following configuration is not needed in WebPack :5.54.0, the path problem has been solved for us

/ / no longer need to configure {test: / \ | (CSS SCSS | sass) $/, use: [{loader: MiniCssExtractPlugin loader, the options: {publicPath: '../../' } }, 'css-loader', 'sass-loader'] }Copy the code

The cache

When the packaged dist directory is deployed on a server, the browser can access the Server’s Web site and its resources. Retrieving resources is time consuming, which is why browsers use a technique called caching. Caching can be hit to reduce network traffic and make websites load faster, and then, if we don’t change the file name of a resource when we deploy a new version, the browser may think it hasn’t been updated and use its cached version.

So we need to change the name of the changed resource files, and the unchanged resources (third-party files in node_modules) do not change the package name

1. contenthash

[contenthash] creates a unique hash based on the resource content. When the content of the resource changes, the [Contenthash] changes.

//webpack.common.js output: { path: path.resolve(__dirname, ".. /dist"), filename: "[name].[contenthash:8].js", clean: true,Copy the code

Define global environment variables

1. Define compile-time global variables

(1) Installation:

yarn add cross-env -D
Copy the code

(2) Configuration:

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack serve --config build/webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

//webpack.common.js
console.log('process.env.NODE_ENV',process.env.NODE_ENV)
Copy the code

2. Define compiled global variables

This is done via DefinePlugin

The new config/dev. Env. Js

module.exports = { NODE_ENV:'"development"', } //webpck.dev.js const env = require(".. /config/dev.env"); const webpack =require("webpack") module.exports = merge(common,{ plugins: [ new webpack.DefinePlugin({ "process.env": env, }), ], }) //main.js console.log(process.env)Copy the code

Optimized packing volume

1. Enable gzip compression

(1) Installation:

yarn add compression-webpack-plugin -D
Copy the code

(2) Configuration:

//webpack.prod.js
const CompressionPlugin = require("compression-webpack-plugin");

module.exports = {
  plugins: [new CompressionPlugin()],
};
Copy the code

2.css-minimizer-webpack-plugin

Optimize and compress CSS

(1) Installation:

yarn add css-minimizer-webpack-plugin --save-dev
Copy the code

(2) Configuration:

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

plugins:[
    new CssMinimizerPlugin(),
]
Copy the code

3. externals

Prevent packaging external resource bundles into your own bundles

Example: Import jQuery from CDN instead of packaging it

(1) index. HTML

< script SRC = "https://code.jquery.com/jquery-3.1.0.js" integrity = "sha256 - slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk =" crossorigin="anonymous" ></script>Copy the code

(2) webpack.com mon. Js

module.exports = {
  //...
  externals: {
    jquery: 'jQuery',
  },
};
Copy the code

(3) This removes the dependency modules that do not need to be changed

import $ from 'jquery';
Copy the code

Configure the Vue

(1) Installation:

yarn add -D vue-template-compiler vue-loader vue-style-loader
Copy the code

Note that the vUE and vue-template-Compiler versions must be the same. If the VUE needs to be updated, vue-template-Compiler should also be updated accordingly

Vue-loader is used to parse. Vue files

Vue-template-compiler is used for template compilation

(2) Configuration:

webpack.common.js

const {VueLoaderPlugin} = require('vue-loader'); // vue loader const isProd = process.env.node_env === 'production'; / / cross - env global variable const cssConfig = [isProd? {loader: MiniCssExtractPlugin loader, the options: {publicPath: '../../' } } : 'vue-style-loader', 'css-loader', 'sass-loader', { loader: "postcss-loader", options: { postcssOptions: { plugins: [ "autoprefixer", ], }, }, } ]; module.exports={ module:{ rules:[ { test: /\.vue$/, loader: 'vue-loader', include: [path.resolve(__dirname, '../src')] }, { test: /\.(css|scss|sass)$/, use: cssConfig } ] }, plugins:[ new VueLoaderPlugin(), ] }Copy the code

Vue-loader must be placed first in the matching rule. Otherwise, an error will be reported

(3) Configure externals

// index.html

< script SRC = "https://cdn.bootcss.com/vue/2.6.12/vue.min.js" > < / script > < script SRC = "https://cdn.bootcss.com/vue-router/3.5.1/vue-router.min.js" > < / script >Copy the code

// webpack.common.js

externals: {
    'vue': 'Vue',
    'vue-router':'VueRouter'
}
Copy the code

(4) Use

New SRC/App. Vue

<template> <div class="app"> <router-link to="/">home</router-link> <router-link to="/about">about</router-link> <router-view/> </div></template><script>export default { name: "App"}</script><style scoped>.app { font-size: 14px; color: aquamarine; }</style>Copy the code

New SRC/views/about. Vue

<template> <div> About page </div></template>Copy the code

New SRC/views/home. Vue

Home page </div></template>Copy the code

The new router/index. Js

Vue.use(VueRouter); const Home = () => import( /* webpackChunkName: "Home" */ '@/views/home.vue')const About = () => import( /* webpackChunkName: "About" */ '@/views/about.vue')const routes = [{ path: '/', component: Home}, { path: '/about', component: About}]const router = new VueRouter({ routes})export default routerCopy the code

Modify the main js

import App from './App.vue';
import router from './router';
Vue.config.productionTip = false;

new Vue({
    router,
    render: (h) => h(App)
}).$mount('#app');
Copy the code

Restart the project to see the results

Configure the React

Install @babel/preset- React in addition to installing other required Babel

1. Install Babel to parse JSX

yarn add -D @babel/preset-react
Copy the code

2. The configuration

//webpack.common.js entry: { main:path.resolve(__dirname, ".. / SRC /main.js"), //vue entry index:path.resolve(__dirname, ".. / SRC/index. Js ") / / react entry}, / /. Babelrc {" presets ": [" @ Babel/preset - env", "@ Babel/preset - react"], "plugins" : ["@babel/plugin-transform-runtime"] }Copy the code

3. Install the react

yarn add react react-dom -S
Copy the code

Use 4.

Modify index.html to add

<div id="root"></div>
Copy the code

New SRC/hello. Js

import React, {Component} from 'react'; let name = 'Alan'; export default class Hello extends Component{ render() { return ( {name} ); }}Copy the code

New SRC/index. Js

import React from 'react'; import {render} from 'react-dom'; import Hello from './hello'; Render (, document.getelementbyid ('root')); render(, document.getelementbyid ('root'));Copy the code

Restart the project and see the results