The most complete and practical configuration of webpack (Collection)

Time:2022-1-24

1. Getting started (let’s use these small examples to familiarize you with the configuration of webpack)

1.1 initialization items

Create a new directory and initialize NPM

npm init

Webpack runs in the node environment. We need to install the following two NPM packages

npm i -D webpack webpack-cli
  • NPM I – D is the abbreviation of NPM install — save dev
  • NPM I – s is the abbreviation of NPM install — save

Create a new foldersrc, and then create a new filemain.js, write some code to test it

console. Log ('call me Yuan ')

Configure package JSON command

The most complete and practical configuration of webpack (Collection)

59f09701704cb2a02f14f738f13bd7b2.png

implement

npm run build

At this point, if a dist folder is generated and contains main JS indicates that the package has been successfully packaged

1.2 start our own configuration

The above simple example is only the default configuration of webpack. Next, we want to implement richer custom configurations

Create a newbuildFolder, create a new one insidewebpack.config.js

// webpack.config.js
const path = require('path');
module.exports = {
    Mode: 'development', // development mode   
    entry: path.resolve(__dirname, '../src/main.js'),
    //Entry file  
    output: {
        filename: 'output. JS', // packaged file name  
        path: path. Resolve (_dirname, '.. / dist') // packaged directory
    }
}

Change our packaging command

The most complete and practical configuration of webpack (Collection)

fe33a8e067a27311098fb56c59325eb6.png

implementnpm run build
You will find that the following directories (pictures) have been generated
amongdistIn foldermain.jsIs the file we need to actually run in the browser
Of course, it’s not just that in practical application. Let’s take you to quickly start webpack through practical cases

1.3 configuring HTML templates

The JS file is packaged, but we can’t do it every timehtmlManually import the packaged in the filejs

Some friends here may think that the name of our packaged JS file is not always fixed(output.js)? So you don’t have to change the name of the imported file every time? In fact, we often configure this in our daily development:

module. Exports = {// omit other configurations   
    output: {
        filename: '[name]. [hash:8]. JS', // packaged file name  
        path: path. Resolve (_dirname, '.. / dist') // packaged directory
    }
}

Generated at this timedistThe catalog file is as follows

The most complete and practical configuration of webpack (Collection)

40f2f617f29192c8903cc107f7433d08.png

For caching, you will find that the name of the packaged JS file is different every time. The JS file packaged by webpack needs to be introduced into HTML, but it is very troublesome for us to manually modify the JS file name every time, so we need a plug-in to help us do this

npm i -D html-webpack-plugin

Create a newbuildPeer folderpublic, create a new index html
The specific configuration files are as follows

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = {
    Mode: 'development', // development mode   
    entry: path. Resolve (_dirname, '.. / SRC / main. JS'), // entry file  
    output: {
        filename: '[name]. [hash:8]. JS', // packaged file name   
        path: path. Resolve (_dirname, '.. / dist') // packaged directory  
    },
    plugins: [new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/index.html')
    })]
}

The generated directory is as follows (picture)

The most complete and practical configuration of webpack (Collection)

6da20cc5c3fda1c096fca0a2abb0a5a0.png

It can be found that the JS file generated by packaging has been automatically introduced into the HTML file

1.3.1. How to develop multi entry files

Generate multiplehtml-webpack-pluginExamples to solve this problem

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    Mode: 'development', // development mode   
    entry: {
        main: path.resolve(__dirname, '../src/main.js'),
        header: path.resolve(__dirname, '../src/header.js')
    },
    output: {
        filename: '[name]. [hash:8]. JS', // packaged file name  
        path: path. Resolve (_dirname, '.. / dist') // packaged directory 
    },
    plugins: [new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/index.html'),
        filename: 'index.html',
        Chunks: ['main '] // module name corresponding to the entry file    
    }), new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/header.html'),
        filename: 'header.html',
        Chunks: ['header '] // module name corresponding to the entry file  
    }), ]
}

The following directories will be found:

The most complete and practical configuration of webpack (Collection)

bc1ca7c754aedeeac89b038a5a3969bb.png

1.3.2 clean-webpack-plugin

Every time you execute NPM run build, you will find that the last packaged file will remain in the dist folder. Here we recommend a plugin to help us empty the folder before packaging and outputclean-webpack-plugin

const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module. Exports = {//... Omit other configurations    
plugins:[new CleanWebpackPlugin()]
}

