preface

A series of notes sorted out in the process of learning Webpack, if there is any wrong place, please guide your elder brother.

What exactly is Webpack for?

Webpack is a packaging tool. What can it do? Here are a few:

  • 1. Package your code and remove the parts of your code that you don’t need
  • 2, with a variety ofloaderSo you can use itSass, less, TS, esNew syntax, and parsing a variety of files
  • 3, help you through the use of packaged projectspluginDo various optimizations (compress, obfuscate code)

Download and basic use of Webpack

Download webpack

NPM install webpack webpack-cli -g

View the Webpack version number

webpack -v

// Create the webpack.config.js file
const { resolve } = require('path');
module.exports = {
    entry:"./src/index.js".// Import file
    output: {// Output configuration
        filename:'./built.js' // Output the file name
        path:resolve(__dirname,'build/js') // Output file path configuration
    },
    mode:"production" // Production environment
}
// Inside any module file, you can use the __dirname variable to get the full absolute path to the directory where the current module file resides.



// index.js entry file configuration
import data from "./data/json"
console.log(data);

function add(x, y){
    return x + y;
}
console.log(add(1.2));
Copy the code

Package the file using the Webpack directive

Files and code generated after successful packaging (because production js code is automatically compressed into a single line for display)

Basic conclusions

  • 1.webpackCan deal withjs/jsonResources,css/imgResources need to be packaged by downloading proprietary dependencies
  • 2,webpackIt is divided into development environment and production environment
  • 3. Development environment: where your code is tested, changed, and run on a local server,
  • Production: Your code is already being used on a real server

Webpack development environment configuration

1. Package style resources

Run the NPM install css-loader style-loader less-loader -d command to install the required dependencies for handling style resources

// Configure it in rules in the module of webpack.config.js
// Loader (style) configuration
module: {rules: [// Details loader configuration
        {
            // Which files to match
            text:/\.css$/.// Which loaders are used for processing
            use:[
                // Loaders in the use array are executed from right to left or from bottom to top
                // Create a style tag, insert the js style resource, add it to the head to take effect
                'style-loader'.// Load the CSS file as a comm module as a string into js
                'css-loader'] {},text:/\.less$/,
            use:[
                'style-loader'.'css-loader'.// Compile less files into CSS files
                'less-loader']]}}Copy the code

2. Package HTML resources

NPM install html-webpack-plugin -d installs dependencies needed to process HTML files

// Configure the following options in plugins in the webpack.config.js configuration item
const HtmlWebpackPlugin = require('html-webpack-plugin');

plugins:[
    // Plugins are configured
    // html-webpack-plugin
    // Function: creates an empty HTML by default, automatically importing all the resources (JS/CSS) that are packaged as output.
    // Requirements: Need a structured HTML file
    new HTMLWebpackPlugin({
        // Copy the "./ SRC /index.html" file and automatically import all the resources (JS/CSS) that are packaged as output.
        // title:' This is a custom title'
        template:"./src/index.html"})].mode:"development"
Copy the code

3. Pack image (IMG) resources

NPM install url-loader -d installs the dependencies needed to process image files

// Configure it in rules in the module of webpack.config.js
module: {rules:[
        {
            // Problem: img images in HTML cannot be processed by default
            // Process image resources
            test:/\.(jpg|png|gif)$/.// Use a loader
            loader:"url-loader".options: {// Images smaller than 8KB will be base64 processed
                // Advantages: reduce the number of requests (reduce server stress)
                // Disadvantages: Larger image size (slower file request)
                limit:8 * 1024.// Problem: Because url-loader uses es6 module by default, htMl-loader imports images from commonJS specification
                [object,object]
                // Resolve: Disable ES6 modularization of urL-loader and use CommonJS parsing
                esModule:false.// Turn off es6 module syntax
                // Rename the image
                // [hash:10] takes the first 10 digits of the hash value of the image
                // [ext] takes the original extension of the file
                name:'[hash:10].[ext]'
            },
            Webpack 5 needs to be added
            type:'javascript/auto'}}]Copy the code

4. Pack other resources (Iconfont.)

NPM install file-loader -d installs the dependencies needed to process image files

