preface

2021, webpack build or CLI package (nothing to understand), combined with the official website, decided to systematically learn webpack, understand the beauty of Webpack (life force)

1.webpackWhat is the

Essentially, WebPack is a static module packaging tool for modern JavaScript applications. When WebPack works with an application, it internally builds a dependency graph that maps to each module required for the project and generates one or more bundles.

module -> chunk -> bundle

2. Initialize the project

Create a new project name, any location, any name (English is recommended), and create a folder called mulei

Initialize the project

npm init
Copy the code

Install webpack

npm i webpack webpack-cli -D
Copy the code

Current Installed Version

"webpack": "^ 5.43.0"."webpack-cli": "^ 4.7.2." "
Copy the code

The entry file defaults to./ SRC /index.js and can also be configured in webpack.config.js

module.exports = {
      entry: './src/index.js',}Copy the code

Starting with V4.0.0, WebPack can run webPack without importing a configuration file to package a project, and go with the default output dist/main.js

  • In the current directorywebpackYou need to usenpmBuilt-in package processornpxnpx webpackBin /node_modules/.bin/
  • npx webpackNo mode specifiedmodeIn the case of the default go isproduction, the development environment needs to executenpx webpack --mode development

3. Split the configuration andmerge

There are huge differences in build goals between development and production environments. In a development environment, we need: a powerful source map and a Localhost Server with live reloading or hot Module replacement capabilities. Production environment goals move to other areas, focusing on bundle compression, lighter source maps, resource optimizations, and so on to improve load times. To follow logical separation, we generally recommend writing separate WebPack configurations for each environment.

To prevent configuration duplication in different environments, extract the common configuration and use webpack-merge to merge the common configuration and environment-specific configuration.

Create the build folder in the root directory and create the public configuration webpack.common.js, the development configuration webpack.dev.js, and the production configuration webpack.prod.js.

Install webpack – merge

npm i webpack-merge -D
Copy the code

Configuration webpack. Dev. Js

const { merge } = require("webpack-merge")
const webpackCommon = require('./webpack.common.js')

module.exports = merge(webpackCommon, {
    mode: "development"
})
Copy the code

How do I run webpack.dev.js? For convenience, you need to configure it in the scripts of package.js

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

4. Automatic HTML build

html-webpack-plugin

Create a folder public in the root directory and create a new index.html file. How do we package the index.html file into the dist folder and import the output main.js? Generate an HTML5 file using the HTML-webpack-plugin and import all of your WebPack-generated bundles using the Script tag in the body.

HTML – webpack – the plugin installation

npm i html-webpack-plugin -D
Copy the code

Since HTML needs to be built in both development and production environments, the HTml-webpack-plugin is configured in the common configuration webpack.common.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    plugins: [
        new HtmlWebpackPlugin()
    ]
}
Copy the code

The html-webpack-plugin generates index.html in the dist folder by default without any configuration

<! DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Webpack App</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script defer src="main.js? e68f6906a7f78bef340d"></script> </head> <body> </body> </html>Copy the code

However, the generated default index.html is different from the one we created ourselves. In this case, we need to configure template

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html".hash: true.// Add a unique hash for CSS and JS files. Loop-breaking caching is very useful}})]Copy the code

copy-webpack-plugin

Copy an existing single file or entire directory to the build directory, such as a website icon

Install the copy – webpack – the plugin

npm i copy-webpack-plugin -D
Copy the code

Specific configuration

// webpack.common.js
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
    plugins: [
        new CopyPlugin({
            patterns: [{from: "public/favicon.ico".to: "favicon.ico"}]}),]}Copy the code

5. Compile the JS file

Load ES2015+ code and convert it to ES5 using Babel

The following plug-ins need to be installed

npm install babel-loader @babel/core @babel/preset-env -D
Copy the code

The Babel configuration can be configured either in the configuration file webpack.common.js or in.babelrc

// webpack.common.js
module.exports = {
    module: {
        rules: [{test: /\.js$/,
                use: {
                    loader: 'babel-loader? cacheDirectory'.options: {
                        "presets": ["@babel/preset-env"]}},exclude: /node_modules/}}},]Copy the code
// .babelrc
{
    "presets": ["@babel/preset-env"]}Copy the code

There are two things you can do to improve your build speed:

  • includeContains,excludeEliminate files and reduce the number of compiled files
  • cacheDirectoryUsed to cache loader execution results. Later WebPack builds will attempt to read the cache, the default cache directorynode_modules/.cache/babel-loader

6,CSSPreprocessing language andCSS

compile

Webpack can’t compile style files directly, you need to use loader

