How to use webpack to optimize the development / production environment

Keywords: Javascript Front-end Webpack

HMR hot module replacement / module hot replacement

Function: when a module changes, it will only update the module (not package all) to improve the speed
Style file: you can use the HRM function because the style loader is implemented internally
js file: no HRM by default
html file: there is no HRM by defau lt, and the html file cannot be hot updated (local code cannot be recompiled) < just one file, no HMR function is required >

  • Solution: modify the entry entry and import html files
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
module.export={
   entry:['./src/index.js','./src/index.html'],
   output:{
   filename:'built.js',
   path:resolve(_dirname,'build')
   },
   module: {
     rules: [
        module: {
     rules: [
       //Detailed loader configuration 
       { 
         //Handling css resources
         test:/\.css$/,
         use:[
           'style-loader',//(it's a package)
           'css-loader',//(it's a package)
         ]
       },
       { 
         //Handling less resources
         test:/\.less$/,
         use:[
           'style-loader',//(it's a package)
           'css-loader',//(it's a package)
           'less-loader'
         ]
       },
       {
         //Processing picture resources
         test:/\.(jpg|png|gif)$/,
         loader:'url-loader'
         options:[
           limit:8*1024
           name:'[hash:10].[ext]',
           //Turn off es6 modularization
           esModule:false,
           outputPath:'imgs'//Change output path
         ]
       },
        {
         test:/\.html$/,
         //Processing img images of html files
         loader:'html-loader'
         name:'[hash:10].[ext]'
       },
       {
       //Package other resources
         exclude:/\.(css|js|html|less|jpg|png|gif)$/,
         loader:'file-loader',
         //Modify name
         options:{
         name:'[hash:10],[ext]'
       },
     ]
   },
   //Configuration of plugin
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'
     })
   ],
   //pattern
   mode:'development'
     devServer:{
     //Path after project construction
      contentBase:resolve(_dirname,'build'),
      //Start gzip compression
      compress:true,
      //Port number
      port:3000,
      //Open browser automatically
      open:true,
      //Turn on HMR function
      //When the webpack configuration is modified, be sure to restart the webpack service
      hot:true
  }
}

js thermal module
Write in the index.js file

