1 Introduction
Environment: nodejs 10 +, webpack 4.26+
webpack: front-end resource building tool and static module packer, which treats all front-end resources as modules, analyzes dependencies and packages them into static resource bundle s. You can compile and transform. The browser cannot recognize the latest syntax: es6 or less. webpack is equivalent to a collection of tools, which contains many gadgets.
Process: enter from the portal, analyze various resources that the portal file depends on, and introduce them to form a chunk. Analyze and compile various resources in chunk to form a bundle.
2. Five core concepts of webpack
- Entry: entry, which file is the starting point for webpack to analyze and build the dependency graph.
- Output: the destination and naming rules of the packaged bundle output
- Loader: extension, file type recognized by webpack (only js is recognized by default)
- Plugins: plug-in with stronger functions, which is equivalent to function expansion
- Mode: mode, development and production. Selecting different modes will automatically enable different plug-ins
- Development: process.env.NODE_ENV=development, enable: NamedChunksPlugin and NamedModulesPlugin
- Production: process.env.NODE_ENV=production, enable: FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin, UglifyJsPlugin
3 try
Global installation: NPM I webpack webpack cli - G
Local installation: NPM I webpack webpack cli - D
3.1 package js/json
Prerequisite preparation: create a new build directory, src directory, src/index.js file, and install webpack and webpack cli in the local npm
Execution: webpack. / SRC / index.js - O. / build / build. JS -- mode = development (will compile es6 modularization into browser recognizable modularization)
index.js Code:
import data from './data.json' console.log(data) function add(a,b){return a+b} console.log(add(1,2))
data.json Code:
{ "name":"pp", "age":12, "sex":"male" }
Execution: webpack. / SRC / index.js - O. / build / build. JS -- mode = production (indicates the production environment and compresses the code)
3.2 packaging css/less
css files are imported into index.js, and then packaged normally. An error is reported when packaging, indicating that webpack does not support css/img by default and requires a loader to translate unrecognized files
The use of loader requires [download and configuration] to take effect
webpack.config.js configuration file. If you need to configure detailed parameters, create a configuration file to use
Special note: since the build tool is based on nodejs and adopts commonjs for modularization, the configuration file export uses: module.exports
const { resolve } = require('path') module.exports = { entry: './src/index.js', output: { filename: 'built.js', // The path must be a full path, so use the path in nodejs to get it path: resolve(__dirname,'build') }, // loader configuration module: { rules: [ // Detailed configuration { // test indicates the matching file type test: /\.css$/, // Which loader s are used and the execution order is from back to front use: [ 'style-loader', // Insert the style string in js into the style tag and put it into the head tag to take effect 'css-loader' // Load the css file programming commonjs module into js, and the content is the style string ] } ] }, // plugins plug-in configuration plugins: [ ], mode: 'development', // mode: 'production' }
If you need to package less: you need to configure the less loader, as shown below
To process less files, add a loader after css loader. Note: each loader can only process one file type
{ test: /\.less$/, use: ['style-loader','css-loader','less-loader'] }
After configuration, relevant modules need to be downloaded: NPM I less less loader - D
3.3 packaging html
The html package uses a plug-in. The plug-in needs to be downloaded, imported and configured to take effect
Download: HTML webpack plugin: NPM I HTML webpack plugin - D
Import and configuration: webpack.config.js
const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname,'build') }, // loader configuration module: { rules: [] }, // plugins plug-in configuration plugins: [ new HtmlWebpackPlugin({ // By default, an empty html file is created and all resources of the packaged output are introduced. If a template is required, the configuration {template} needs to be passed in template: './src/index.html' // Use this file as a template }) ], mode: 'development', // mode: 'production' }
Note: do not manually import resources in the html template file. They will be imported automatically. Just import resources in the entry file
3.4 packaged pictures
There are two kinds of referenced pictures:
- url import in style file
- Introduction of src in html
For the introduced in css style files, you need to install URL loader and file loader and configure webpack:
const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname,'build') }, // loader configuration module: { rules: [ { // test indicates the matching file type test: /\.css$/, // Which loader s are used and the execution order is from back to front use: [ 'style-loader', // Insert the style string in js into the style tag and put it into the head tag to take effect 'css-loader' // Load the css file programming commonjs module into js, and the content is the style string ] }, { test: /\.(jpg|png|gif)$/, // Multiple file types are written like this loader: 'url-loader', // A loader writes like this options: { // Additional configuration of this loader limit: 8*1024 // 8kb, less than this value will be encoded by base64 } } ] }, // plugins plug-in configuration plugins: [ new HtmlWebpackPlugin({ // By default, an empty html file is created and all resources of the packaged output are introduced. If a template is required, the configuration {template} needs to be passed in template: './src/index.html' // Use this file as a template }) ], mode: 'development', // mode: 'production' }
base64 image processing can reduce the number of requests and reduce the pressure on the server, but the image size may be larger, so it is generally used to process images below 8kb
For src imported in html: you need to Download html loader, which is specially used to handle src imported pictures in html so that they can be parsed by URL loader
{ test: /.\html$/, loader: 'html-loader' }
Here, we will find the wrong picture reference in html. The reason is: html loader is exported in common JS modularization, while URL loader is parsed in es6 modularization
Solution: turn off es6 modularization of URL loader and use the default commonjs parsing
{ test: /\.(jpg|png|gif)$/, // Multiple file types are written like this loader: 'url-loader', // A loader writes like this options: { // Additional configuration of this loader limit: 8*1024, // 8kb, less than this value will be encoded by base64 esModule: false // Turn off the es6 modularization of the loader and use commonjs for parsing (because the picture mode introduced after HTML loader parsing adopts commonjs) } }
Rename the imported image: name:'[hash:10].[ext], and take the top 10 digits of the image hash value
{ test: /\.(jpg|png|gif)$/, // Multiple file types are written like this loader: 'url-loader', // A loader writes like this options: { // Additional configuration of this loader limit: 8*1024, // 8kb, less than this value will be encoded by base64 esModule: false, // Turn off the es6 modularization of the loader and use commonjs for parsing (because the picture mode introduced after HTML loader parsing adopts commonjs) name:'[hash:10].[ext]' } }
3.5 packaging other resources
Other resources: for resources other than css/js/html, you can use exclude to match all resources except the excluded type. You only need to configure in the loader:
{ exclude: /\.(css|js|html)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]' } }
All resources excluding css/js/html will be packaged and processed by this loader
3.6 devServer
Configure the development server to automatically compile, package, open the browser, refresh and see the effect after the change
// It will be packaged in memory without any output // Start: webpack dev server devServer: { contentBase: resolve(__dirname,'build'), // The directory to run the project. If HTML webpack plugin is configured, the configuration will not work compress: true, // Start gzip compression port: 3000 // Port number open: true // Open browser automatically }
You need to install: NPM I - D webpack dev server first
Configure the instruction in package.json: "start": "webpack dev server", and then use npm run start to start
Note: after webpack 5, the startup command is changed to: webpack serve
Once the source code is modified and saved, it will be compiled automatically and displayed on the page
4 basic configuration of environment
4.1 development environment
Packaging: js, json, html, css, less, img, file and other resources
const {resolve} = require("path") const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'js/built.js', // The storage place of the entry file, which includes the combination of js and css path: resolve(__dirname,'build') // All resource storage locations }, module: { rules: [ { test: /\.less$/, use: ['style-loader','css-loader','less-loader'] }, { test: /\.css$/, use: ['style-loader','css-loader'] }, { test: /\.(jpg|png|jpeg|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'imgs' } }, { test: /.\html$/, loader: 'html-loader' }, { exclude: /\.(html|js|css|less|jpg|png|jpeg|gif)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'medias' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], // It will be packaged in memory without any output // Start: webpack dev server devServer: { contentBase: resolve(__dirname,'build'), // The directory in which the project is running compress: true, // Start gzip compression port: 3000, // Port number open: true // Open browser automatically }, mode: 'development' }
4.2 production environment
In order to make the code faster, better performance and more stable (these need not be considered in the development environment)
- In the development environment, css and js are bundle s packaged together. In the loading process, first load js, and then create a style tag to load css, which will cause a flashing phenomenon
- The code needs to be compressed uniformly
- Style compatibility
4.2.1 extracting CSS to a separate file
Plug in to be installed: NPM I - D Mini CSS extract plugin
Step: register the plug-in and replace the style loader with MiniCssExtractPlugin.loader (sytle loader creates a style tag for the style string in js and inserts it into html. Now MiniCssExtractPlugin.loader extracts the style string in js into a separate file and introduces the style tag)
const {resolve} = require("path") const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { entry: './src/index.js', output: { filename: 'js/built.js', // The storage place of the entry file, which includes the combination of js and css path: resolve(__dirname,'build') // All resource storage locations }, module: { rules: [ ... { test: /\.css$/, use: [MiniCssExtractPlugin.loader,'css-loader'] }, ... ] }, plugins: [ ... new MiniCssExtractPlugin({ filename: 'css/built.css' }) ], ... }
4.2.2 css compatibility processing
You need to use: postcss loader and postcss preset env (for accurate browser version)
Installation: NPM I - D postcss loader postcss preset env
const { resolve } = require("path") const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') // Set the node environment variable in this way, and postcss will read the environment variable to determine whether to read the production or development configuration // process.env.NODE_ENV = "development" process.env.NODE_ENV = "production" module.exports = { entry: './src/index.js', output: { filename: 'js/built.js', // The storage place of the entry file, which includes the combination of js and css path: resolve(__dirname, 'build') // All resource storage locations }, module: { rules: [{ test: /\.less$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [ require('postcss-preset-env')() ] } } }, 'less-loader', ] }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader' { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [ require('postcss-preset-env')() ] } } } ] }, ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' }) ], }
Special note: 1. The node environment variable needs to be configured: process.env.NODE_ENV = “production”; 2, Configure the postcss loader and its parameters. This loader needs to be processed by CSS loader first. 3, Configure browserlist in package.json
Configure browserslist in package.json to specify the css compatibility style to load
"browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.2%", "not dead", "not op_mini all" ] }
For the detailed configuration of browserslist, you can query on github. Note: by default, the plug-in implements the production environment configuration, unless the Node environment variable is configured (independent of the mode in webpack.config.js)
The compiled css code adds compatible styles
#b { display: -webkit-flex; display: flex; -webkit-backface-visibility: hidden; backface-visibility: hidden; }
4.2.3 css compression
A plug-in is required: optimize CSS assets webpack plugin
Installation: NPM I - D optimize CSS assets webpack plugin
Configuration method: import the plug-in and use the new plug-in.
const {resolve} = require("path") const MiniCssExtractPlugin = require('mini-css-extract-plugin') const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'js/built.js', // The storage place of the entry file, which includes the combination of js and css path: resolve(__dirname,'build') // All resource storage locations }, module: { rules: [ ... { test: /\.css$/, use: [MiniCssExtractPlugin.loader,'css-loader'] }, ... ] }, plugins: [ ... new MiniCssExtractPlugin({ filename: 'css/built.css' }), new OptimizeCssAssetsWebpackPlugin() ], ... }
Note: there is a 'cssnano': {} configuration in the postcss loader, which can also be used to compress css! Example: cssnano: CTX. Env = = 'production'? {} : false
4.2.4 JS syntax check - eslint
Eslint is used for js syntax checking and needs to be installed: eslint loader and eslint
Note: due to the requirement to check only the source code under src, no third-party libraries are checked (use exclude)
The eslint check rule needs to be set in the eslintConfig attribute in package.json. It is recommended to use the airbnb rule
Eslint config airbnb base: basic check library, excluding react plug-in. The library depends on eslint plugin import eslint
Eslint config airbnb: includes the react plug-in
Steps: (you need to install: NPM I - D eslint eslint loader eslint config airbnb base eslint plugin import)
- loader configuration
{ test: /\.js$/, loader: 'eslint-loader', enforce: "pre", // Pre compile check exclude: /node_modules/, // Undetected files include: [path.resolve(__dirname, 'src')], // Specify the directory to check options: { // The configuration item parameters here will be passed to the client engine of eslint fix: true // Automatically fix errors } }
- package.json configuration, where airbnb syntax rules are used
"eslintConfig":{ "extends":"airbnb-base" }
You can use comments to cancel the check: / / eslint disable next line cancels the syntax check on the next line, / * eslint disable * / placed on the first line of the file means that the file is not checked
reference resources: https://blog.csdn.net/kai_vin/article/details/89026115
4.2.5 JS compatibility processing
JS compatibility means that some browsers do not support ES6 syntax, and babel will transcode it into ES5, relying on @ babel/core, which is called compatibility processing. The loader used is babel loader, which can convert different syntax according to the preset environment.
[basic compatibility processing]: @ Babel / preset Env,
Installation: NPM I - D Babel loader @ Babel / core @ Babel / preset env
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } }
Only basic functions such as const and arrow functions can be converted. Promise is not supported.
[violence handling] all js compatible handling: @ babel/polyfill
Installation: npm i -D @babel/polyfill
Use: import in the entry file: import '@babel/polyfill
@babel/polyfill has been replaced by: core JS / stable + regenerator Runtime / runtime, using:
import "core-js/stable"; import "regenerator-runtime/runtime";
[load compatibility processing on demand] use core JS
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ '@babel/preset-env', { useBuiltIns: 'usage', // Turn on demand loading corejs: {version: 3}, // Specify the core JS version targets: {chrome:'60',firefox:'60',ie:'9',safari:'10',edge:'17'} // Specify which version is more compatible } ] } }
Note: violent treatment cannot be used with this program
4.2.6 html and js compression
js compression: just turn on mode='production '(the plug-in that works is UglifyJsPlugin)
html compression: similarly, you only need to turn on the production mode. Of course, you can also configure it in the plug-in html webpack plugin:
new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, // Remove spaces removeComments: true // Remove comment } }),
4.2.7 ultimate configuration of production environment
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') // Set the node environment variable in this way, and postcss will read the environment variable to determine whether to read the production or development configuration // process.env.NODE_ENV = "development" process.env.NODE_ENV = "production" const commonCssLoader = [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [ require('postcss-preset-env')() ] } } } ] module.exports = { entry: './src/index.js', output: { filename: 'js/built.js', // The storage place of the entry file, which includes the combination of js and css path: resolve(__dirname, 'build') // All resource storage locations }, module: { rules: [{ test: /\.less$/, use: [ ...commonCssLoader, 'less-loader' ] }, { test: /\.css$/, use: [ ...commonCssLoader ] }, { test: /\.(jpg|png|jpeg|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'imgs' } }, { test: /.\html$/, loader: 'html-loader' }, { exclude: /\.(html|js|css|less|jpg|png|jpeg|gif)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'medias' } }, { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ '@babel/preset-env', { useBuiltIns: 'usage', // Turn on demand loading corejs: {version: 3}, // Specify the core JS version targets: {chrome:'60',firefox:'60',ie:'9',safari:'10',edge:'17'} // Specify which version is more compatible } ] } }, { test: /\.js$/, loader: 'eslint-loader', enforce: "pre", // Check before compilation. If the attribute is true in the same test, execute it first exclude: /node_modules/, // Undetected files include: [path.resolve(__dirname, 'src')], // Specify the directory to check options: { // The configuration item parameters here will be passed to the client engine of eslint fix: true } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, // Remove spaces removeComments: true // Remove comment } }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), new OptimizeCssAssetsWebpackPlugin() ], // It will be packaged in memory without any output // Start: webpack dev server devServer: { contentBase: resolve(__dirname, 'build'), // The directory in which the project is running compress: true, // Start gzip compression port: 3000, // Port number open: true // Open browser automatically }, mode: 'production' }
In package.json:
{ ... "scripts": { ... "build": "webpack", "start": "webpack serve" }, ... "browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.2%", "not dead", "not op_mini all" ] }, "eslintConfig":{ "extends":"airbnb-base" } }
5 webpack optimization
Optimization of two environments
Development environment: 1 optimize the speed of packaging and construction 2 optimize code debugging
Production environment: 1 optimize the speed of packaging and construction 2 optimize the performance of code operation
5.1 development environment
Question 1: if any module is modified, all modules of the whole project will be reloaded
Solution: HMR: hot module replacement. A module change will only package the module, not all modules
Add: hot:true in devServer
devServer: { contentBase: resolve(__dirname, 'build'), // The directory in which the project is running compress: true, // Start gzip compression port: 3000, // Port number open: true, // Open browser automatically hot: true // Thermal loading },
For style modification, because style loader implements HMR function, hot module update can be realized
For JS files, there is no HMR function
Solution: add HMR function
// In the entry file, listen for updates to other imported modules if(module.hot){ module.hot.accept('./xxx.js',function(){Callback function} }
Note: the entry js file does not need or can not be used for HMR, because it will be reintroduced if it changes other functions
For HTML files, you cannot use the HMR function (because HTML has only one file), and you cannot respond to updates after opening it
Solution: add html file entry in webpack.config.js: entry: ['./src/index.js','./src/index.html '],
Source map: provides the mapping technology between source code and built code to facilitate the query and location of error causes
Configuration: add: devtool: 'source map' in webpack.config.js
Note: source map has multiple values:
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
Of which:
Source map: locate the external error to the [source] code, accurate to rows and columns
Inline source map: locate the [source] code for the inline error
Hidden source map: locate the external error to the [compiled] code
Eval source map: locate the [source] code for the inline error
Nosources source map: the external error is located in the [source] code, but cannot be viewed
Soap source map: the external error is located in the [source] code, which is accurate to the row but not to the column
Soap module source map: the external error is located in the [source] code. The accuracy is a little better...
The mapping generated by introversion is faster to build in packaged js, and the external mapping is at the same level of js
Recommended for development: Eval source map
Recommended for production: source map