Taking less as an example, the pre-processing language can be divided into four steps:

  • less-loader:webpackLessCompiled intoCSSloader

Install less and less-loader

npm i less less-loader -D
Copy the code
  • postcss-loaderUse:PostCSSTo deal withCSSloader.postcss-preset-envAutomatically adds the compatible browser style prefix. You need to set the compatible browser version

The postcss-loader attribute postcssOptions allows you to set plug-ins, which can also be configured in postcss.config.js

Install postCSS-loader and postCSs-preset -env

npm i postcss-loader postcss-preset-env -D
Copy the code
  • css-loader:@importurl()For processing

Install the CSS – loader

npm i css-loader -D
Copy the code
  • style-loader:CSSInserted into theDOMthroughstyleTag mode added tohtmlOf the fileheadIn the label

Install style – loader

npm i style-loader -D
Copy the code

For your convenience, you can install:

npm i less less-loader postcss-loader postcss-preset-env css-loader style-loader -D
Copy the code

Execute from right to left, bottom to top

Detailed configuration:

// webpack.dev.js
const { merge } = require("webpack-merge")
const webpackCommon = require('./webpack.common.js')

module.exports = merge(webpackCommon, {
    mode: "development".module: {
        rules: [{test: /\.css$/,
                use: [
                    "style-loader"."css-loader"."postcss-loader"
                    / / {
                    // loader: "postcss-loader",
                    // options: {
                    // postcssOptions: {
                    // plugins: [
                    / / /
                    // "postcss-preset-env",
                    / / {
                    // browsers: ["last 1 version", "> 1%", "IE 10"]
                    / /}
                    / /]
                    / /]
                    / /}
                    / /}
                    // }] {},test: /\.less$/,
                use: [
                    "style-loader"."css-loader"."postcss-loader"./ / {
                    // loader: "postcss-loader",
                    // options: {
                    // postcssOptions: {
                    // plugins: [
                    / / /
                    // "postcss-preset-env",
                    / / {
                    // browsers: ["last 1 version", "> 1%", "IE 10"]
                    / /}
                    / /]
                    / /]
                    / /}
                    / /}
                    // },
                    "less-loader"]}]}})Copy the code