For non portal files js
import print from './print';
if(module.hot){
  //Once module.hot is true, the HMR function is enabled -- > to make the HMR function code take effect
  module.hot.accept('./print.js',function(){
  //Method listens for changes in the print.js file. Once changes occur, other modules will not be repackaged and built, and the following callback functions will be executed
  print();
}

Debugging code in development environment (source map)

A technology that provides source code to post build code to mapping (if the post build code is wrong, it can be traced to the directory of source code through mapping)
[inline-|hidden-|eval-][nosources-][cheap-[module]]source-map

  • Source map: Outreach
    Prompt the accurate information of the error code and the error location of the source code
  • Inline source map: inline: only one source map is generated
    Prompt the accurate information of the error code and the error location of the source code
  • Hidden source map: Outreach
    Prompt the error code and error reason, but there is no error location, and the source code error cannot be traced
  • Eval source map: inline: each file generates a corresponding source map in the eval function
    Prompt the accurate information of the error code and the error location of the source code
  • Mosources source map: Outreach
    Prompt the accurate information of the error code, and there is no source code error location
  • Soap source map: Outreach
    Prompt the accurate information of the error code and the error location of the source code, which can only be accurate to the line
  • Soap module source map: Outreach
    Prompt the accurate information of the error code and the error location of the source code

1. Production environment: fast and friendly debugging (inlining will make the code large, so it is excluded) source map
2. Development environment: source code hiding? Mode friendly? eval-source-map

Differences between inline and extranet 1. Files are generated externally, but not inline 2. Inline construction is faster

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
module.export={
   entry:['./src/index.js','./src/index.html'],
   output:{
   filename:'built.js',
   path:resolve(_dirname,'build')
   },
   module: {
     rules: [
        module: {
     rules: [
       //Detailed loader configuration 
       { 
         //Handling css resources
         test:/\.css$/,
         use:[
           'style-loader',//(it's a package)
           'css-loader',//(it's a package)
         ]
       },
       { 
         //Handling less resources
         test:/\.less$/,
         use:[
           'style-loader',//(it's a package)
           'css-loader',//(it's a package)
           'less-loader'
         ]
       },
       {
         //Processing picture resources
         test:/\.(jpg|png|gif)$/,
         loader:'url-loader'
         options:[
           limit:8*1024
           name:'[hash:10].[ext]',
           //Turn off es6 modularization
           esModule:false,
           outputPath:'imgs'//Change output path
         ]
       },
        {
         test:/\.html$/,
         //Processing img images of html files
         loader:'html-loader'
         name:'[hash:10].[ext]'
       },
       {
       //Package other resources
         exclude:/\.(css|js|html|less|jpg|png|gif)$/,
         loader:'file-loader',
         //Modify name
         options:{
         name:'[hash:10],[ext]'
       },
     ]
   },
   //Configuration of plugin
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'
     })
   ],
   //pattern
   mode:'development'
     devServer:{
     //Path after project construction
      contentBase:resolve(_dirname,'build'),
      //Start gzip compression
      compress:true,
      //Port number
      port:3000,
      //Open browser automatically
      open:true,
      //Turn on HMR function
      //When the webpack configuration is modified, be sure to restart the webpack service
      hot:true
  },
  //Add something
  devtool:'eval-source-map'
}

oneOf

Improve construction speed

//When a file is processed by multiple loaders, it is necessary to specify the order of execution of loaders in js (execute eslint first and then babel)
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const 	MiniCssExtractPlugin=require('mini-css-extract-plugin');
const 	OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
//Reuse loader
const commonCssLoader=[
  MiniCssExtractPlugin.loader,
  'css-loader',
  {//For compatibility, define browserlist in package.json
    loader:'postcss-loader',
    //Modify configuration
    potions:{
    ident:'postcss',
    plugins:()=>[
      //postcss plug-in
      require('postcss-preset-env')()
    ] 
    }
  }
];
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.js',
   path:resolve(_dirname,'build')
   },
   module: {
     rules: [
     {
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            //Meaning of priority implementation
            enforce:'pre'
            options:{
              //Automatically fix eslint errors
            fix:true 
         },
     oneOf:[//Only one of the following loader s will match. Two configurations cannot process files of the same type
       {
         test:/\.css$/,
         use:[commonCssLoader]
        },
        {
          test:/\.less$/,
          use:[...commonCssLoader, 'less-loader']
         },
         {//Eslintconfig -- > airbnb in package.json
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //Specify corejs version
                      corejs:{
                        version:3            
                      },
                     //Which version of browser is compatible
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ]
              ]
            }
           },
           {
             test:/\.(jpg|png|gif)$/,
             loader:'url-loader',
             options:{
               limit:8*1024,
               name:'[hash:10].[text]',
               outputath:'imgs',
               esModule:false
             }
           },//img in html
           {
             test:/\.html$/,
             loader:'html-loader'
           },
           {
              //Package other resources
             exclude:/\.(css|js|html|less|jpg|png|gif)/,
             loader:'file-loader',
             options:{
               outputPath:'media',
               name:'[hash:10],[ext]'
             }
            },
           
   },
   //Configuration of plugin
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html',
       //Compress the html code, which compresses the configuration
       minify:{
         //Collapse spaces
         collapseWhitespace:true,
         //Remove comment
         removeComments:true
       }
     }),
     new MiniCssExtractPlugin({
       //If you want to enter / rename into the css directory
       filename:'css/built.css'
     }),
     //Compressing css: will run faster
     new OptimizeCssAssetsWebpackPlugin(),
   ],
   //Automatic compression of js code in production mode
   mode:'production'
}

cache

  • babel: CacheDirectory:true – > make the second package build faster
  • File resource modify file name hash: a unique hash value is generated each time the webpack is built and packaged
    Problem: because js and css use the same hash value, repackaging will invalidate all caches
    Chunk hash: the hash value generated by chunk. If the package comes from the same trunk, the hash value is the same
    Problem: the hash values of js and css are the same. Because css is introduced in js, it belongs to the same trunk
    What is a trunk? All js and css imported according to the entry file will use a trunk, which is a code block
    contenthash: the hash generated according to the contents of the file. The hash values of different files must be different – > make the code run online and cache faster