1.4 reference CSS

Our entry file is JS, so we introduce our CSS file into the entry JS

The most complete and practical configuration of webpack (Collection)

28caa7b6a2f26aabda40b239c0354350.png

At the same time, we also need some loaders to parse our CSS files

npm i -D style-loader css-loader

If we use less to build styles, we need to install two more

npm i -D less less-loader

The configuration file is as follows

// webpack.config.js
module. Exports = {//... Omit other configurations  
    module: {
        rules: [{
            test: /.css$/,
            Use: ['style loader', 'CSS loader'] // parse the policy from right to left    
        }, {
            test: /.less$/,
            Use: ['style loader', 'CSS loader', 'less loader'] // parse the policy from right to left      
        }]
    }
}

Browser openhtmlas follows

The most complete and practical configuration of webpack (Collection)

5fdfdd2d6de878b325326e523d412346.png

1.4.1 add browser prefix to CSS

npm i -D postcss-loader autoprefixer

The configuration is as follows

// webpack.config.js
module.exports = {
    module: {
        Rules: [test /. Less $/, use: ['style loader', 'CSS loader', 'postcss loader', 'less loader'] // parse the policy from right to left  
        ]
    }
}

Next, we need to introduceautoprefixerThere are two ways to make it effective

1. Create one under the project root directorypostcss.config.jsFile, the configuration is as follows:

module. Exports = {plugins: [require ('autoprefixer ')] // just reference the plug-in}

2. Directly inwebpack.config.jsInterior configuration

// webpack.config.js
module. Exports = {//... Omit other configurations  
    module: {
        rules: [{
            test: /.less$/,
            use: ['style-loader', 'css-loader', {
                loader: 'postcss-loader',
                options: {
                    plugins: [require('autoprefixer')]
                }
            }, 'less loader'] // parse the policy from right to left 
        }]
    }
}

At this time, we find that CSS is added to HTML files through style tags, but if there are many style files, all of them are added to HTML, it will inevitably appear chaotic. At this time, we want to split the CSS and introduce the CSS file in the form of external chain. What should we do? At this time, we need to use plug-ins to help us

1.4.2 splitting CSS

npm i -D mini-css-extract-plugin

Before webpack 4.0, we passedextract-text-webpack-pluginPlug in to extract CSS styles from JS files into separate CSS files. webpack4. After 0, it is officially recommendedmini-css-extract-pluginPlug in to package CSS files

The configuration file is as follows

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module. Exports = {//... Omit other configurations  
    module: {
        rules: [{
            test: /.less$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
        }]
    },
    plugins: [new MiniCssExtractPlugin({
        filename: "[name].[hash].css",
        chunkFilename: "[id].css",
    })]
}

1.4.3 splitting multiple CSS

We need to be more specific here, as we used abovemini-css-extract-pluginAll CSS styles will be merged into one CSS file. If you want to split multiple CSS files into one-to-one correspondence, we need to useextract-text-webpack-pluginAt presentmini-css-extract-pluginThis feature is not yet supported. We need to install the @ next versionextract-text-webpack-plugin

npm i - D extract - text - webpack - plugin @next // webpack.config.js
const path = require('path');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
let indexLess = new ExtractTextWebpackPlugin('index.less');
let indexCss = new ExtractTextWebpackPlugin('index.css');
module.exports = {
    module: {
        rules: [{
            test: /.css$/,
            use: indexCss.extract({
                use: ['css-loader']
            })
        }, {
            test: /.less$/,
            use: indexLess.extract({
                use: ['css-loader', 'less-loader']
            })
        }]
    },
    plugins: [indexLess, indexCss]
}

1.5 package pictures, fonts, media, and other documents

file-loaderAfter some processing (mainly processing the file name and path, parsing the file URL), the file is moved to the output directoryurl-loaderGeneral andfile-loaderWhen used together, the function is similar to that of file loader. If the file size is less than the limit. Base64 encoding will be returned. Otherwise, use file loader to move the file to the output directory

// webpack.config.js
module. Exports = {// omit other configurations  
    module: {
        rules: [ // ...     
            {
                test: /. (JPE? G|png|gif) $/ I, // image file 
                use: [{
                    loader: 'url-loader',
                    options: {
                        limit: 10240,
                        fallback: {
                            loader: 'file-loader',
                            options: {
                                name: 'img/[name].[hash:8].[ext]'
                            }
                        }
                    }
                }]
            }, {
                test: /. (mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, // Media files 
                use: [{
                    loader: 'url-loader',
                    options: {
                        limit: 10240,
                        fallback: {
                            loader: 'file-loader',
                            options: {
                                name: 'media/[name].[hash:8].[ext]'
                            }
                        }
                    }
                }]
            }, {
                test: /. (woff2?|eot|ttf|otf)(?.*)?$/ i. // font
                use: [{
                    loader: 'url-loader',
                    options: {
                        limit: 10240,
                        fallback: {
                            loader: 'file-loader',
                            options: {
                                name: 'fonts/[name].[hash:8].[ext]'
                            }
                        }
                    }
                }]
            },
        ]
    }
}

1.6 escaping JS files with Babel

In order to make our JS code compatible with more environments, we need to install dependencies

npm i babel-loader @babel/preset-env @babel/core
  • be careful

babel-loaderAndbabel-coreVersion correspondence of

  1. babel-loader8. X correspondencebabel-core 7.x
  2. babel-loader7. X correspondencebabel-core 6.x

The configuration is as follows

// webpack.config.js
module. Exports = {// omit other configurations 
    module: {
        rules: [{
            test: /.js$/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env']
                }
            },
            exclude: /node_modules/
        }, ]
    }
}