// postcss.config.js
module.exports = {
    plugins: [["postcss-preset-env",
            {
                browsers: ["last 1 version"."1%" >."IE 10"[}]]}Copy the code

To ensure that different tools share the same browser compatible version, you are advised to create a.browserslistrc file in the root directory

last 1 version
> 1%
IE 10 # sorry
Copy the code

extractingCSS

As the project gets more complex and more CSS is inserted into the head, the development environment is tolerable and the production environment is too cluttered, So the production environment uses the Mini-CSs-extract-plugin to extract CSS into a separate file and install the Mini-CSs-extract-plugin

npm i mini-css-extract-plugin -D
Copy the code

The configuration is as follows:

// webpack.prod.js
const { merge } = require("webpack-merge")
const webpackCommon = require('./webpack.common.js')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = merge(webpackCommon, {
    mode: "production".module: {
        rules: [{test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader"."postcss-loader"] {},test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader"."postcss-loader"."less-loader"]},]},plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/style.[contenthash:8].css'})]})Copy the code

CSSThe compression

Now you can separate styles, but the code is not compressed. Use the csS-minimizer-webpack-plugin to enable CSS compression. Install csS-minimizer-webpack-plugin

npm i css-minimizer-webpack-plugin -D
Copy the code

The csS-minimizer-webpack-plugin is added by configuring optimization.minimizer, but it overwrites the default compression tool, so it needs to be in webpack@5 and can be used… Syntax to extend existing minimizer (terser-webpack-plugin)

Specific configuration

// webpack.prod.js
const { merge } = require("webpack-merge")
const webpackCommon = require('./webpack.common.js')
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = merge(webpackCommon, {
    mode: "production".optimization: {
        minimizer: [
            // In webpack@5, you can use '... 'syntax to extend existing minimizer (i.e.,' terser-webpack-plugin '), uncomment the next line
            `... `.new CssMinimizerPlugin(),
        ],
    },
})
Copy the code

7. Resource module

Asset Module is a module type that allows you to use resource files (fonts, ICONS, etc.) without having to configure an additional loader.

There are four types:

  • asset/resourceSend a separate file and export itURL. Previously by usingfile-loaderThe implementation.
  • asset/inlineTo export a resourcedata URI. Previously by usingurl-loaderThe implementation.
  • asset/sourceExport the source code of the resource. Previously by usingraw-loaderThe implementation.
  • assetI’m exporting adata URIAnd automatically select between sending a separate file. Previously by usingurl-loaderAnd configure the resource volume limitation implementation.

They replace the ability of url-loader and file-loader to process font images.

I set the asset type to images/[hash][ext][query] by default in the dist folder. Where is it configured? The two methods are as follows:

  • Set up theoutput.assetModuleFilenameTo modify the default output location
  • Set up theRule.generator.filename, to set different output positions for different types of files, only applicableassetasset/resourceModule type.

Webpack will automatically choose between resource and inline by default: files less than 8KB will be treated as inline module types, otherwise they will be treated as Resource module types.

Can rule hierarchy in the webpack configuration of the module, set the rule. The parser. DataUrlCondition. MaxSize options to modify the conditions

Specific configuration

// webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    output: {
        filename: "[name].[contenthash:8].js".clean: true.// assetModuleFilename: 'images/[hash][ext][query]'
    },
    module: {
        rules: [{test: /\.js$/,
                use: {
                    loader: 'babel-loader? cacheDirectory',},exclude: /node_modules/
            },
            {
                test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                type: 'asset'.generator: {
                    / / and the output. The same assetModuleFilename and applies only to the asset and the asset/resource module type
                    // filename: "images/[hash][ext][query]"
                },
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024 // The default is 8KB}},exclude: /node_modules/}},plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html".hash: true.// Add a unique hash for CSS and JS files. Loop-breaking caching is very useful}})]Copy the code

8. Export configuration

output.filename

Output. filename determines the name of each output bundle, usually named bundle.[contenthash:8].js. Multi-entry case, generally in [name].[contenthash:8].js

Add contenthash, which changes when the content is modified so that the browser does not run the cache when accessing the resource.

output.clean

Set to true to empty the output directory before packaging

Exclude some files from using the keep attribute

module.exports = {
    / /...
    output: {
        clean: {
            keep: /assets/,}}};// or

module.exports = {
    / /...
    output: {
        clean: {
            keep (asset) {
                // If there are many files, you can set a whitelist
                return asset.includes('assets'); }},}};Copy the code

9. Development server

webpack-dev-server

Webpack-dev-server can be used to quickly develop applications.

Webpack – dev – server installation

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

Change the scripts of package.json file to webpack serve –config build/webpack.dev.js, run NPM run dev, Visit http://localhost:8080/ to see your own page

The following attributes are commonly used:

  • portSetting the port Number
  • proxyEnabling the agent
module.exports = {
    devServer: {
        proxy: {
            '/api': 'http://localhost:3000',}}};Copy the code

On/API/users request will request broker to http://localhost:3000/api/users

If the interface does not have/API, the path needs to be overridden

module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://localhost:3000'.pathRewrite: { '^/api': ' '},},},},};Copy the code
  • hotTo enable thewebpackHot Module Replacementfunction

Is needed to fully enable HMR webpack HotModuleReplacementPlugin. If you start Webpack or webpack-dev-server with the –hot option, the plug-in is automatically added

HRM

Module hot replacement, which allows all types of modules to be updated at run time without a complete refresh. Specific Settings:

// webpack.dev.js
const { merge } = require("webpack-merge")
const webpackCommon = require('./webpack.common.js')
const webpack = require("webpack")

module.exports = merge(webpackCommon, {
    mode: "development".module: {
        rules: [{test: /\.css$/,
                use: [
                    "style-loader"."css-loader"."postcss-loader"] {},test: /\.less$/,
                use: [
                    "style-loader"."css-loader"."postcss-loader"."less-loader"]]}},plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        hot: true.proxy: {
            '/api': 'http://localhost:3000',}}})Copy the code

In this case, the hot update will not take effect, and you need to set the target to Web, because the runtime environment will be recommended based on the configuration if the.browserslistrc file exists

Modifying the style file later does not refresh the page. Modifying the JS file will refresh the page again

Need to be configured in index.js

if(module && module.hot) {
    module.hot.accept() // Accept self-update
}
Copy the code

10. Devtool configuration

When an error occurs in your code and the specific file and line where the error occurred cannot be found, you need to select a Source Map format to enhance the debugging process.

The development environment needs to know the exact error file and the exact line, and needs the source code to quickly find the exact error location, so configure eval-cheap-module-source-map

In the production environment, you need to know the specific error file and line, but do not need to expose the source code, so configure nosource-source-map

reference

  • Webpack website
  • Liu Xiaoxi

conclusion

To this point, some basic configuration of Webpack has been completed, the first study of Webpack, a lot of content understanding may not be profound, welcome everyone’s criticism and correction.

Code word is not easy, like, comment, collect three even yo!