// Configure it in rules in the module of webpack.config.js
// Package other resources (other than HTML/JS/CSS resources)
{
    // Exclude CSS /js/ HTML resources
    exclude:/\.(css|js|html)$/,
    loader:'file-loader'.options: {name:"[hash:10].[ext]"}}Copy the code

5. DevServer

Configure devServer in webpack.config.js

devServer:{
    // webpack5
    static: {directory: resolve(__dirname,"build")},/ / contentBase: resolve an error (__dirname, "build")
    // Start gzip compression
    compress: true./ / the port number
    port: 3000.// Whether to open the page automatically
    open: true,}Copy the code

Purpose: To automate (automatically compile, automatically open the browser, automatically refresh the browser)

Features: Only packages are compiled in memory, with no output

Start command: NPX webpack serve

6. The development environment is configured

const HtmlWebpackPlugin = require('html-webpack-plugin');
const{ resolve } = require('path');

module.exports = {
    entry:"./src/js/index/js".output: {filename:"js/built.js".path:resolve(__dirname,'build')},module: {rules: [// Loader handles the configuration of the style
            // Process less resources
            {
                test:/\.less$/,
                use:['style-loader'.'css-loader'.'less-loader']},// Process CSS resources
            {
                test:/\.css$/,
                use:['style-loader'.'css-loader']},// Process image resources
            {
                test:/\.(jpg|png|gif)$/,
                loader:"url-loader".options: {// indicates that images below 8KB will be processed through Base64
                    limit:8 * 1024.name:"[hash:10].[ext]".esModule:false.outputPath:"imgs"
                },
                type:"javascript/auto"
            },
            // Process img resources in HTML
            {
                test:/\.html$/,
                loader:"html-loader"
            },
            {
             // Process other resources
                 exclude:/\.(html|js|css|less|jpg|png|gif)/,
                 loader:"file-loader".options: {name:"[hash:10].[ext]".outputPath:"media"}}},plugins: [// Plugins are configured
        new HtmlWebpackPlugin({
            template:"./src/index.html"})].// Development server
    devServer: {static: {directory:resolve(__dirname,"build")},compress:ture,
        port:3000.open:true
    },
    mode:"development"
}
Copy the code

Webpack production environment configuration

1. Extract the CSS into a separate file

Install mini-css-extract-plugin -d dependencies required by NPM

const HtmlWebpackPlugin = requrie('html-webpack-plugin')
const MinCssExtractPlugin = requrie('mini-css-extract-plugin')
const { resolve } = require('path')

module.exports = {
    entry:"./src/js/index.js".output: {filename:"js/built.js".path:resolve(__dirname,'build')},module: {rules:[
            {
                test:/\.css$/,
                use:[
                    // Create a style tag to place the style on
                    // 'style-loader'这个loader取代style-loader
                    // Function: Extract CSS from js into a separate file
                    MiniCssExtarctPlugin.loader,
                    // Integrate CSS files into js files
                    'css-loader']]}},plugins: [new HtmlWebpackPlugin({
            template:"./src/index.html"
        }),
        new MiniCssExtractPlugin({
            // Rename the file
            filename:"css/built.css"})].mode:"production"
}
Copy the code

The effect

2. Check the CSS compatibility

Install mini-css-extract-plugin -d dependencies required by NPM

// Add the following configuration when rules handles CSS in the module of webpack.config.js
// CSS compatibility processing: postcss => postCSs-loader postCSs-preset -env
// Help postcss find the configuration in package.json browserslist and load the specified CSS compatibility content through the configuration
{
    loader:"postcss-loader".options: {// webpack 5
        postcssOptions: {plugins: ["postcss-preset-env"[// Opitons[]}}}Copy the code

The effect

3. Compress CSS

Install the dependency required by NPM install optimize- CSS -assets-webpack-plugin -d

// Plugins in webpack.config.js are configured as follows
plugins: [new HtmlWebpackPlugin({
        template:"./src/index.html"
    }),
    new MiniCssExtractPlugin({
        filename:"css/built.css"
    }),
    new OptimizeCssAssetsPlugin()
]
Copy the code

The effect

4. Check the js syntax

Use NPM to install eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -d to install the required dependencies

// Rules for modules in the webpack.config.js configuration configure the following options
module: {rules: [// Syntax check :eslint-loader eslint
        // Note: only check your own source code, third-party libraries are not checked
        {
            test:/\.js$/,
            exclude:/node_modules/,
            loader:"eslint-loader".options: {// Automatically fixes esLint errors
                fix:true}}}]Copy the code

Configure eslintConfig in package.json

5. Js compatibility processing

Run NPM install babel-loader @babel/ core@babel /preset-env-d to install the required dependencies

  • 1. Basic JS compatibility processing@babel/preset-envProblem: Only basic syntax can be converted, such aspromiseYou cannot convert
  • 2. All JS compatibility processing@babel/Problem: I only want to solve part of the compatibility problem, but it is too bulky to introduce all the compatibility code
  • 3, need to do compatibility processing to do: load on demandcore-js
module: {rules:[
        {
            test:/\.js$/,
            exclude:/node_module/,
            loader:"babel-loader".options: {// Preset: what compatibility processing is instructed to Babel
                [
                    '@babel/preset-env',
                    {
                        // Load as needed
                        useBuiltIns:'usage'.// Specify the core-js version
                        corejs: {version:3
                        },
                        // Specify which version of the browser is compatible with
                        targets: {chrome:'60'.firefox:'60'.ie:'9'.safari:'10'.edge:'17'}}]}}Copy the code

6. The compression of HTML

NPM install html-webpack-plugin -d

plugins:[
    new HtmlWebpackPlugin({
        template:'./src/index.html'.minify: {// Remove whitespace
            collapseBooleanAttributes:true.// Remove comments
            removeComments:true}})]Copy the code

7. The production environment is configured

const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const { resolve } = require('path');
const commonCssLoader = [
    MiniCssExtractPlugin.loader,
    'css-loader',
    {
        // Browserslist needs to be defined in package.json
        loader:'postcss-loader'.options: {postcssOptions: {plugins:[
                    [
                        'postcss-preset-env'[// Options[]}}}]// Define the nodeJS environment variable: Determines which environment to use browserslist
process.env.NODE_ENV = 'production';
module.exports = {
    entry:"./src/js/index.js".output: {filename:"js/builts.js".path:resolve(__dirname,'build')},module: {rules:[
            {
                test:/\.css$/,
                use:[...commonCssLoader]
            },
            {
                test:/\.less$/,
                use:[...commonCssLoader,'less-loader']},// Normally, a file can only be processed by one loader when a file is processed by multiple Loaders
            // Specify the order in which the loader executes; Run esLint before Babel
            {
                test:/\.js$/,
                exclude:/node_modules/.// Priority execution
                enforce:"pre".loader:"eslint-loader".options: {fix:true}}, {test:/\.js$/,
                exclude:/node_modules/,
                loader:'babel-loader'.options: {presets:[
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns:'usage'.corejs: {versions:3
                                },
                                targets: {chrome:'60'.firefox:'50'}}]]}}, {test:/\.(jpg|png|gif)/,
                loader:'url-loader'.options: {limit:8 * 1024.name:"[hash:10].[ext]".outputPath:'imas'.esModule:false
                },
                type:'javascript/auto'
            },
            {
                test:/\.html$/,
                loader:'html-loader'}, {exclude:/\.(js|css|less|html|jpg|png|gif)/,
                loader:'file-loader'.options: {outputPath:'media'}}},plugins: [new MiniCssExtractPlugin({
            filename:'css/built.css'
        }),
        new OptimizeCssAssetsPlugin(),
        new HtmlWebpackPlugin({
            template:"./src/index/html".minify: {collapseWhitespace:true.removeComments:true}})].mode:"production"
}

Copy the code

Webpack optimizes configuration

1.HMR (Optimize packing speed)

HMR: Hot Module replacement or hot module replacement

What it does: When a module sends changes, it repackages only that module, not all modules, greatly increasing build speed

  • 1. Style files: you can use the HMR function because style-loader is implemented internally

  • 2. Js file: HMR function cannot be used by default, js code needs to be modified. Add code to support HMR functionality

Note: the HMR function can only handle non-entry JS files.

if(module.hot){
    // Once module.hot is true, HMR is enabled --> HMR is enabled
    module.hot.accept('./print.js'.function(){
        // The print.js method listens for changes in the print.js file, and when changes occur, other modules are not repackaged and built
        // The following callback functions are executedprint(); })}Copy the code
  • 3. HTML files: HMR cannot be used by default. It also causes problems: HTML files cannot be hot updated

Solution: Modify the entry entry to import the HTML file

module.exports = {
    entry: ['./src/js/index.js'.'./src/index.html'].output: {... }}Copy the code

2. Soure-map (Source code mapping technique)

// Configure the devtool option in webpack.config.js

module.exports = {
    entry: ['./src/js/index.js'].output: {... },module:{
        ...
    },
    plugins:[
        ...
    ]
},
mode:"development".devtool:'hidden-source-map'
Copy the code

Source-map: a technique that provides source-to-build code mapping (mapping to trace source code errors if errors occur after a build)

  • 1.sourec-map(external) : Error code exact information and source code error location
  • 2,inline-source-map(Inline) : Only one inline is generatedsource-mapError code exact information and source code error location
  • 3,hidden-source-map(External) : Error code error cause, but there is no error location, can not trace the source code error, only to the error location of the built code
  • 4,eval-source-map(inline) : each file generates the correspondingsource-map, all ineval, error code exact information and source code error location
  • 5,nosources-source-map(external) : Error code exact information, but no source code information
  • 6,cheap-source-map(external) : Error code exact information, but no source code information, only down to the line
  • 7,cheap-module-source-map(external) : Error code exact information, but no source code information,modulewillloaderthesource-mapjoin

Development environment: Fast, debug friendly, speed (eval>inline> Cheap >..)

Production environment: Should source code be hidden? Is the mode more friendly?

Inlining can make code larger, so inlining is not used in production. Nosource-source-map is completely hidden, and hidden-source-map only hides the source code, prompting error messages when the code is built

3. Cache (performance optimization of live code)

Babel cache, cacheDirectory: true for faster secondary packaging, file resource caching

  • 1.hash: a unique webpack is generated each time the webpack is builthashValue,

Problem: js and CSS use the same hash value, repackaging will invalidate all caches, (maybe I only change one file)

  • 2,chunkshash: Hash value generated by chunk. If the package comes from the same chunk (entry file), the hash value is the same

Problem: JS and CSS still have the same hash value, because CSS is introduced in JS, so it belongs to the same chunk

  • 3,contenthash: Generates a hash value based on the content of the file. The hash value must be different for different files

Make the live code cache more usable (live code performance optimization)

// Add the filename suffix to output

module.exports = {
    entry:"./src/js/index/js".output: {filename:"js/builts.[contenthash:10].js".path:resolve(__dirname,'build')}},Copy the code

The effect

Create the serve.js file to start the server

    // Server code
    // Start the server
    // npm install nodemon -g
    // nodemon server.js
    // Access server address: http://localhost:3000
    
    const express = require('express');
    
    const app = express();
    The exposed build directory is valid for about 1 hour
    app.use(express.static('build', {maxAge: 1000 * 3600 }))
    
    app.listen(3000)
Copy the code

4. Tree shaking

Prerequisites: 1. ES6 modularization must be used; 2

What it does: Reduces code volume and makes requests load faster

Configure in package.json

    "sideEffects":false // All code is tree shaking
Copy the code

Change “sideEffects” to “sideEfects” in WebPackage 5

Problem: It is possible to bring CSS /@babel/polyfill files directly into the file

“SideEfects “:[“*.css”

5. Lazyding (lazy loading and preloading)

// In the entry file index.js

document.getElementById('btn').onclick = function (){
    // Lazy loading: files are loaded only when they are needed
    // Preload: Prefetch preloads the JS file before it is used
    // Normal loading can be considered parallel loading (multiple files are loaded at the same time)
    // Prefetch: Wait until all other resources are loaded and the browser is free
    import(/* webpackChunkName:'test',webpackPrefetch:true */'./test')
    .then(({ mul }) = > {
        console.log(mul(4.5))})}Copy the code

6.PWA (Progressive Web development application — offline accessible)

Install NPM install workbox-webpack-plugin -d

// Configure plugins in webpack.config.js with the following options

plugins: [new WorkboxWebpackPlugin.GenerateSW({
        // 1. Help ServiceWorker start quickly
        Delete the old ServiceWorker
        // Function: Generate a Serviceworker profile
        clientsClaim:true.skipWaiting:true})]1. Eslint does not recognize the window.navigator global variable. Json eslintConfig "env":{"browser":true supports browser-side global variables} 2. Sw code must run on the server --> nodejs --> NPM install serve-g Serve-s build starts the server and exposes all resources in the build directory as static resources */ 


// Register serviceWorker to handle compatibility issues
if('serviceWorker' in navigator){
    window.addEventListener('load'.() = > {
        navugator.serviceWorker.register('./service-worker.js')
        .then(() = > {
            console.log('Sw registered successfully');
        }).catch(() = > {
            console.log('SW registration failed')})})}Copy the code

7. Multithreaded packaging

Install NPM thread-loader -d

// Rules configuration in module webpack.config.js
{
    test:/\.js$/,
    exclude:/node_modules/,
    use:[
        /* Multithreaded packaging is required only when the work takes a long time
        {
            loader:'thread-loader'.options: {// The number of workers generated, by default, is the number of CPU cores
                workers:2.// The number of jobs being performed in a worker process
                // The default is 20
                workerParallelJobs:50.// Additional Node.js parameters
                workerNodeArgs: ['--max-old-space-size'.'1024'].// Delete worker processes when idle
                // the default is 500ms
                // It can be set to infinite to keep the worker alive in watch mode
                poolTimeout:2000.// The number of jobs assigned to the worker by the pool
                / / the default 200
                // Lowering this number will reduce overall efficiency, but will improve work distribution more evenly
                poolParallelJobs:50.// Pool name
                // You can change the name to create a pool with the same other options.
                name:'my-pool'}}}]Copy the code

Externals (exclude some packages from packaging)

For example: the jquery

    const { resolve } = require('path');
    
    const HTMLWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
        entry:"./src/js/index.js".output: {filename:"built.js".path:resolve(__dirname,"build")},plugins: [new HTMLWebpackPlugin({
                template:"./src/index.html"})].mode:"production".// Reject some package parameters packaging
        externals: {// Refuse to package jQuery
            jquery:"jQuery"}}Copy the code

DLL (separate package of code)

Use the DllReferencePlugin in Webpack

NPM install add-asset-html-webpack-plugin -d

    // Plugins in webpack.config.js are configured as follows
    const { resolve } = require('path');
    
    const webpack = require('webpack');
    const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
    module.exports = {
        // entry:....
        plugins: [// Tell WebPack which libraries are not included in the package, and change their names when used
            new webpack.DllReferencePlugin({
                manifest:resolve(__dirname,"dll/manifest.json")})// Package a file and export it to HTML automatically
            new AddAssetHtmlWebpackPlugin({
                filepath:resolve(__dirname,"dll/jquery.js"),
                // Output directory
                outputPath:"auto/"}})]Copy the code

The effect

Webpack configuration details

1. Entry point

  • 1. Single entry :string is used to package a chunk file and output a bundle file. In this case, the default name of chunk is main.

    Code: entry: ‘. / SRC/index ‘

  • 2. Multiple entries: The array type. All entries form only one chunk and only one bundle file is exported.

    Code: Entry :[‘./ SRC /add.js’,’./ SRC /count.js’] (HTML hot updates only work in HMR)

  • 3. Multiple entries: Object: Several entries form several chunks and output several bundle files. The name of chunk is key

    Code: entry: {index: “. / SRC/index. Js “, add: “. / SRC/add. Js “}

  • 4. Special usage: All import files end up as one chunk, and only one bundle is exported

    Code: entry: {index: [“. / SRC/index. Js “, “. / SRC/count. Js “], the add: “. / SRC/add. Js “}

2. Output (packaged output file directory)

module.exports = {
    entry:"./src/index.js".output: {// File name (specified directory + directory)
        filname:"js/[name].js".// Output file directory (public directory for future output of all resources)
        path:resolve(__dirname,'dist'),
        // Introduce a common path prefix for all resources --> "imas/a.jpg --> /imgs/a.jpg"
        publicPath:"/".// The name of the non-entry chunk
        chunkFilename:'[name]_chunk.js'.// The name of the variable exposed throughout the library
        libray:"[name]"./* librayTarget:'window', variable name added to browser librayTarget:'global', variable name added to node librayTarget:'commonjs', To which node */ the variable name is added}}Copy the code

3. Loader configuration in Module

module: {rules: [// Loader configuration
        {
            // Check some files
            test:/\.css$/.// Multiple loaders use use
            use:['style-loader'.'css-loader'] {},test:/\.js$/.// Exclude js files under node_modules
            exclude:/node_modules/.// Check only js files under SRC
            include:resolve(__dirname,'src'),
            // Priority execution
            enforce:"pre".// The execution is delayed
            // enforce:'post'
            // Single loader uses loader
            loader:"eslint-loader"
        },
        {
            // The following configuration will only generate one
            oneOf] : []}}Copy the code

4. Resolve (Resolve module rules)

// Parse the module's rules
resolve: {// Configure the parsing module path alias: advantage short path, disadvantage path is not prompted
    alias: {$css:resolve(__dirname,'src/css')},// Omit the suffix of the path
    extensions: ['.js'.'.json'.'.jsx'.'.css'].// Tells Webpack which directory to look for
    modules:[resolve(__dirname,'.. /.. /node_modules'),'node_modules']}Copy the code

5. DevServer (Development Environment Server)

devServer:{
    // Directory to run the code
    static: {directory:resolve(__dirname,'build')},/ / comtentBase: resolve (__dirname, 'dist), an error
    // Monitor all files in contentBase and reload them if they change
    watchContentBase:true.// Monitor files
    watchOptions: {// Ignore files and do not participate in monitoring
        ignored:/node_modules/
    },
    // Start gzip compression
    compress:true./ / the port number
    port:5000./ / domain name
    host:"localhost".// Automatically open the browser
    open:ture,
    // Enable HMR
    hot:true.// Do not display startup server logs
    clientLogLeval:'none'.// Do not display anything except some basic startup information
    quite:true.
    // If an error occurs, do not display it in full screen
    overlay:false.// Server proxy --> Resolve cross-domain issues in the development environment
    proxy: {// Once devServer(5000) receives a request for/API/XXX, it forwards the request to another address
        'api': {target:'http://localhost:3000'.// if (/ API/XXX --> / XXX)
            pathRewrite: {'^/api':' '}}}}Copy the code

6. Optimization

optimization:{
    splitChunks: {chunks:'all'.// The following is the default value
        // the minimum size of the chunk to be split is 30kb. If the size is smaller than 30kb, the chunk will not be split
        misSize:30 * 1024.// There is no limit to how large a partition can be
        maxSize:0.// The chunks to be extracted should be referenced at least once
        minChunks:1.// The maximum number of files that can be concurrently loaded on demand is 5
        maxAsyncRequests:5.// The maximum number of parallel requests for entry js files is 3
        maxInitialRequest:3.// Name concatenation
        automaticNameDelimiter:'~'.// You can use naming conventions
        name:true.// Split the chunk group
        cacheGroups: {// node_modules files are packaged into vendors group chunk --> vendrors~ XXX.js
            // Meet the above common rules: if the size exceeds 30KB, be referenced at least once
            vendors: {test:/[\\/]node_modules[\\/]/./ / priority
                priority:-10
            },
            default: {// The chunk to be extracted must be referenced at least twice
                minChunks:2./ / priority
                priority: -20.// If the current module to be packaged is the same module that has already been extracted, it will be reused
                reuseExistingChunk:ture
            }
        }
    },
    // Package the hash of the current module into a single file runtime
    // Error: The contenthash value of file B changes as a result of modifying file A
    / / address:
    runtimeChunk: {name:entrypoint= > `runtime=${entrypoint.name}`
    },
    minimizer: [// Configure the compression scheme for the production environment: JS and CSS
        new TerserWebpackPlugin({
            // terserOptions:{
                // Enable caching
                // cache:true,
                // Enable multi-threaded packaging
                parallel:true./ / start the source - the map
                // sourceMap:true}}})]Copy the code

Webpack5 introduction

conclusion

If you find this article helpful, give it a thumbs up and a pat on the back.