//When a file is processed by multiple loaders, it is necessary to specify the order of execution of loaders in js (execute eslint first and then babel)
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const 	MiniCssExtractPlugin=require('mini-css-extract-plugin');
const 	OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
//Reuse loader
const commonCssLoader=[
  MiniCssExtractPlugin.loader,
  'css-loader',
  {//For compatibility, define browserlist in package.json
    loader:'postcss-loader',
    //Modify configuration
    potions:{
    ident:'postcss',
    plugins:()=>[
      //postcss plug-in
      require('postcss-preset-env')()
    ] 
    }
  }
];
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.[hash:10].js', //The generated resource has a hash value
   path:resolve(_dirname,'build')
   },
   module: {
     rules: [
     {
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            //Meaning of priority implementation
            enforce:'pre'
            options:{
              //Automatically fix eslint errors
            fix:true 
         },
     oneOf:[//Only one of the following loader s will match. Two configurations cannot process files of the same type
       {
         test:/\.css$/,
         use:[commonCssLoader]
        },
        {
          test:/\.less$/,
          use:[...commonCssLoader, 'less-loader']
         },
         {//Eslintconfig -- > airbnb in package.json
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //Specify corejs version
                      corejs:{
                        version:3            
                      },
                     //Which version of browser is compatible
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ],
                //Enable babel cache
                //On the second build, the previous cache is read
                CacheDirectory:true
              ]
            }
           },
           {
             test:/\.(jpg|png|gif)$/,
             loader:'url-loader',
             options:{
               limit:8*1024,
               name:'[hash:10].[text]',
               outputath:'imgs',
               esModule:false
             }
           },//img in html
           {
             test:/\.html$/,
             loader:'html-loader'
           },
           {
              //Package other resources
             exclude:/\.(css|js|html|less|jpg|png|gif)/,
             loader:'file-loader',
             options:{
               outputPath:'media',
               name:'[hash:10],[ext]'
             }
            },
           
   },
   //Configuration of plugin
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html',
       //Compress the html code, which compresses the configuration
       minify:{
         //Collapse spaces
         collapseWhitespace:true,
         //Remove comment
         removeComments:true
       }
     }),
     new MiniCssExtractPlugin({
       //If you want to enter / rename into the css directory
       filename:'css/built.css'
     }),
     //Compressing css: will run faster
     new OptimizeCssAssetsWebpackPlugin(),
   ],
   //Automatic compression of js code in production mode
   mode:'production'
}

tree shaking

Remove code that is not used in the application
Prerequisites: 1. You must use es6 modularization. 2. Start the production environment
Function: reduce code volume
Configure in package.json

"sideEffects":false;//All codes have no side effects (tree shaking can be performed)
//Problem: can you kill the css/ @babel/polyfill file
"sideEffects":["*.css","*.less"];//solve

code split

module.export={
//Single entry
  // entry:'./src/index.js',
  entry:{
    //Multiple entries: with one entry, the final output will have a bundle
    main:'./src/index.js',
    test:'./src/test.js',
  }
   output:{
   //[name] get file name
   filename:'built.[name].[hash:10].js', //The generated resource has a hash value
   path:resolve(_dirname,'build')
   },
   //Configuration of plugin
   plugins:[
   ],
   //Node can be_ The code in modules is packaged separately into a chunk final output
   //Automatically analyze whether there are public files in multi entry files. If there are, they will be packaged into a separate trunk
   optimzation:{
     splitChunks:{
     chunks:'all'
     }
   }
   //Automatic compression of js code in production mode
   mode:'production'
}

The third way is to package a file into a trunk through js code
On the index.js page
Import dynamic import syntax: a file can be packaged separately

import('./test')
  .then(()=>{
    //File loaded successfully
  })
  .catch(()=>{
    //File loading failed
  })

Lazy loading and preloading

Lazy loading of js files (only when certain conditions are triggered)

//Lazy loading -- it is placed in the function and loaded when the function is called: it is loaded only when it needs to be loaded
//Preload prefetch: the js file will be loaded in advance
//Normal loading can be considered as parallel loading (loading multiple files at one time) preloading: when other resources are loaded and the browser is idle, download them secretly
//'/ * webpackChunkName:'test',webpackPrefetch:true * /' split into two files
import('/*webpackChunkName:'test'*/'./test').then(()=>{
 console.log('Loading succeeded after a period of time')
}

PWA (progressive network development application)

It can also be accessed offline
workbox download package