abovebabel-loaderOnly ES6 / 7 / 8 syntax will be converted to Es5 syntax, but the new API will not be converted (e.g. promise, generator, set, maps, proxy, etc.)
At this time, we need to use Babel Polyfill to help us transform

npm i @babel/polyfill
// webpack.config.js
const path = require('path')module.exports = {  
  Entry: ["@ Babel / Polyfill, path. Resolve (_dirname,'.. / SRC / index. JS')"], // entry file}
  • Typing the above demo manually is more beneficial to reading the following articles. It is recommended that the introductory students knock it more than three times

The above practice is that we have a preliminary understanding of the functions of webpack, but we need a systematic practice in order to skillfully apply it to development. Let’s get rid of scaffolding and try to build a Vue development environment ourselves

2. Build Vue development environment

The above small example has helped us to package CSS, images, JS, HTML and other files.
However, we also need the following configurations

2.1 analysis Vue file

npm i -D vue-loader vue-template-compiler vue-style-loadernpm i -S vue

vue-loaderFor parsing.vuefilevue-template-compilerUsed to compile templates
The configuration is as follows

const vueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
    module: {
        rules: [{
            test: /.vue$/,
            use: ['vue-loader']
        }, ]
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.runtime.esm.js',
            ' @': path.resolve(__dirname, '../src')
        },
        extensions: ['*', '.js', '.json', '.vue']
    },
    plugins: [new vueLoaderPlugin()]
}

2.2 configure webpack dev server for hot update

npm i -D webpack-dev-server

The configuration is as follows

const Webpack = require('webpack')
module. Exports = {//... Omit other configurations 
    devServer: {
        port: 3000,
        hot: true,
        contentBase: '../dist'
    },
    plugins: [new Webpack.HotModuleReplacementPlugin()]
}

The complete configuration is as follows

// webpack.config.js
const path = require('path');
const {
    CleanWebpackPlugin
} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const Webpack = require('webpack')
module.exports = {
    Mode: 'development', // development mode   
    entry: {
        main: path.resolve(__dirname, '../src/main.js'),
    },
    output: {
        filename: '[name]. [hash:8]. JS', // packaged file name 
        path: path. Resolve (_dirname, '.. / dist') // packaged directory 
    },
    module: {
        rules: [{
            test: /.vue$/,
            use: ['vue-loader']
        }, {
            test: /.js$/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: [
                        ['@babel/preset-env']
                    ]
                }
            }
        }, {
            test: /.css$/,
            use: ['vue-style-loader', 'css-loader', {
                loader: 'postcss-loader',
                options: {
                    plugins: [require('autoprefixer')]
                }
            }]
        }, {
            test: /.less$/,
            use: ['vue-style-loader', 'css-loader', {
                loader: 'postcss-loader',
                options: {
                    plugins: [require('autoprefixer')]
                }
            }, 'less-loader']
        }]
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.runtime.esm.js',
            ' @': path.resolve(__dirname, '../src')
        },
        extensions: ['*', '.js', '.json', '.vue']
    },
    devServer: {
        port: 3000,
        hot: true,
        contentBase: '../dist'
    },
    plugins: [new CleanWebpackPlugin(), new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/index.html'),
        filename: 'index.html'
    }), new vueLoaderPlugin(), new Webpack.HotModuleReplacementPlugin()]
}

