I. Development and Optimization
1. File monitoring
File monitoring is when the source code changes, automatically rebuild the new output file, will be updated to the disk, polling to determine whether the last edit time of the file has changed, a file changes, will not immediately tell the listener, cache first
Disadvantages: Manual refresh is required
Startup mode:
- Method 1
Start the Webpack command with the –watch parameter to start listening
// package.json
"scripts": {
"watch":"webpack --watch"
}
Copy the code
npm run watch
npx webpack --watch
Copy the code
- Methods type 2
Set watch:true in the configuration file
// webpack.config.js
module.exports = {
watch: true.// By default, false is disabled
// With watch, it only works if it is on
watchOptions: {
// A file or directory that does not listen to is empty by default and supports re
ignored: /node_modules/.// Wait 300ms for file changes, default 300ms,
aggregateTimeout: 300.// Check whether the file has changed by constantly asking the system whether the specified file has changed. The default value is once per second
poll: 1000 //ms
}
// Poll 1s and check once
}
Copy the code
2. Webpack-dev-server automatically opens the browser, saves the Settings, and automatically refreshes the browser
2.1 installation
Note: webpack-dev-server is incompatible with webpack-cli 4.x.x.
npm install webpack-dev-server -D
Copy the code
Start the
// package.json
"scripts": {
"server": "webpack-dev-server"
}
Copy the code
npm run server
Copy the code
2.2 configuration
// webpack.config.js
var path = require('path');
module.exports = {
/ /...
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true.port: 9000}};Copy the code
-
DevServer: Packaged modules are stored in memory to speed up packaging.
-
ContentBase: Tells the server where the content comes from. Configure this only if you need to provide static files.
-
Port: the port
-
Open: indicates whether to open the browser
-
Proxy: Solves cross-domain problems in development environments
// webpack.config.js
devserver: {
proxy: {
'/api': { / / request
target: 'http://localhost:9092'}}}Copy the code
// index.js
axios.get("/api/info").then(res= > {
console.log(res);
});
Copy the code
- mock server
Before and after are two hooks provided by the middleware, one before and one after the middleware starts
before(app, server) {
app.get('/api/mock'.(req, res) = > {
res.json({
hello: 'express'})})}Copy the code
3. Hot Module Replacement (HMR)
3.1 Hot Update Configuration
Hot update: the new code takes effect, the web page is not refreshed, and the status is not lost
/ / introduce webpack
const webpack = require('webpack');
module.exports = {
plugins: [
Use the webpack plugin
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
hot: true.// Even if HMR does not work, the browser does not automatically refresh, just enable hotOnly
hotOnly: true,}}Copy the code
Note: CSS hot updates do not support extracted CSS, mini-CSS-extract-plugin is not recommended for development environments, and contenthash and Chunkhash are not supported
3.2 Replacing JS hot Modules
You need to use module.hot.accept to observe module updates to update
//number.js
function number() {
var div = document.createElement("div");
div.setAttribute("id"."number");
div.innerHTML = 13000;
document.body.appendChild(div);
}
export default number;
Copy the code
import number from "./number";
number();
// Whether to enable hot update
if (module.hot) {
// Whether the module has changed
module.hot.accept("./number".function () {
// Remove the element
document.body.removeChild(document.getElementById("number"));
// Add the element again
number();
});
}
Copy the code
3.3 the React
React Hot Loader: Adjust the React component in real time.
3.4 the Vue
Vue Loader: This Loader supports HMR of Vue components and provides out-of-the-box experience
4. Narrow the scope of Loader processing
Optimized the Loader configuration to reduce the loader processing scope
4.1 include: Only that
module.exports = {
module: {
rules: [{
test: /\.css$/.// Only files in the SRC directory are processed
include: path.resolve(__dirname, './src'),}}}Copy the code
Exclude: exclude that
module.exports = {
module: {
rules: [{
test: /\.css$/.// Don't deal with that
exclude: path.resolve(__dirname, './node_modules')}}}]Copy the code
Choose include or exclude. Include is recommended
5. Optimize the Resolve configuration
5.1 resolve. Modules
Resolve. modules configures the directory in which Webpack finds third-party modules. Default is [‘node_modules’]
To find third-party modules, the default is node_modules in the current project directory. If you don’t find any, go to the next level up. /node_modules find, no more will go to.. /.. /node_modules, and so on, is similar to node.js’s module finding mechanism.
// webpack.config.js
module.exports={
resolve: {
// Specify a path to find only here
modules: [
path.resolve(__dirname, "./node_modules")]}}Copy the code
5.2 resolve. Alias
Resolve. Alias configures the alias to map the original import path to a new one
By default, Webpack recursively parses and processes dependent files from the entry file./node_modules/bin/react/index. We can specify the file directly to avoid this time consuming area.
// webpack.config.js
module.exports={
resolve: {
alias: {
"@": path.join(__dirname, "./pages"),
// Specify the react file path to save lookup time
react: path.resolve(__dirname, "./node_modules/react/umd/react.production.min.js"),
// Specify the react-dom file path to save lookup time
"react-dom": path.resolve(__dirname,"./node_modules/react-dom/umd/react-dom.production.min.js")}}Copy the code
5.3 resolve. Extensions
Resolve. Extensions import statements without file suffixes and WebPack will try to find out if the file exists.
- Try to keep the list of suffixes small
- Import statements should be suffixed as much as possible.
// webpack.config.js
module.exports={
resolve: {
// Default configuration
extensions: ['.js'.'.json'.'.jsx'.'.ts']}}Copy the code
6. Use tools to quantify
6.1 Speed-measure-webpack-plugin: measures the time spent by each plug-in and loader
Installation:
npm i speed-measure-webpack-plugin -D
Copy the code
//webpack.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const config = {
/ /... Webpack configuration
}
module.exports = smp.wrap(config)
Copy the code
6.2 Webpack-bundle-Analyzer: Analyzes module dependencies after WebPack is packaged
Installation:
npm install webpack-bundle-analyzer -D
Copy the code
When you start a WebPack build, a window opens by default
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
//....
plugins: [
/ /...
new BundleAnalyzerPlugin(),
]
}
Copy the code
7. DllPlugin packages third-party libraries to optimize build performance
Projects introduced many third party libraries, the libraries in a long period of time, the basic will not update, when packaged separate packaging to improve packing speed, and dynamic link library plug-in DllPlugin, its principle is to make web page depend on the basis of abstract module packaging to the DLL file, when you need to import the exists in a DLL module, The module is no longer packaged, but retrieved from a DLL
Dll dynamic link library is actually do cache
Webpack already has built-in support for dynamically linked libraries
- DllPlugin: Used to package individual dynamic link library files
- DllReferencePlugin: Used to introduce the DllPlugin plug-in packaged dynamic link library file into the main configuration file
Create a new webpack.dll.config.js file and package the base module
We use the react and react-dom libraries in index.js, and we’ll package them first.
7.1 Packaging a Dynamic Link Library
// webpack.dll.config.js
const path = require("path");
const { DllPlugin } = require("webpack");
module.exports = {
mode: "development".entry: {
react: ["react"."react-dom"] / /! node_modules?
},
output: {
path: path.resolve(__dirname, "./dll"),
filename: "[name].dll.js".library: "react"
},
plugins: [
new DllPlugin({
// Manifest.json file output location
path: path.join(__dirname, "./dll"."[name]-manifest.json"),
// Define the function name exposed by the packaged public vendor file
name: "react"}})];Copy the code
run
npx webpack --config webpack.dll.config.js
Copy the code
It will create a DLL folder with the dL.js file in it, so we’ll have our React stuff packed separately
- DLL files contain code for a large number of modules, which are stored in an array. Using the array’s index number as the ID, you can access the module in window. XXX by exposing yourself globally through variables
- Manifest.json describes which modules are contained in the corresponding DLL. js, along with their ids and paths.
7.2 Introducing a Dynamic Connection Library
- Separate the base modules that web pages depend on and package them into a single dynamic link library, which can contain multiple modules.
- If the module to be imported exists in a dynamic link library, do not package it again and use the built dynamic link library directly.
module.exports = {
new DllReferencePlugin({
manifest: path.resolve(__dirname,"./dll/react-manifest.json")})}Copy the code
- All dynamic link libraries that the page depends on need to be loaded.
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="Width = device - width, initialscale = 1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>webpack</title>
<link href="css/main_e2bf39.css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
<! -- Introducing dynamic link library -->
<script type="text/javascript" src="react.dll.js"></script>
<script type="text/javascript" src="js/main_142e6c.js"></script>
</body>
</html>
Copy the code
Use the add-asset-html-webpack-plugin, which will inject our packed DLL. js file into our generated index.html. Make changes in the webpack.base.config.js file
Install: NPM I add-asset-html-webpack-plugin
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '.. /dll/react.dll.js') // The corresponding DLL file path
}),
Copy the code
8. HardSourceWebpackPlugin, DllPlugin replacement scheme
DllPlugin is easy to understand and hard to use. Then came the HardSourceWebpackPlugin, which provides the same optimization but is extremely simple to use
- Provides intermediate cache function
- The first build didn’t change much
- The second build time is a big savings
Installation:
npm i hard-source-webpack-plugin -D
Copy the code
// webpack.config.js
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
module.exports = {
plugins: [
new HardSourceWebpackPlugin()
]
}
Copy the code
9. IgnorePlugin Excludes modules from the bundle
Webpack Chinese website
var webpack = require('webpack');
module.exports = {
plugins: {
new webpack.IgnorePlugin(/^\.\/locale$/./moment$/)}}Copy the code
10. Use Happypack to execute tasks concurrently to achieve multi-threaded accelerated compilation
Webpack running on Node. Has a single-threaded model, meaning that Webpack needs to process tasks one by one, not multiple tasks at a time. Happy Pack allows Webpack to do this by splitting the task into multiple child threads for concurrent execution, which then send the results to the main process. Thus exerting the power of multi-core CPU computer.
Happypack also takes some time to start, so use it on demand.
Install: NPM i-d happypack
const path = require('path');
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
module.exports = {
mode: 'development'.module: {
rules: [{
test: /\.css$/,
include: path.resolve(__dirname, './src'),
use: [{// Each loader corresponds to an ID
loader: 'happypack/loader? id=css'}}}]],// Add to plugins
plugins: [
new HappyPack({
// Use a unique identifier id to indicate that the current HappyPack is used to process a specific class of files
id: "css".// Loader to process
loaders: ['style-loader'.'css-loader'].threadPool: happyThreadPool
})
]
};
Copy the code
11. ParallelUglifyPlugin
- Webpack built-in Uglify tool compression JS is single threaded
- ParallelUglifyPlugin enables multiple sub-threads to compress files, but each sub-process still compresses the code using UglifyJS
Installation:
npm i -D webpack-parallel-uglify-plugin
Copy the code
Configuration:
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = {
plugins: {
ParallelUglifyPlugin is used to compress the output JS code in parallel
new ParallelUglifyPlugin({
// The argument passed to UglifyJS
// (use UglifyJS compression again, just to help start multi-process)
uglifyJS: {
output: {
beautify: false.// Most compact output
comments: false.// Delete all comments
},
compress: {
// Delete all 'console.log' statements, compatible with Internet Explorer
drop_console: true.// Inline variables that are defined but used only once
collapse_vars: true.// Extract static values that occur multiple times but are not defined as variables
reduce_vars: true}})}}Copy the code
Ii. Production Optimization
1. Use externals to optimize CDN static resources
By deploying resources around the world, CDN enables users to access resources nearby and speeds up access. To access the CDN, you need to upload static resources of web pages to the CDN service. When accessing these resources, the URL provided by the CDN service is used.
<body>
<div id="root">root</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</body>
Copy the code
We can store some JS files on the CDN (reducing the size of the JS packed by Webpack) and import them with tags in index.html
We want to be able to still reference it as import (e.g. Import $from ‘jquery’) when we use it, and we want webPack not to package it, so we can configure externals.
//webpack.config.js
module.exports = {
/ /...
externals: {
// When jquery is introduced via script, you have jquery variables globally
'jquery': 'jQuery'}}Copy the code
2. Use static resource path publicPath (CDN).
// webpack.config.js
output: {publicPath: '//cdnURL.com'.// Specify the CDN address for storing JS files
}
Copy the code
Ensure that static resource files are uploaded or not
3. Processing the CSS file
- Use postCSS to automatically complete the browser prefix caniuse for styles
- Extract the CSS with the MiniCssExtractPlugin
- Compress CSS
3.1 compressed CSS
Use ptimize-CSS-assets-webpack-plugin and CSsnano
Installation:
npm i optimize-css-assets-webpack-plugin -D
npm i cssnano -D
Copy the code
Configuration:
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
plugins: [
new OptimizeCSSAssetsPlugin({
cssProcessor: require("cssnano"), // Introduce the CSsnano configuration compression option
cssProcessorOptions: {
discardComments: { removeAll: true}}})]}Copy the code
4. Compressed HTML
Use the htmlWebpackPlugin
Installation:
npm i html-webpack-plugin -D
Copy the code
Configuration:
new htmlWebpackPlugin({
title: Jingdong Mall.template: "./index.html".filename: "index.html".minify: {
// Compress HTML files
removeComments: true.// Remove comments from HTML
collapseWhitespace: true.// Remove whitespace and newline characters
minifyCSS: true // Compress inline CSS}})Copy the code
5. Tree Shaking Dead Code
Dead Code Features:
- Code will not be executed, not reachable
- The results of code execution are not used
- The code only affects dead variables (write, not read)
5.1 Css tree shaking
Clean up useless CSS with the purgecss-webpack-plugin
Process paths with glob-all
Installation:
npm i purgecss-webpack-plugin -D
npm i glob-all -D
Copy the code
Configuration:
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const globAll = require("glob-all");
module.exports = {
plugins: [
// Remove useless CSS
new PurgeCSSPlugin({
paths: globAll.sync([
// Make the path file for CSS Tree Shaking
path.resolve(__dirname, './src/*.html'),
// Note that we also need to tree shaking HTML files
path.resolve(__dirname, './src/*.js'])})]}Copy the code
5.2 JavaScript tree shaking
The production mode is automatically enabled and only import is supported. Commonjs is not supported
Differences between ES6 and CommonJS
Commonjs is dynamically imported, imported at execution time, the module outputs a shallow copy of the value, which is changed after the module outputs, and other reference modules do not change
ES6 statically imports, compile-time imports, the module outputs references to values, the module outputs changes, the reference module changes
module.exports = {
mode: 'production'
}
Copy the code
- Automatically turn on code compression
- Delete modality code (such as warning in development environment)
- Automatically start tree-shaking
Code Splitting
Single-page application SPA: after packaging, all pages generate only one bundle.js, which makes the code bulky and not easy to download, and does not make proper use of browser resources
Mpa for multiple pages: If multiple pages introduce some common modules, then these common modules can be separated and packaged separately. Common code only needs to be downloaded once and then cached, avoiding repeated downloads.
- The code is smaller
- Create functions with less scope
The concept of code Splitting is not directly related to Webpack, but webpack provides a more convenient way to implement code Splitting based on split-chunk-plugin
optimization: {
splitChunks: {
chunks: 'async'.// For synchronous initial, asynchronous async, all modules
minSize: 30000.// Minimum size, when the module is larger than 30KB
maxSize: 0.// This is not recommended
minChunks: 1.// At least a few chunks of the generated chunk file reference this module
maxAsyncRequests: 5.// Maximum number of asynchronous requests. Default: 5
maxInitialRequests: 3.// Maximum initialization request, entry file synchronization request, default 3
automaticNameDelimiter: The '-'.// Package the split symbol
name: true.// The packaged name can accept a function in addition to a Boolean value
cacheGroups: {/ / cache group
vendors: {
test: /[\\/]node_modules[\\/]/,
name:"vendor".// The name of the separated chunk to cache
priority: -10// Cache group priority A larger number indicates a higher priority
},
other: {chunks: "initial"./ / must choose three: "initial" | | "all" "async" (the default is async)
test: /react|lodash/.// Regular rule validation, if match, extract chunk,
name:"other".minSize: 30000.minChunks: 1,},default: {
minChunks: 2.priority: -20.reuseExistingChunk: true// You can set whether to reuse the chunk}}}}Copy the code
optimization: {
// help us do automatic code splitting
splitChunks: {chunks:"all".// Asynchrony is supported by default, we use all}}Copy the code
7. In the case of Scope promotion,
Webpack uses static analysis of ES6 syntax to work out the dependencies between modules and put modules into the same function as much as possible
Example:
// hello.js
export default "hello webpack";
Copy the code
import str from "./hello.js";
console.log(str);
Copy the code
Through configuration optimization. ConcatenateModules = true to open the Scope Hoisting
// webpack.config.js
module.exports = {
optimization: {
concatenateModules: true}}Copy the code
Iii. Development vs Production mode is differentiated and packaged
Merge common configurations with NPM install webpack-merge -d
Installation:
npm install webpack-merge -D
Copy the code
// webpack.dev.js
const merge = require("webpack-merge");
// Introduce the Webpack common configuration
const commonConfig = require("./webpack.common.js");
const devConfig = {
...
}
// Merge the configuration and export it
module.exports = merge(commonConfig,devConfig);
Copy the code
// package.json
"scripts": {"dev":"webpack-dev-server --config webpack.dev.js"."build":"webpack --config webpack.prod.js"
}
Copy the code
Four,
1. It can be used in production environment
- Optimized the loader processing scope
- Optimizing the Resolve Configuration
- IgnorePlugin
- happyPack
- tree Shaking
- ParallelUglifyPlugin
- Code Splitting
- In the case of Scope promotion
- Optimization using CDN
2. Cannot be used in the production environment
- Hot Module Replacement (HMR: Hot Module Replacement)
- Quantization using tools
- DllPlugin, HardSourceWebpackPlugin