//When a file is processed by multiple loaders, it is necessary to specify the order of execution of loaders in js (execute eslint first and then babel)
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const 	MiniCssExtractPlugin=require('mini-css-extract-plugin');
const 	OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
const 	WorkboxWebpackPlugin=require('workbox-webpack-plugin');
//Reuse loader
const commonCssLoader=[
  MiniCssExtractPlugin.loader,
  'css-loader',
  {//For compatibility, define browserlist in package.json
    loader:'postcss-loader',
    //Modify configuration
    potions:{
    ident:'postcss',
    plugins:()=>[
      //postcss plug-in
      require('postcss-preset-env')()
    ] 
    }
  }
];
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.[hash:10].js', //The generated resource has a hash value
   path:resolve(_dirname,'build')
   },
   module: {
     rules: [
     {
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            //Meaning of priority implementation
            enforce:'pre'
            options:{
              //Automatically fix eslint errors
            fix:true 
         },
     oneOf:[//Only one of the following loader s will match. Two configurations cannot process files of the same type
       {
         test:/\.css$/,
         use:[commonCssLoader]
        },
        {
          test:/\.less$/,
          use:[...commonCssLoader, 'less-loader']
         },
         {//Eslintconfig -- > airbnb in package.json
            test:/.js$/,
            exclude:/node_modules/,
            loader:'babel-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //Specify corejs version
                      corejs:{
                        version:3            
                      },
                     //Which version of browser is compatible
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ],
                //Enable babel cache
                //On the second build, the previous cache is read
                CacheDirectory:true
              ]
            }
           },
           {
             test:/\.(jpg|png|gif)$/,
             loader:'url-loader',
             options:{
               limit:8*1024,
               name:'[hash:10].[text]',
               outputath:'imgs',
               esModule:false
             }
           },//img in html
           {
             test:/\.html$/,
             loader:'html-loader'
           },
           {
              //Package other resources
             exclude:/\.(css|js|html|less|jpg|png|gif)/,
             loader:'file-loader',
             options:{
               outputPath:'media',
               name:'[hash:10],[ext]'
             }
            },
           
   },
   //Configuration of plugin
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html',
       //Compress the html code, which compresses the configuration
       minify:{
         //Collapse spaces
         collapseWhitespace:true,
         //Remove comment
         removeComments:true
       }
     }),
     new MiniCssExtractPlugin({
       //If you want to enter / rename into the css directory
       filename:'css/built.css'
     }),
     //Compressing css: will run faster
     new OptimizeCssAssetsWebpackPlugin(),
     new WorkboxWebpackPlugin.GenerateSW({
     //Help service worker start quickly
     //Delete old serviceworker
     //Generate a serviceworker configuration file
       clientsClaim:true,
       skipWaitting:true
     })
   ],
   //Automatic compression of js code in production mode
   mode:'production'
}

Register serviceworker
In the entry file

//Note: 1.eslint doesn't know window. navigator global variable
 Solution: repair required package.json in eslintConfig to configure
2.sw The agent must run on the server-->nodejs  -->npm i serve -g    serve -s build 
Start the server, and the build All resources in the directory are exposed as static resources

"env":{
  "browser":true//Support browser side global variables
}//
//Register serviceworker
//Handling compatibility issues
if('serviceworker' in navigator){
  window.addEventListener('load',()=>{
    navigator.serviceworker.register('/service-worker.js')
    .then(()=>{
      console.log('Registration succeeded')
     })
    .catch(()=>{
      console.log('Registration failed')
    })
}

Multi process packaging

Download thread loader, usually for Babel loader

         {//Eslintconfig -- > airbnb in package.json
            test:/.js$/,
            exclude:/node_modules/,
            use:[
            //Start multi process packaging. The process has time to start, about 600ms. The process communication also has overhead
            //Only when the work takes a long time, multi process packaging is required
              'thread-loader',
              //Modify configuration
              options:{
                workers:2//2 processes
              }
              {
                loader:'babel-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //Specify corejs version
                      corejs:{
                        version:3            
                      },
                     //Which version of browser is compatible
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ],
                //Enable babel cache
                //On the second build, the previous cache is read
                CacheDirectory:true
              ]
            }
              }
            ],
            
           },

externals and dill (Dynamic Link Library)

The difference is: dill packages the library separately, some do not package, and some split and package into multiple libraries

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const webpack=require('webpack');
const AddAssetHtmlWebpackPlugin=require('add-asset-html-webpack-plugin');
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.[hash:10].js', //The generated resource has a hash value
   path:resolve(_dirname,'build')
   },
   module: {
     rules: []
   },
   //Configuration of plugin
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html',
     }),
     //Tell webpack which libraries do not participate in packaging, and change their names when using them
      new webpack.DillPlugin({
      mainfes:resolve(_dirname,'dill/mainfest.json'),
      //Package and output a file and introduce the resource into html
      new AddAssetHtmlWebpackPlugin({
        filepath:resolve(_dirname,'dill/jquery.json'),
      })
   ],
   //Automatic compression of js code in production mode
   mode:'production',
   externals:{//fast
     //Reject package package -- npm package
     jquery:'jQuery'
   }
}
stay index.js Page introduction

Dill package, create webpack.dill.js
Use dill technology to package some libraries separately (jQuery, react, vue...)
Run – > webpack -- config webpack.dill.js

const {resolve}=require('path');
const webpack=require('webpack');
module.export={
   entry:{//The final package generates [name] -- > jQuery
     //['jquery '] -- > the library to package is jQuery
     jquery:['jquery']
   },
   output:{
     filename:'[name].js', 
     path:resolve(_dirname,'dill'),
     libiary:'[name]_[hash]',//The name of the content exposed to the outside in the packaged library
   },
   plugins:[
     new webpack.DillPlugin({
       name:'name_[hash]',//The exposed content name of the mapping library
       path:resolve(_dirname,'dill/mainfest.json'),//Output file path
   ],
   mode:'production'
  }

summary

Posted by PugJr on Tue, 07 Dec 2021 00:22:02 -0800