2.3 configuring packaging commands

The most complete and practical configuration of webpack (Collection)

83e3eb20ea09be8d47edd1ab631e2cb3.png

The package file has been configured. Let’s test it
First, create a new main. In SRC js

The most complete and practical configuration of webpack (Collection)

34b9342d1bd1b24e90dfecd45c4eb090.png

Create a new app vue

The most complete and practical configuration of webpack (Collection)

421deeabdfc47804d536a62274ee7a8c.png

Create a new public folder with an index html

The most complete and practical configuration of webpack (Collection)

44f6ea02073654e737e34f3f7676dcd9.png

implementnpm run devAt this time, if the Vue development environment runs successfully in the browser, congratulations. You have successfully taken the first step

2.4 distinguish between development environment and production environment

In the actual application of the project, we need to distinguish between the development environment and the production environment config. JS and add two more files

  • webpack.dev.jsDevelopment environment profile
The development environment mainly realizes the hot update, does not compress the code, and the complete sourcemap
  • webpack.prod.jsProduction environment profile
The production environment mainly realizes the compression of code, extraction of CSS files, reasonable sourcemap and code segmentation. The following modules need to be installed: NPM I - D webpack merge copy webpack plugin optimize CSS assets webpack plugin uglifyjs webpack plugin
  • webpack-mergeMerge configuration
  • copy-webpack-pluginCopy static resources
  • optimize-css-assets-webpack-pluginCompress CSS
  • uglifyjs-webpack-pluginCompress JS

webpack modeset upproductionJS code will be automatically compressed when. In principle, there is no need to introduceuglifyjs-webpack-pluginRepeat the work. howeveroptimize-css-assets-webpack-pluginCompressing CSS will destroy the original JS compression at the same time, so we introduce it hereuglifyjsCompress

2.4.1 webpack.config.js

const path = require('path')
const {
    CleanWebpackPlugin
} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const devMode = process.argv.indexOf('--mode=production') === -1;
module.exports = {
    entry: {
        main: path.resolve(__dirname, '../src/main.js')
    },
    output: {
        path: path.resolve(__dirname, '../dist'),

        filename: 'js/[name].[hash:8].js',
        chunkFilename: 'js/[name].[hash:8].js'
    },
    module: {
        rules: [{
            test: /.js$/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env']
                }
            },
            exclude: /node_modules/
        }, {
            test: /.vue$/,
            use: ['cache-loader', 'thread-loader', {
                loader: 'vue-loader',
                options: {
                    compilerOptions: {
                        preserveWhitespace: false
                    }
                }
            }]
        }, {
            test: /.css$/,
            use: [{
                loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
                options: {
                    publicPath: "../dist/css/",
                    hmr: devMode
                }
            }, 'css-loader', {
                loader: 'postcss-loader',
                options: {
                    plugins: [require('autoprefixer')]
                }
            }]
        }, {
            test: /.less$/,
            use: [{
                loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
                options: {
                    publicPath: "../dist/css/",
                    hmr: devMode
                }
            }, 'css-loader', 'less-loader', {
                loader: 'postcss-loader',
                options: {
                    plugins: [require('autoprefixer')]
                }
            }]
        }, {
            test: /.(jep?g|png|gif)$/,
            use: {
                loader: 'url-loader',
                options: {
                    limit: 10240,
                    fallback: {
                        loader: 'file-loader',
                        options: {
                            name: 'img/[name].[hash:8].[ext]'
                        }
                    }
                }
            }
        }, {
            test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
            use: {
                loader: 'url-loader',
                options: {
                    limit: 10240,
                    fallback: {
                        loader: 'file-loader',
                        options: {
                            name: 'media/[name].[hash:8].[ext]'
                        }
                    }
                }
            }
        }, {
            test: /.(woff2?|eot|ttf|otf)(?.*)?$/i,
            use: {
                loader: 'url-loader',
                options: {
                    limit: 10240,
                    fallback: {
                        loader: 'file-loader',
                        options: {
                            name: 'media/[name].[hash:8].[ext]'
                        }
                    }
                }
            }
        }]
    },
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.runtime.esm.js',
            ' @': path.resolve(__dirname, '../src')
        },
        extensions: ['*', '.js', '.json', '.vue']
    },
    plugins: [new CleanWebpackPlugin(), new HtmlWebpackPlugin({
        template: path.resolve(__dirname, '../public/index.html')
    }), new vueLoaderPlugin(), new MiniCssExtractPlugin({
        filename: devMode ? '[name].css' : '[name].[hash].css',
        chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
    })]
}

