1 Introduction to webpack
1.1 what is a webpack
Webpack is a front-end resource building tool, a static module bundler. In the view of webpack, all resource files (js/json/css/img/less /...) of the front end will be processed as modules. It will perform static analysis according to the dependency of the module and package the corresponding static resources (bundles).
1.2 five core concepts of webpack
1.2.1Entry
The entry indicates which file is the starting point for webpack to start packaging, analyze and build the internal dependency diagram.
1.2.2Output
Output indicates where and how to name the resource bundles packaged by webpack.
1.2.3Loader
Loader enables webpack to handle non JavaScript files (webpack itself only understands JavaScript), which is equivalent to a translator
1.2.4Plugins
Plugins can be used to perform a wider range of tasks. Plug ins range from packaging optimization and compression to redefining variables in the environment
1.2.5Mode
Mode indicates that the webpack uses the configuration of the corresponding mode.
option | describe | characteristic |
---|---|---|
development | Process. In DefinePlugin env. NODE_ The value of Env is set to development. Enable NamedChunksPlugin and namedmodules plugin. | An environment in which code can be debugged and run locally |
production | Process. In DefinePlugin env. NODE_ The value of Env is set to production. Enable FlagDependencyUsagePlugin, FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin, SideEffectsFlagPlugin and TerserPlugin. | Environment that allows code optimization to run online |
2: The first experience of webpack
2.1 initialization configuration
- Initialize package JSON input instruction:
npm init
- Download and install the webpack input command:
npm install webpack webpack-cli -g npm install webpack webpack-cli -D
2.2 compiling and packaging applications
1. Create a file
2. Operation instruction
Development environment Directive:
webpack ./src/index.js -o ./build/built.js --mode=development
Function:
webpack will start with/ src/index.js starts packaging for the entry file and outputs it to/ build/built.js overall packaging environment is the development environment; webpack can compile and package js and json files, and convert the modular syntax of es6 into the syntax recognized by the browser.
Production environment Directive:
webpack ./src/index.js -o ./build/built.js --mode=production
Function:
webpack will start with/ src/index.js starts packaging for the entry file and outputs it to/ build/built.js overall packaging environment, which is the production environment; In the development configuration function, there is one more function to compress the code.
3. Conclusion
webpack itself can handle js/json resources, not css/img and other resources
The production environment and development environment compile ES6 modularization into modularization that can be recognized by the browser, but they can not process the basic syntax of ES6 into ES5 (with the help of loader)
The production environment has one more compressed js code than the development environment
3: Basic configuration of webpack development environment
3.1 creating a profile
1. Create the file webpack config. js
2. Configuration contents are as follows:
const { resolve } = require('path');/ /node Built in core module,Used to deal with path problems module.exports = { entry: './src/js/index.js', / / Entry file output: { / / Output configuration filename: './built.js', / / Output file name path: resolve(__dirname, 'build/js') / / Output file path configuration }, mode: 'development' / / Development environment };
3. Operation instruction:
webpack
4. Conclusion: the function is the same as that in the previous section
3.2 packaging style resources
1. Create a file
2. Download and install the loader package
npm i css-loader style-loader less-loader less -D
3. Modify the configuration file
// resolve the method used to splice absolute paths const { resolve } = require('path'); module.exports = { // webpack configuration / / entry starting point entry: './src/index.js', // output output: { // Output file name: 'build js', // Output path // __ The variable of dirname nodejs represents the absolute directory path of the current file path: resolve(__dirname, 'build') }, // Configuration of loader module: { rules: [ // Detailed loader configuration // Different files must be configured with different loader processing { // Which files match test: /\.css$/, // Which loader s are used for processing use: [ // The order of loader execution in the use array: from right to left, from bottom to top // Create a style tag, insert the style resource in js, and add it to the head to take effect 'style-loader', // Change the css file into a commonjs module and load it into js, where the content is a style string 'css-loader' ] }, { test: /\.less$/, use: ['style-loader', 'css-loader', // Compile less files into css files // You need to download less loader and less 'less-loader' ] } ] }, // plugins configuration plugins: [ // Detailed plugins configuration ], // pattern mode: 'development', // Development mode // mode: 'production' }
- Run command: webpack
webpack
3.3 packaging HTML resources
1. Create a file
2. Download and install the plugin package
npm install --save -dev html-webpack-plugin
3. Modify the configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, module: { rules: [ // Configuration of loader ] }, plugins: [ // plugins configuration // html-webpack-plugin // Function: an empty HTML will be created by default, and all resources (JS/CSS) for packaged output will be automatically introduced // Requirements: a structured HTML file is required new HtmlWebpackPlugin({ // Copy '/ src/index.html 'file and automatically import all resources (JS/CSS) for packaged output template: './src/index.html' }) ], mode: 'development' };
4. Operation instruction:
webpack
3.4 packaging picture resources
1. Create a file
2. Download and install the loader package
npm install --save-dev html-withimg-loader url-loader file-loader
3. Modify the configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, module: { rules: [ { test: /\.less$/, // To use multiple loader s, use use: ['style-loader', 'css-loader', 'less-loader'] }, { // Problem: img images in html cannot be processed by default // Processing picture resources test: /\.(jpg|png|gif)$/, // Use a loader // Download URL loader file loader loader: 'url-loader', options: { // If the image size is less than 8kb, it will be processed by base64 // Advantages: reduce the number of requests (reduce server pressure) // Disadvantages: larger picture size (slower file request) limit: 8 * 1024, // Problem: by default, the URL loader uses es6 modular parsing, while the image introduced by HTML withimg loader is commonjs // There will be a problem when parsing: [object Module] // Solution: turn off es6 modularization of URL loader and use commonjs for parsing esModule: false, // Rename the picture / / [hash:10] take the first 10 bits of the hash of the picture // [ext] get the original file extension name: '[hash:10].[ext]' } }, { // Parsing image resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', } ] }, plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })], mode: 'development' };
4. Operation instruction:
webpack
3.5 packaging other resources
1. Create a file
2. Modify the configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, // Package other resources (resources other than html/js/css resources) { // Exclude css/js/html resources exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]' } } ] }, plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })], mode: 'development' };
3. Operation instruction:
webpack
Standby: summary of the above resource types 1-5:
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader', ] }, { test: /\.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false } }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]' } } ] }, plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })], mode: 'development' }
3.6 devserver
Development server devServer: it is used for automation. It does not need to re-enter the webpack and package it every time after modification (automatically compile, automatically open the browser, and automatically refresh the browser)
Features: it can only compile and package in memory without any output (the build package packaged and output will not be seen outside as before, but in memory and will be automatically deleted after closing)
The instructions to start devServer are: NPX webpack dev server or npx webpack serve
1. Create a file
2. Modify the configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, module: { rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }, // Package other resources (resources other than html/js/css resources) { // Exclude css/js/html / image resources exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' })], mode: 'development', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true } };
3. Operation instruction:
npx webpack-dev-server or npx webpack serve
3.7 development environment configuration
1. Create a file
2. Modify the configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build') }, module: { rules: [ // Configuration of loader { // Handling less resources test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },{ // Handling css resources test: /\.css$/, use: ['style-loader', 'css-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' } }, { // Processing img resources in html test: /\.html$/, loader: 'html-loader' }, { // Processing other resources exclude: /\.(html|js|css|less|jpg|png|gif)/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'media' } } ] }, plugins: [ // plugins configuration new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development', devServer: { contentBase: resolve(__dirname, 'build'), compress: true, port: 3000, open: true } };
9. Operation instruction:
npx webpack-dev-server
4. Basic configuration of webpack production environment
4.1 extract css into a separate file
4.1. 1. Download the installation package
4.1. 2. Download plug-ins
npm install--save-dev mini-css-extract-plugin
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build'), publicPath: '/build/' }, module: { rules: [ { test: /\.css$/, use: [ // Create a style label and put the style into // 'style-loader', // This loader replaces style loader. Function: extract css in js into a separate file MiniCssExtractPlugin.loader, 'css-loader', ] }, { test: /\.less$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'less-loader' ] }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'images' } }, { // Processing img resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', // Parsing image resources in html }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'assets' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' })], mode: 'development', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true } }
4.1. 3. Operation instruction:
npx webpack serve
Note: we include pictures in the packaged resources, so we need to configure the public path in output. publicPath: '/ build /'
4.2css compatibility processing
4.2. 1. Download loader
npm install--save -dev postcss-loader postcss-preset-env
4.2. 2. Modify the configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') // Set nodejs environment variable process.env.NODE_ENV = 'development'; module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build'), publicPath: '/build/' }, module: { rules: [ { test: /\.css$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: "postcss", plugins: [require("postcss-preset-env")()] } } } ] }, { test: /\.less$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'less-loader' ] }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'images' } }, { // Processing img resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', // Parsing image resources in html }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'assets' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), ], mode: 'development', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true } }
4.2. 3. Modify package json
"browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.1%", "not dead", "not op_mini all" ] }
4.2. 4. Operation instruction:
webpack
4.2. 5. Implementation effect:
Development environment:
Production environment:
4.3 compressing css
1. Download the installation package
npm install--save -dev optimize-css-assets-webpack-plugin
2. Modify the configuration file
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 nodejs environment variable. The default is production environment process.env.NODE_ENV = 'development'; module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build'), publicPath: '/build/' }, module: { rules: [ { test: /\.css$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: "postcss", plugins: [require("postcss-preset-env")()] } } } ] }, { test: /\.less$/, use: [ //'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: "postcss", plugins: [require("postcss-preset-env")()] } } }, 'less-loader' ] }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'images' } }, { // Processing img resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', // Parsing image resources in html }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'assets' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), // Compress css new OptimizeCssAssetsWebpackPlugin() ], mode: 'development', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true } }
3. Operation instruction:
webpack
4. Effect:
4.4 JS syntax check
1. Download the installation package
npm install--save -dev eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import
2. Modify the configuration file
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 nodejs environment variable. The default is production environment // process.env.NODE_ENV = 'development'; module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build'), publicPath: '/build/', }, module: { rules: [ { test: /\.css$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [require('postcss-preset-env')()] } }, }, ], }, { test: /\.less$/, use: [ //'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: "postcss", plugins: [require("postcss-preset-env")()] } } }, 'less-loader', ], }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'images', }, }, { // Processing img resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', // Parsing image resources in html }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'assets', }, }, /* Syntax check: eslint loader Note: only check the source code written by yourself, and third-party libraries do not need to be checked Set check rule: package Set in eslintConfig in JSON~ "eslintConfig": { "extends": "airbnb-base" } airbnb Required syntax dependency -- > eslint config airbnb base eslint plugin import eslint */ { test: /\.js$/, // Path that does not require syntax checking exclude: /node_modules/, // Specify the directory to check include: [path.resolve(__dirname, 'src')], loader: 'eslint-loader', // Pre compile check enforce: 'pre' options: { // Automatic repair fix: true, },, }, ], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), // Compress css new OptimizeCssAssetsWebpackPlugin(), ], mode: 'development', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true, }, };
3. Configure package json
"eslintConfig": { "extends": "airbnb-base", "env": { "browser": true } }
4. Operation instruction:
webpack
remarks:
-
1. When debugging, we cannot avoid some eslint warnings. We can use / / eslint disable next line to make the next line not subject to eslint check, such as:
-
2. Detailed configuration of eslint: https://www.cnblogs.com/jackson1/p/12682664.html
4.5 js compatibility processing
1. Download the installation package
npm install --save -dev babel-loader @babel/core @babel/preset-env @babel/polyfill core-js
2. Modify the configuration file
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 nodejs environment variable. The default is production environment // process.env.NODE_ENV = 'development'; module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build'), publicPath: '/build/', }, module: { rules: [ { test: /\.css$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [require('postcss-preset-env')()] } }, }, ], }, { test: /\.less$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: "postcss", plugins: [require("postcss-preset-env")()] } } }, 'less-loader', ], }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'images', }, }, { // Processing img resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', // Parsing image resources in html }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'assets', }, }, /* Syntax check: eslint loader Note: only check the source code written by yourself, and third-party libraries do not need to be checked Set check rule: package Set in eslintConfig in JSON~ "eslintConfig": { "extends": "airbnb-base" } airbnb Required syntax dependency -- > eslint config airbnb base eslint plugin import eslint */ { test: /\.js$/, // Path that does not require syntax checking exclude: /node_modules/, // Specify the directory to check include: [resolve(__dirname, 'src')], loader: 'eslint-loader', // Check before compiling enforce: 'pre', options: { // Automatic repair fix: true, }, }, /* js Compatibility processing: you need to download Babel loader @ Babel / core 1. Basic js compatibility processing -- > @ Babel / preset env Problem: only basic syntax can be converted, such as promise advanced syntax 2. All js compatibility processing -- > @ Babel / Polyfill Problem: as long as some compatibility problems are solved, but all compatibility codes are introduced, the volume is too large 3. If compatibility processing is required, do it: load -- > core JS on demand Final scheme: @ Babel / preset env + core JS */ { test: /\.js$/, exclude: /node_module/, loader: 'babel-loader', options: { presets: [ [ // Basic preset '@babel/preset-env', { // Load on demand useBuiltIns: 'usage', // Specify the core JS version corejs: { version: 3 }, // Specifies which version of browser is compatible with targets: { chrome: '60', firefox: '50', ie: '9', safari: '10', edge: '17', }, }, ], ], }, }, ], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), // Compress css new OptimizeCssAssetsWebpackPlugin(), ], mode: 'development', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true, }, };
3. Implementation
webpack
4. Implementation effect
4.6 js compression and HTML compression
4.6.1 js compression
js code will be automatically compressed in the production environment; In webopack config. js file directly modify the mode
mode: 'production'
4.6.2 HTML compression
When using HtmlWebpackPlugin, we can add the minify configuration item
new HtmlWebpackPlugin({ template: './src/index.html', minify: { // Remove spaces: collapseWhitespace: true, // Remove comment removeComments: true } }),
4.7 summary: webpack production environment configuration summary:
1. Document directory
2.webpack configuration file
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); // Separate files for css production const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // Compress css const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); // Set nodejs environment variable. The default is production environment process.env.NODE_ENV = 'development'; // loader configuration of reusable css const commCssLoader = [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { ident: 'postcss', plugins: [require('postcss-preset-env')()] } }, }] module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build'), publicPath: '/build/', }, module: { rules: [ { test: /\.css$/, use: [ ...commCssLoader ], }, { test: /\.less$/, use: [ ...commCssLoader, 'less-loader', ], }, { test: /\.(gif|img|png|jpg)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'images', }, }, { // Processing img resources in html test: /\.(html|htm)$/i, use: 'html-withimg-loader', // Parsing image resources in html }, { exclude: /\.(css|js|html|less|gif|img|png|jpg)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'assets', }, }, /* Syntax check: eslint loader Note: only check the source code written by yourself, and third-party libraries do not need to be checked Set check rule: package Set in eslintConfig in JSON~ "eslintConfig": { "extends": "airbnb-base" } airbnb Required syntax dependency -- > eslint config airbnb base eslint plugin import eslint */ { test: /\.js$/, // Path that does not require syntax checking exclude: /node_modules/, // Specify the directory to check include: [resolve(__dirname, 'src')], loader: 'eslint-loader', // Priority execution (check first and then perform compatibility processing) enforce: 'pre', options: { // Automatic repair fix: true, }, }, /* js Compatibility processing: you need to download Babel loader @ Babel / core 1. Basic js compatibility processing -- > @ Babel / preset env Problem: only basic syntax can be converted, such as promise advanced syntax 2. All js compatibility processing -- > @ Babel / Polyfill Problem: as long as some compatibility problems are solved, but all compatibility codes are introduced, the volume is too large 3. If compatibility processing is required, do it: load -- > core JS on demand Final scheme: @ Babel / preset env + core JS */ { test: /\.js$/, exclude: /node_module/, loader: 'babel-loader', options: { presets: [ [ // Basic preset '@babel/preset-env', { // Load on demand useBuiltIns: 'usage', // Specify the core JS version corejs: { version: 3 }, // Specifies which version of browser is compatible with targets: { chrome: '60', firefox: '50', ie: '9', safari: '10', edge: '17', }, }, ], ], }, }, ], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { // Remove spaces: collapseWhitespace: true, // Remove comment removeComments: true } }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), // Compress css new OptimizeCssAssetsWebpackPlugin(), ], // js files are compressed in the production environment mode: 'production', devServer: { // Project post build path contentBase: resolve(__dirname, 'build'), // Start gzip compression compress: true, // Port number port: 3000, // Open browser automatically open: true, }, };
3.package.json
"browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.1%", "not dead", "not op_mini all" ] }, "eslintConfig": { "extends": "airbnb-base", "env": { "browser": true } }
5. Optimized configuration of webpack
The optimization is divided into the following aspects:
- webpack Performance Optimization: development environment and production environment performance optimization;
- Development environment performance optimization: optimize the speed of packaging and construction, and optimize code debugging
- Production environment performance optimization: optimize the speed of packaging and construction, and optimize the code running performance
5.1 development environment performance optimization
5.1.1 HMR :
Enable hot module replacement, also known as HMR.
Function: when a module changes, it will only repackage this module (instead of packaging all modules), greatly improving the construction speed
Code: just set hot to true in devServer, and the HMR function will be automatically enabled (only available in development mode)
devServer: { contentBase: resolve(__dirname, 'build'), compress: true, port: 3000, open: true, // Turn on HMR function // When the webpack configuration is modified, the webpack service must be restarted in order for the new configuration to take effect hot: true }
Hot module replacement for each file:
Style file: the HMR function can be used because the style loader used in the development environment implements the hot module replacement function by default
js file: the HMR function cannot be used by default (when a js module is modified, all js modules will be refreshed)
– > to implement HMR, you need to modify js code (add code supporting HMR function)
In index JS file:
// binding if (module.hot) { // Once module If hot is true, HMR function is enabled. -- > Validate HMR function code module.hot.accept('./print.js', function() { // Method listens for print Once the JS file changes, only this module will be repackaged and built, and other modules will not. // The following callback function will be executed print(); }); }
Note: the HMR function can only handle other files that are not imported js files.
html file: the HMR function cannot be used by default (html does not need to be used as the HMR function, because there is only one html file and no further optimization is required)
Using HMR can cause problems: html files cannot be hot updated (they will not be automatically packaged and built)
Solution: modify the entry entry and import the html file (in this way, the html will be refreshed as a whole)
entry: ['./src/js/index.js', './src/index.html']
5.1.2 source-map
source-map:
A technique that provides mapping from source code to post build code (if post build code fails, source code errors can be tracked through mapping)
Parameters:
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
code:
devtool: 'eval-source-map'
Optional scheme: [location where source map is generated | error code information given]
1 . Source map: external error code, accurate information and error location of source code
2. Inline source map: inline. Only one inline source map is generated. The exact information of the error code and the error location of the source code
3. Hidden source map: external, error code, error reason, but there is no error location (to hide the source code). Source code errors cannot be tracked, but only the error location of the built code can be prompted
4. Eval source map: inline. Each file generates a corresponding source map, which is in eval. The exact information of the error code and the error bit of the source code
5. Nosources source map: external, error code, accurate information, but no source code information (to hide the source code)
6. Soap source map: external error code, accurate information and error location of source code. The error can only be accurate to the whole line, and the column is ignored
7. Soap module source map: external error code, accurate information and error location of source code. Module will be added to loader's source map
Difference between inline and external:
- File generated externally, not inline
- Inline builds are faster
Options for development / production environment:
Development environment:
It needs to be considered that the speed is fast and the debugging is more friendly: Fast speed( eval > inline > cheap >... ) eval-cheap-souce-map eval-source-map *More friendly debugging: souce-map cheap-module-souce-map cheap-souce-map
Finally, the best two schemes are obtained:
1. Eval source map (high integrity, fast inline speed, scaffold is used by default)/
2. Eval soap module soap map (error prompt: ignore column but contain other information, fast inline)
Production environment:
We need to consider whether the source code should be hidden and whether debugging should be more friendly Inlining increases the size of the code, so you don't need to inline in the production environment Hide source code nosources-source-map hide all hidden-source-map If only the source code is hidden, the post build code error message will be prompted
Finally, the best two schemes are obtained:
1. Source map (most complete)
2. Soap module soap map (error prompt: ignore a whole row of columns)
5.2 production environment performance optimization
5.2. 1. Optimize the packaging construction speed
5.2.1.1 oneOf
oneOf: after matching to the loader, it will not be matched backward to optimize the packaging and construction speed of the production environment
code:
module: { rules: [ { // js syntax check test: /\.js$/, exclude: /node_modules/, // Priority implementation enforce: 'pre', loader: 'eslint-loader', options: { fix: true } }, { // oneOf optimizes the packaging and construction speed of production environment // Only one of the following loader s will be matched (there will be no further matching after matching) // Note: two configurations cannot handle files of the same type (so extract the eslint loader and put it outside) oneOf: [ { test: /\.css$/, use: [...commonCssLoader] }, { test: /\.less$/, use: [...commonCssLoader, 'less-loader'] }, { // js compatibility processing test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: {version: 3}, targets: { chrome: '60', firefox: '50' } } ] ] } }, { test: /\.(jpg|png|gif)/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', outputPath: 'imgs', esModule: false } }, { test: /\.html$/, loader: 'html-loader' }, { exclude: /\.(js|css|less|html|jpg|png|gif)/, loader: 'file-loader', options: { outputPath: 'media' } } ] } ] },
5.2.1.2 babel cache
babel caching: similar to HMR, it caches the resources processed by babel (update where js changes, and use the previously cached resources for other js), so as to make the second packaging and construction faster
code:
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '50' } } ] ], // Enable babel cache // On the second build, the previous cache is read cacheDirectory: true } },
5.2. 1.3 file resource cache
If the file name remains unchanged, the previously cached resources will not be re requested, but will be used again
1.hash: a unique hash value will be generated each time wepack is packaged.
output: { // Adding a hash value to the file name prevents caching filename: 'js/built.[hash:10].js', path: resolve(__dirname, 'build'), publicPath: '/build/', },
new MiniCssExtractPlugin({ filename: 'css/built.[hash:10].css' }),
Problem: when repackaging, the hsah value of all files will change, which will invalidate all caches. (only one file may have been changed)
2. Chunk hash: hash value generated according to chunk. The hash value from the same chunk is the same
Problem: js and css come from the same chunk, and the hash value is the same (because css loader will load css files into js, they belong to the same chunk)
output: { // Adding a hash value to the file name prevents caching filename: 'js/built.[chunkhash:10].js', path: resolve(__dirname, 'build'), publicPath: '/build/', },
new MiniCssExtractPlugin({ filename: 'css/built.[chunkhash:10].css' }),
3.contenthash: generates a hash value according to the contents of the file. The hash value of different files must be different (the hash in the file name will change only when the file content is modified)
Modify the content of the css file, the hash value of the packaged css file name will change, while the hash value of the js file will not change. In this way, the css and js caches will judge whether to re request resources -- > so that the code can run online and the cache can be used better
output: { // Adding a hash value to the file name prevents caching filename: 'js/built.[contenthash:10].js', path: resolve(__dirname, 'build'), publicPath: '/build/', },
new MiniCssExtractPlugin({ filename: 'css/built.[contenthash:10].css' }),
Packaged file name:
Modify index JS code is repackaged without modifying css code
5.2.1.4 tree shaking
Premise:
- ES6 modularization must be used
- When the production environment is enabled, the tree shake will be used automatically (in this way, the useless code will be removed automatically)
Function: remove useless code and reduce code volume
In package JSON configuration:
"sideEffects": false
Indicates that all codes have no side effects (tree shaking can be performed)
This may cause problems: css / @babel/polyfill files may be killed (side effects); these files are only imported and not used, so they will not be packaged because of tree shaking
Therefore, you can configure:
"sideEffects": ["*.css", "*.less"]
The css/less file tree shaking is not processed
5.2.1.5 code split
Code segmentation. A large bundle that will be packaged for output JS file is split into multiple small files, so multiple files can be loaded in parallel, which is faster than loading one file.
1. Multi entry splitting (this method can be used for multi page applications)
entry: { // Multiple entries: with one entry, the final output will have a bundle index: './src/js/index.js', test: './src/js/test.js' }, output: { // [name]: get file name filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build') },
Output file after packaging
2.optimization:
optimization: { splitChunks: { chunks: 'all' } },
Add node_ The code in modules is packaged separately (more than 30kb in size)
Automatically analyze whether there are public files in the multi entry chunk. If there is, it will be packaged into a single chunk (for example, jquery is introduced into both modules, and it will be packaged into a separate file) (the size is more than 30kb),
example
If we were in index Package after introducing jquery third-party tools into JS:
Packaging without optimization configuration:
Package with optimization configuration:
86kb is the jquery code we introduced; Even if multiple entry files refer to jquery,jquery will only be packaged once
3.import dynamic import syntax: a file is packaged into a chunk through js code
/* import Dynamic import syntax: a file can be packaged separately (test file will not be packaged in the same file as index, but separately) webpackChunkName:Specify the name of the file after test is packaged separately */ import(/* webpackChunkName: 'test' */'./test') .then(({ mul, count }) => { // File loaded successfully~ // eslint-disable-next-line console.log(mul(2, 5)); }) .catch(() => { // eslint-disable-next-line console.log('File loading failed~'); });
4. Summary: the common scheme is single entry file + optimization
5.2.1.6 lazy loading
1. Lazy loading: the file is loaded only when it needs to be used (code segmentation is required). However, if the resources are large, the loading time will be long and there will be a delay.
2. Normal loading: it can be considered that parallel loading (loading multiple files at the same time) has no sequence, and loading unnecessary resources first will waste time.
3. Preload prefetch (poor compatibility): it will be loaded in advance before use. After other resources are loaded and the browser is idle, load this resource secretly. In this way, it has been loaded when in use, and the speed is very fast. Therefore, it is better to add preload on the basis of lazy loading.
code:
index.js file
document.getElementById('btn').onclick = function() { // Put the contents of import into the asynchronous callback function, click the button, test JS will be loaded (it will not be loaded repeatedly) // webpackPrefetch: true indicates that preload is enabled import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => { console.log(mul(4, 5)); }); import('./test').then(({ mul }) => { console.log(mul(2, 5)) }) };
Analysis: click the btn button and go back to load test JS file and then call the mul() function. When the second click, it will directly get from the cache and call the mul() function
be careful:
The webpack will report an error 'import' and 'export' may only appear at the top level
Solution:
1. Install Babel eslint
npm install --save-dev babel-eslint
2. New eslintrc file
{ "parser": "babel-eslint", "parserOptions": { "sourceType": "module", "allowImportExportEverywhere": true } }
5.2.1.7 pwa (offline accessible technology)
pwa: offline accessible technology (progressive network development application), using serviceworker and workbox technology. The advantage is that it can be accessed offline, but the disadvantage is poor compatibility.
webpack.config.js configuration:
1. Installation: workbox webpack plugin:
npm install workbox-webpack-plugin --save-dev
2. Use
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); // Introducing plug-ins // Add to plugins: new WorkboxWebpackPlugin.GenerateSW({ /* 1. Help service worker start quickly 2. Delete old serviceworker Generate a serviceworker configuration file */ clientsClaim: true, skipWaiting: true })
3. Modify package eslintConfig configuration in JSON (eslint does not know window and navigator global variables)
"eslintConfig": { ...... "env": { "browser": true } }
4.1. serviceWorker code must be running on the server
npm i serve -g
4.2 start the server and expose all the resources under the build directory of the package output as static resources
serve -s build
5. Register serviceworker: index JS also needs to write a piece of code to activate its use
if ('serviceWorker' in navigator) { // Handling compatibility issues window.addEventListener('load', () => { navigator.serviceWorker .register('/service-worker.js') // Register serviceWorker .then(() => { console.log('sw Registration succeeded~'); }) .catch(() => { console.log('sw Registration failed~'); }); }); }
5.2. 1.8 multi process packaging
Multi process Packaging: a task takes a long time and gets stuck. Multiple processes can do multiple things at the same time, which is more efficient.
Advantages: it improves the packing speed,
Disadvantages: the startup and communication of each process will have overhead (Babel loader takes the longest time, so thread loader is used to optimize it)
When there are a lot of js code, the effect of using multi process packaging will be obvious
{ test: /\.js$/, exclude: /node_modules/, use: [ /* thread-loader Multi process packaging will be enabled for the loader behind it (Babel loader in this case). The process startup is about 600ms, and the process communication also has overhead. (the startup cost is expensive, so don't abuse it) Only when the work takes a long time, multi process packaging is required */ { loader: 'thread-loader', options: { workers: 2 // 2 processes } }, { loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '50' } } ] ], // Enable babel cache // On the second build, the previous cache is read cacheDirectory: true } } ] },
Using multithreaded packaging in a simple project:
Do not use multithreaded packaging:
5.2.1.9 externals
externals: Let some libraries not be packaged through cdn introduce webpack.config.js Configuration in: externals: { // Refuse jQuery to be packaged (it will be faster if it is introduced through cdn) // Ignored library name -- npm package name jquery: 'jQuery' }
Need to be in index Html is introduced through cdn:
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
5.2.1.10 dll
dll: package some libraries separately, and then directly import them into build. Node can be split in code split_ After modules, dll is used for finer segmentation to optimize the performance of code operation.
1. Add webpack dll. JS file and configure: (package jquery separately)
/* node_modules The libraries will be packaged together, but in many cases, the output js file is too large Using dll technology, some libraries (third-party libraries: jquery, react, vue...) are packaged separately When running webpack, the default is to find webpack config. JS configuration file Requirement: you need to run webpack dll. JS file --> webpack --config webpack.dll.js(Running this command means packaging with this configuration file) */ const { resolve } = require('path'); const webpack = require('webpack'); module.exports = { entry: { // [name] -- > jQuery generated by final packaging // ['jquery] -- > the library to be packaged is jQuery jquery: ['jquery'] }, output: { // Export designation filename: '[name].js', // name is jquery path: resolve(__dirname, 'dll'), // Package to dll directory library: '[name]_[hash]', // What is the name of the content exposed in the packaged library }, plugins: [ // Package to generate a manifest JSON -- > provides the mapping relationship of jquery (tell webpack: jquery does not need to package and expose the name of the content) new webpack.DllPlugin({ name: '[name]_[hash]', // The exposed content name of the mapping library path: resolve(__dirname, 'dll/manifest.json') // Output file path }) ], mode: 'production' };
2. Running this command means packaging with this configuration file (that is, packaging the dependencies in node_module separately)
webpack --config webpack.dll.js
3.webpack.config.js configuration: (tell webpack that jquery does not need to be packaged, and output the previously packaged jquery to the build directory together with other packaged resources)
// Introducing plug-ins const webpack = require('webpack'); const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin'); // Configuration in plugins: plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), // Tell webpack which libraries do not participate in packaging, and the name of the libraries used will change new webpack.DllReferencePlugin({ manifest: resolve(__dirname, 'dll/manifest.json') }), // Package and output a file to the build directory, and automatically import the resource into html new AddAssetHtmlWebpackPlugin({ filepath: resolve(__dirname, 'dll/jquery.js') }) ],
4. Packing
webpack
5. Summary:
1. Configure webpack dll. JS file tells webpack that those dependent packages need to be packaged separately
2. Execute: webpack -- config webpack dll. JS, packaged separately, and the separately packaged resource path is recorded in manifest JSON resource mapping file
3. Execute webpack to start project packaging. During the packaging process, manifest JSON gets the separately packaged resource path and introduces it into index HTML file
6.webpack configuration details
entry: Entrance starting point string --> './src/index.js',Single entry Package to form a chunk. Output a bundle File. here chunk The default name is main array --> ['./src/index.js', './src/add.js'],Multiple entry All entry files will eventually form only one chunk,There is only one output bundle File. (Generally only used in HMR Let in function html Hot update effective) object,Multiple entry Several entry files form several chunk,Output several bundle File, at this time chunk Your name is key value --> Special usage: entry: { // In the end, only one chunk will be formed, and only one bundle file will be output. index: ['./src/index.js', './src/count.js'], // Form a chunk and output a bundle file. add: './src/add.js' }
6.2 output
output: { // File name (specify name + directory) filename: 'js/[name].js', // Output file directory (public directory for future output of all resources) path: resolve(__dirname, 'build'), // All resources introduce a common path prefix -- > 'IMGs / a.jpg' -- > '/ IMGs / a.jpg' publicPath: '/', chunkFilename: 'js/[name]_chunk.js', // Specifies the name of the non entry chunk library: '[name]', // Variable names exposed after packaging the entire library libraryTarget: 'window' // To which browser: window is the variable name added // libraryTarget: 'global' // node: global // libraryTarget: 'commonjs' // conmmonjs module exports },
6.3 module
module: { rules: [ // Configuration of loader { test: /\.css$/, // Multiple loader s use use: ['style-loader', 'css-loader'] }, { test: /\.js$/, // Exclude node_ js file under modules exclude: /node_modules/, // Only check js files under src include: resolve(__dirname, 'src'), enforce: 'pre', // Priority implementation // enforce: 'post', / / postpone execution // Single loader loader: 'eslint-loader', options: {} // Specify configuration options }, { // Only one of the following configurations will take effect oneOf: [] } ] },
6.4 resolve
// Rules for parsing modules resolve: { // Configure the path alias of the resolution module: advantages: when the directory level is very complex, it shortens the path; Disadvantages: the path does not prompt alias: { $css: resolve(__dirname, 'src/css') }, // Omit the suffix of the configuration file path (you can not write the file suffix when importing) extensions: ['.js', '.json', '.jsx', '.css'], // Tell the webpack parsing module which directory to look for modules: [resolve(__dirname, '../../node_modules'), 'node_modules'] }
After this configuration, the import file can be abbreviated as follows: import '$css/index';
6.5 dev server
devServer: { // The directory where the code is running contentBase: resolve(__dirname, 'build'), // Monitor all files in the contentBase directory, and reload if the file changes watchContentBase: true, watchOptions: { // Ignore file ignored: /node_modules/ }, // Start gzip compression compress: true, // Port number port: 5000, // domain name host: 'localhost', // Open browser automatically open: true, // Turn on HMR function hot: true, // Do not display startup server log information clientLogLevel: 'none', // Do not display anything except some basic information quiet: true, // If something goes wrong, don't give a full screen prompt overlay: false, // Server agent, -- > solve the cross domain problem of development environment proxy: { // Once the devServer(5000) server receives the request for / api/xxx, it forwards the request to another server 3000 '/api': { target: 'http://localhost:3000', // When sending a request, the request path is rewritten: change / api / xxx -- > / xxx (remove / api) pathRewrite: { '^/api': '' } } } }
Among them, cross domain problem: different protocols, port numbers and domain names in the same source strategy will produce cross domain problems.
There is cross domain between normal browsers and servers, but there is no cross domain between servers. The code runs through the proxy server, so there is no cross domain between the browser and the proxy server. The browser sends the request to the proxy server, and the proxy server forwards it to another server for you. There is no cross domain between the servers, so the request is successful. The proxy server then sends the received response to the browser. This solves the cross domain problem in the development environment.
6.6 optimization
Content hash caching can cause a problem: modifying a file causes the content hash of b file to change.
Because in index a.js is introduced into JS, and index.js is packaged JS records the hash value of a.js. When a.js changes, the repackaged hash changes, resulting in index The hash of a.js recorded in the content of JS file is also changed, so index. JS is repackaged The hash value of JS will also change, which will invalidate the cache. (the a.js file is changed, but the hash value of the index.js file is also changed)
Solution: runtimechunk -- > package the hashes of other modules recorded by the current module into a separate runtime file. In this way, the hash change of a.js will only affect the runtime file, not the index JS file
output: { filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build'), chunkFilename: 'js/[name].[contenthash:10]_chunk.js' // Specify the names of other chunks that are not entry files_ chunk }, optimization: { splitChunks: { chunks: 'all', /* The following are the default configurations of splitChunks, which can be left blank miniSize: 30 * 1024, // The minimum chunk for segmentation is 30kb (only those larger than 30kb can be segmented) maxSize: 0, // There is no limit to the maximum minChunks: 1, // The chunk to be extracted is referenced at least once maxAsyncRequests: 5, // The maximum number of files loaded in parallel when loading on demand is 5 maxInitialRequests: 3, // Maximum number of parallel requests for entry js file automaticNameDelimiter: '~', // Name connector name: true, // You can use naming rules cacheGroups: { // Split chunk s vendors: { // node_modules The files in will be packaged in the chunk of the vendors group, -- > vendors ~ XXX js // The above public rules are met. The size exceeds 30kb and is referenced at least once test: /[\\/]node_modules[\\/]/, // priority priority: -10 }, default: { // The chunk to be extracted is referenced at least 2 times minChunks: 2, prority: -20, // If the current module to be packaged is the same as the previously extracted module, it will be reused instead of repackaged reuseExistingChunk: true } } */ }, // Index The hash value of a.js recorded by JS is separately packaged into the runtime file to prevent the modification of a file from changing the hash value of b file. Finally, index If the file name of application b in JS file does not change, there will be a problem runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` }, minimizer: [ // Configure the compression scheme of the production environment: js/css new TerserWebpackPlugin({ // Enable cache cache: true, // Turn on multi process packaging parallel: true, // Enable sourcemap (otherwise it will be compressed) sourceMap: true }) ] }