2.4.2 webpack.dev.js

const Webpack = require('webpack')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
module.exports = WebpackMerge(webpackConfig, {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    devServer: {
        port: 3000,
        hot: true,
        contentBase: '../dist'
    },
    plugins: [new Webpack.HotModuleReplacementPlugin()]
})

2.4.3 webpack.prod.js

const path = require('path')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = WebpackMerge(webpackConfig, {
    mode: 'production',
    devtool: 'cheap-module-source-map',
    plugins: [
        new CopyWebpackPlugin([{
            from: path.resolve(__dirname, '../public'),
            to: path.resolve(__dirname, '../dist')
        }]),
    ],
    optimization: {
        Minizer: [new uglifyjsplugin ({// compress JS 
            cache: true,
            parallel: true,
            sourceMap: true
        }), new OptimizeCssAssetsPlugin({})],
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                libs: {
                    name: "chunk-libs",
                    test: /[/]node_modules[/]/,
                    priority: 10,
                    Chunks: "initial" // only package the third party that you depend on initially   
                }
            }
        }
    }
})

2.5 optimize webpack configuration

You may be a little tired to see here, but in order to get a better offer and higher salary, you must continue to go deeper

The most complete and practical configuration of webpack (Collection)

2f2be2cd559266f3bed5d93d2d902510.png

Optimizing the configuration is of great practical significance to us, which is actually related to the size and speed of your packaged files.
The specific optimization can be divided into the following points:

2.5.1 optimize packing speed

Build speed refers to the speed of hot updates after each code modification and the speed of packaging files before release.

2.5.1.1 reasonably configure mode parameters and devtool parameters

modeSettabledevelopment productionTwo parameters

If not set,webpack4WillmodeThe default value for is set toproduction``productionIn modetree shaking(remove useless code) anduglifyjs(code compression confusion)

2.5.1.2 narrow the search scope of files (configure include exclude alias noparse extensions)

  • alias: when we appear in the codeimport 'vue'When, webpack will use the way of upward recursive search to searchnode_modulesUnder the directory. In order to reduce the search scope, we can directly tell webpack which path to find. Alias(alias)Configuration of.
  • include excludeSame configurationinclude excludeCan also reducewebpack loaderSearch conversion time.
  • noParseWhen we use it in our codeimport jq from 'jquery'When,webpackIt will resolve JQ whether the library depends on other packages. But we have similarjquerySuch dependent libraries are generally considered not to refer to other packages (except for special ones, at your own discretion). increasenoParseProperties, tellwebpackThere is no need to parse, so as to increase the packaging speed.
  • extensions webpackWill be based onextensionsFind files with defined suffixes (file types with higher frequency are written first)
The most complete and practical configuration of webpack (Collection)

87bf48305eb3e59f5c08bfcc53fe301a.png

2.5.1.3 start multi process loader conversion with happypack

In the process of webpack construction, it actually takes time, and most of it is used in loader parsing and conversion and code compression. In daily development, we need to use loader to convert JS, CSS, pictures, fonts and other files, and the amount of file data converted is also very large. Due to the characteristics of JS single thread, these conversion operations cannot process files concurrently, but need to process files one by one. The basic principle of happypack is to decompose these tasks into multiple sub processes for parallel processing, and send the results to the main process after the sub process processing, so as to reduce the total construction time

npm i -D happypack
The most complete and practical configuration of webpack (Collection)

a74b7e241211c4e1508ce477547be910.png

2.5.1.4 using webpack parallel uglify plugin to enhance code compression

The loader conversion has been optimized above, so another difficulty is to optimize the compression time of the code.

npm i -D webpack-parallel-uglify-plugin
The most complete and practical configuration of webpack (Collection)

54a7fed62d3a52b299e9850f2c40ec0d.png

2.5.1.5 pull out the third-party module

For static dependency files that do not change frequently in development projects. Similar to ourselementUi、vueFamily bucket, etc. Because there are few changes, we don’t want these dependencies to be integrated into each build logic. The advantage of this is that every time I change the file of my local code,webpackI only need to package the file code of my project itself without compiling the third-party library. In the future, as long as we don’t upgrade the third-party package, thenwebpackThese libraries will not be packaged, which can quickly improve the packaging speed.

Here we usewebpackBuilt inDllPlugin DllReferencePluginPull off
In andwebpackNew under the same level directory of the configuration filewebpack.dll.config.js
The code is as follows

// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
module. Exports = {// the array of modules you want to package  
    entry: {
        vendor: ['vue', 'element-ui']
    },
    output: {
        path: path. Resolve (_dirname, 'static / JS'), // location of file output after packaging 
        filename: '[name].dll.js',
        library: '[name]_library'
        //You need to communicate with webpack In dllplugin ` Name: '[name]_ Library ', ` keep consistent. 
    },
    plugins: [
        new webpack.DllPlugin({
            path: path.resolve(__dirname, '[name]-manifest.json'),
            name: '[name]_library',
            context: __dirname
        })
    ]
};

staypackage.jsonThe following commands are configured in

"dll": "webpack --config build/webpack.dll.config.js"

Next, in ourwebpack.config.jsAdd the following code in

module.exports = {
        plugins: [
                new webpack.DllReferencePlugin({
                    context: __dirname,
                    manifest: require('./vendor-manifest.json')
                }),
                New copywebpackplugin ([// copy the generated file to the dist directory, so you don't have to manually CV {from: 'static', to: 'static'}]),
                    ]
                };

implement

npm run dll

You will find that the third place of the set we need is generated
Codedvendor.dll.js
We need to behtmlManually import this filejsfile

<!DOCTYPE html>
<html lang="en">
<head>  
<meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
  < title > old yuan < / Title >
  <script src="static/js/vendor.dll.js"></script>
</head>
<body> 
 <div></div>
</body>
</html>

In this way, if we don’t update the third-party dependency package, we don’t have tonpm run dll。 Direct executionnpm run dev npm run buildYou will find that our packing speed has improved significantly. Because we have passeddllPluginPulled out the third-party dependency package.

2.5.1.6 configure cache

Every time we execute the build, we will compile all the files repeatedly. Can such repeated work be cached? The answer is yes. At present, most of them areloaderAll providedcacheConfiguration item. Like inbabel-loaderIn, you can setcacheDirectoryTo turn on the cache,babel-loader?cacheDirectory=trueEach compilation result will be written into the hard disk file (the default is in the project root directory)node_modules/.cache/babel-loaderDirectory, of course, you can also customize)
<p>But ifloaderDoes not support caching? We also have methods that we can passcache-loader, what it does is very simplebabel-loaderopencacheAfter doing things, willloaderThe compilation results of are written to the hard disk cache. If the file has not changed from the previous one, the cache will be used directly. The usage method is shown in the official demo. You can add this loader before some loaders with high performance overhead</p>

npm i -D cache-loader
The most complete and practical configuration of webpack (Collection)

4ef93fe7e1d065a305d87805ccb60a73.png

2.5.2 optimize the volume of packaged files

We have optimized the speed of packaging, but the volume of packaged files is very large, resulting in slow page loading and waste of traffic. Let’s continue to optimize the volume of files

2.5.2.1 introduce webpack bundle analyzer to analyze packaged files

webpack-bundle-analyzerThe packaged content bundle is displayed as an intuitive tree view to facilitate interaction, so that we can know the content really introduced in the package we build

npm i -D webpack-bundle-analyzer
The most complete and practical configuration of webpack (Collection)

773bf92c29463e1181cb37ae3aa82d66.png

Next inpackage.jsonConfigure startup command in

"analyz": "NODE_ENV=production npm_config_report=true npm run build"

Please install windowsnpm i -D cross-env

"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"

nextnpm run analyzThe browser will automatically open the web page of the file dependency graph

2.5.2.3 externals

According to the official documentation, if we want to reference a library, but we don’t want towebpackPackaging without affecting our ability toCMD、AMDperhapswindow/globalGlobal and other methods can be used through configurationExternals。 This function is mainly used when creating a library, but it can also be fully used in our project developmentExternalsIn this way, we eliminate these static resources that do not need to be packaged from the construction logic and use them insteadCDN
To reference them.
<p>Sometimes we want us to passscriptImported library, such as CDNjquery, when we use it, we still use itrequireBut I don’t want to use itwebpackCompile it into a file again. The case on the official website here is clear enough. If you are interested, you can click to understand it</p>

webpack
The cases on the official website are as follows

<script  src="https://code.jquery.com/jquery-3.1.0.js"  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="  crossorigin="anonymous"></script>module.exports = { 
 //...  
externals: {    jquery: 'jQuery'  }};
import $ from 'jquery';
$('.my-element').animate(/* ... */);

2.5.2.3 Tree-shaking

Let me mention it alonetree-shaking, because there’s a pit here.tree-shakingThe main function of is to remove useless parts of the code. Currently inwebpack4We setmodebyproductionIt has been turned on automatically by the time oftree-shaking。 But for it to work, the generated code must be an ES6 module. Other types of modules such asCommonJSAnd the like. If usedBabelIf so, there is a small problem becauseBabelBy default, any module type will be translated intoCommonJSType. It’s also easy to fix this problem.babelrcFile or inwebpack.config.jsSet in filemodules: falseJust fine

// .babelrc{  "presets": [    ["@babel/preset-env",      {        "modules": false      }    ]  ]}

perhaps

// webpack.config.js 
module: {
    rules: [{
        test: /.js$/,
        use: {
            loader: 'babel-loader',
            options: {
                presets: ['@babel/preset-env', {
                    modules: false
                }]
            }
        },
        exclude: /(node_modules)/
    }]
}

After the baptism of the above two series, we have become a qualified webpack configuration engineer. However, the replaceability of screwing is still very high. Next, we will go deep into the principle of webpack

The most complete and practical configuration of webpack (Collection)

65aec257be14fb24c610d2e6cdb4bd94.png

3. Handwritten webpack series

Having experienced the above two parts, we can skillfully use the relevant loaders and plugins to convert and parse our code. Next, we manually implement the loader and plugin to make it more fun in normal development.

3.1 handwritten webpack loader

loaderIn essence, it is anodemodular. Equivalent to a juicer(loader)The file code of the relevant type will be(code)Give it. According to the rules we set, after a series of processing, we will return the processed fruit juice to us(code)

loaderCompilation principles

  • Single principle: eachLoaderDo only one thing;
  • Chained call:WebpackEach is called in a sequential chainLoader
  • Principle of unification: followWebpackThe design rules and structure are formulated. The input and output are stringsLoaderCompletely independent, plug and play;

In the daily development environment, in order to facilitate debugging, we often add manyconsolePrint. However, we do not want printed values to exist in the production environment. So here we implement one by ourselvesloaderRemove from codeconsole

Popularization of knowledge pointsASTASTGenerally speaking, suppose we have a filea.js, we’re righta.jsThe 1000 lines inside are used for some operations, such as for allawaitincreasetry catch, and other operations, buta.jsThe code inside is essentially a pile of strings. What should we do? That is, we can easily add, delete, modify and query objects (abstract syntax trees) with marked information. The marked object (abstract syntax tree) isAST。 Here is a good ast article to get started with

npm i -D @babel/parser @babel/traverse @babel/generator @babel/types
  • @babel/parserParse the source code intoAST
  • @babel/traverseyesASTNodes are traversed recursively to generate a code that is convenient for operation and conversionpathobject
  • @babel/generatortakeASTDecoding generationjscode
  • @babel/typesThrough this module, the specificASTNodes can be added, deleted, modified and queried

newly builddrop-console.js

const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const generator = require('@babel/generator').default
const t = require('@babel/types')
module.exports = function(source) {
    const ast = parser.parse(source, {
        sourceType: 'module'
    }) traverse(ast, {
        CallExpression(path) {
            if (t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.object, {
                    name: "console"
                })) {
                path.remove()
            }
        }
    }) const output = generator(ast, {}, source);
    return output.code
}

How to use

const path = require('path')
module.exports = {
    mode: 'development',
    entry: path.resolve(__dirname, 'index.js'),
    output: {
        filename: '[name].[contenthash].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [{
            test: /.js$/,
            use: path.resolve(__dirname, 'drop-console.js')
        }]
    }
}

Actuallywebpack4Removal has been integrated inconsoleFunction, inminimizerConfigurable console in

Attach how to write a loader on the official website

3.2 handwritten webpack plugin

stayWebpackMany events will be broadcast in the life cycle of operation,PluginYou can monitor these events and pass them at the right timeWebpackProvidedAPIChange the output. Generally speaking, a plate of delicious fried eggs with salt beans needs to go through the process of burning oil, frying, seasoning and finally loadingpluginIt is equivalent to monitoring each link and operating it. For example, you can write a message with less pepperplugin, monitoringwebpackExposed life cycle events (seasoning), perform the operation of putting less pepper during seasoning. So it’s withloaderWhat is the difference between? We also mentioned aboveloaderA single principle,loaderThere can only be one thing, for exampleless-loader, can only be resolvedlessDocuments,pluginIt is to perform a wide range of tasks for the whole process.

A basic plugin structure is as follows

class firstPlugin {
    constructor(options) {
        console.log('firstPlugin options', options)
    }
    apply(compiler) {
        compiler.plugin('done', compilation => {
            console.log('firstPlugin')))
    }
}
module.exports = firstPlugin

What are compiler and compilation?

  • compilerObject containsWebpackAll configuration information of the environment. This object is startingwebpackIt is established at one time, and all operable settings are configured, includingoptionsloaderandplugin。 When inwebpackWhen a plug-in is applied in the environment, the plug-in will receive this messagecompilerObject. You can use it to accesswebpackMain environment.
  • compilationObject contains current module resources, compiled resources, changed files, etc. When runningwebpackWhen developing environment middleware, whenever a file change is detected, a new one will be createdcompilationTo generate a new set of compilation resources.compilationObject also provides many callbacks at critical times for plug-ins to choose when doing custom processing.

The difference between compiler and compilation is

  • Compiler represents the whole life cycle of webpack from Startup to shutdown, while compilation only represents a new compilation process
  • Compiler and compilation expose many hooks, which can be customized according to the actual demand scenario

Compiler hook document
Compilation hook document

Let’s manually develop a simple requirement to automatically generate information about the size of the packaged file before generating the packaged file

Create a newwebpack-firstPlugin.js

class firstPlugin {
    constructor(options) {
        this.options = options
    }
    apply(compiler) {
        compiler.plugin('emit', (compilation, callback) => {
            let str = ''
            for (let filename in compilation.assets) {
                STR + = ` file: ${filename} size ${compilation. Assets [filename] ['size '] ()} n`
            }// through compilation Assets can obtain the static resource information after packaging, and can also be written to resources     
            compilation.assets['fileSize.md'] = {
                source: function() {
                    return str
                },
                size: function() {
                    return str.length
                }
            }
            callback()
        })
    }
}
module.exports = firstPlugin

How to use

const path = require('path')const firstPlugin = require('webpack-firstPlugin.js')module. Exports = {// omit other code plugins: [new firstplugin()]}

implementnpm run buildYou can see indistA folder containing information about the package file is generatedfileSize.md

Top twoloaderAndpluginThe case is just a guide, which is in the actual development needsloaderAndpluginThere are many aspects to consider. I suggest you try it yourself.

Attach how to write a plugin on the official website

3.3 handwritten webpack

Because the length is too long and the principle is more in-depth. In view of the principle of applying this article to practical development quickly, it is decided to start another new article to analyze it in detailwebpackPrinciple and implementation of ademoedition. After the format is calibrated, the article link will be posted below

4. webpack5. 0 Era

The update speed of both front-end framework and construction tools is far faster than we imagined. In previous yearsjqueryThe era of a shuttle is gone forever. What we want to embrace is the constant updating and iterationvue、react、node、serverless、docker、k8s….

The most complete and practical configuration of webpack (Collection)

v2-916338e511a20085880148dbd1d9b060_b.gif

Webpack, which is unwilling to lag behind, has also recently released webpack 5.0.0 beta 10. The author also mentioned beforewebpack5.0It aims to reduce the complexity of configuration and make it easier to use(webpack4And some performance improvements

  • Use persistent cache to improve build performance;
  • Use better algorithms and default values to improve long-term caching;
  • Clean up the internal structure without introducing any destructive changes;
  • Introduce some breaking changes to use V5 version as long as possible.

At present, the updates of maintainers are very frequent. I believe it won’t take longwebpack5.0Will embrace the public. Interested students can install it firstbetaTry the new version. But before that, I suggest you firstwebpack4Master it, so that the road behind will be better and better.

The most complete and practical configuration of webpack (Collection)

c95b888cee04722dffe05d5b8ea9ce19.png

Original author’s name: front end Xiaobu
Original source: segmentfault
(Collection)