Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
π¨π» Interviewer: Have you been involved in configuring Webpack for your company’s projects? Or did you do anything to optimize the configuration?
π¨πΎ me: No π
π¨π» Interviewer: Em…
At this moment, BGM said, π΅ is afraid of sudden silence.
Actually this is a very sincere answer! Many people really don’t have the opportunity to participate in Webpack configuration on a project, let alone configuration optimization.
Therefore, it is easy to have the following problems:
- Without more practice opportunities, people tend to neglect its learning
- Want to learn, and do not know where to start π€¦βοΈ
At this point, we can start by looking at what is usually asked about Webpack in an interview
Why start with interview questions?
- Find out exactly what Webpack knowledge the interviewer is looking for in the candidate
- It is convenient for us to capture the knowledge focus of learning Webpack
Here I’ve found some representative questions to see how many you can answer π
Q: Which loaders have been used in the Webpack configuration? What does it do?
Q: What plugins have been used in the Webpack configuration? What does it do?
Q: What is the difference between Loader and Plugin?
Q: How do I write a Loader? Introduce the idea?
Q: How do I write a Plugin? Introduce the idea?
Q: Is Webpack Optimize configured? Can you explain it briefly?
Q: How is Webpack level performance optimized?
Q: What is the Webpack process?
Q: How does tree-shaking work?
Q: How is Webpack Hot Update (HMR) implemented?
Q: How does the Babel plug-in in the Webpack package work?
Q. What are the similarities and differences between Webpack and Rollup?
Q: what new features are updated with Webpack5?
How’s thatοΌ Are these questions OK?
Next, we will break down and summarize these interview questions to draw a general knowledge system
After establishing the knowledge system, we will simply divide the knowledge system into three levels:
- Basic – can configure
- Advanced – can be optimized
- Deep – understand the principle
A layer of promotion to play strange π¦, answer different depth of Webpack interview questions π€
Come on, let’s start now π€
First, Webpack foundation
The first part, from the simple “configuration” requirements, first understand Webpack simple configuration and simple configuration will be involved in the interview questions.
1. Simple configuration
This part needs to master:
- What are the general Webpack configuration items?
- What are the common Loaders? How to configure it?
- What are the common plugins? How to configure?
- How is Babel configured? How to use the Babel plug-in?
1.1 Installation Dependencies
Without a doubt, start with a local installation of WebPack and WebPack-CLI
$ npm install webpack webpack-cli -D Install to local dependencies
Copy the code
Installation complete β
+ webpack-cli@4.72.
+ webpack@5.44. 0
Copy the code
1.2 Working Mode
Webpack has supported 0 configuration packaging since 4, so we can test it out
- new
./src/index.js
File, write a simple code
const a = 'Hello ITEM'
console.log(a)
module.exports = a;
Copy the code
Directory structure at this point
ββ SRC β ββ ββ download.jsonCopy the code
- Run directly
npx webpack
, start packing
The ‘mode’ option has not been set…
This means that we have not configured mode, so we are reminded to do so
Mode: The mode configuration option tells Webpack to use the built-in optimizations for the corresponding mode. The default value is Production, and there are also development and None. The differences are as follows
options | describe |
---|---|
development | Development mode, packaging is faster, save code optimization steps |
producttion | Production mode, which is slow to pack, turns on tree-shaking and compression code |
none | Do not use any default optimization options |
How do you configure it? Very simple
- Simply provide the mode option in the configuration object:
module.exports = {
mode: 'development'};Copy the code
- Pass from CLI parameters:
$ webpack --mode=development
Copy the code
1.3 Configuration File
Although there are 0 configuration packages, in actual work, we still need to use configuration files to meet the needs of different projects
-
Create a new configuration file, webpack.config.js, in the root directory
-
Added basic configuration information
const path = require('path')
module.exports = {
mode: 'development'./ / mode
entry: './src/index.js'.// Package entry address
output: {
filename: 'bundle.js'.// Output the file name
path: path.join(__dirname, 'dist') // Output file directory}}Copy the code
I don’t want to say more about this, the basic configuration
1.4 Loader
So if we change the entry to a CSS file, what happens if we package it
1. New. / SRC/main CSS
body {
margin: 0 auto;
padding: 0 20px;
max-width: 800px;
background: #f4f8fb;
}
Copy the code
- Modifying entry Configuration
const path = require('path')
module.exports = {
mode: 'development'./ / mode
entry: './src/main.css'.// Package entry address
output: {
filename: 'bundle.css'.// Output the file name
path: path.join(__dirname, 'dist') // Output file directory}}Copy the code
3. Run pack command: NPX webpack
This is an error!
This is because: Webpack by default supports processing JS files, other types of files can not be processed, here must use Loader to process different types of files.
- The installation
css-loader
To deal with CSS
npn install css-loader -D
Copy the code
- Configure the resource loading module
const path = require('path')
module.exports = {
mode: 'development'./ / mode
entry: './src/main.css'.// Package entry address
output: {
filename: 'bundle.css'.// Output the file name
path: path.join(__dirname, 'dist') // Output file directory
},
module: {
rules: [ // Convert rules
{
test: /.css$/.// Matches all CSS files
use: 'css-loader' // use: indicates the Loader name}}}]Copy the code
- Rerun the package command
npx webpack
Hey hey, can pack π
Dist β β bundle. CSS# The result of packing
Copy the code
This is an attempt to change the entry file back to./ SRC /index.js
Here we can draw a conclusion: Loader is all about converting content that Webpack doesn’t know into content that Webpack does
1.5 Plugin
Unlike a Loader used to convert specific types of files, plugins can perform different tasks throughout the life cycle of a Webpack package
Here’s an example in use:
1. Create the./ SRC /index.html file
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>ITEM</title>
</head>
<body>
</body>
</html>
Copy the code
If I want packaged resource files, such as JS or CSS files, to be automatically imported into Html, I need to use the html-webpack-plugin to help you do this
2. Install the HTmL-webpack-plugin locally
npm install html-webpack-plugin -D
Copy the code
3. Configure the plug-in
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development'./ / mode
entry: './src/index.js'.// Package entry address
output: {
filename: 'bundle.js'.// Output the file name
path: path.join(__dirname, 'dist') // Output file directory
},
module: {
rules: [{test: /.css$/.// Matches all CSS files
use: 'css-loader' // use: indicates the Loader name}},plugins: [// Configure the plug-in
new HtmlWebpackPlugin({
template: './src/index.html'}})]Copy the code
Run the package and open the index.html file generated in the dist directory
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>ITEM</title>
<script defer src="bundle.js"></script></head>
<body>
</body>
</html>
Copy the code
As you can see, it automatically introduces bundled bundle.js, which is very handy
1.6 Automatically Clearing packing Directories
Every time you pack, the package directory will leave behind the files you packed last time. In order to keep the package directory clean, you need to empty the package directory before packing
We can do this using the clean-webpack-plugin
- The installation
$ npm install clean-webpack-plugin -D
Copy the code
- configuration
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// Import plug-ins
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
// ...
plugins: [// Configure the plug-in
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin() // Import plug-ins]}Copy the code
1.7 Differentiating Environments
Local development and deployment lines certainly have different requirements
Local Environment:
- Faster build times are required
- Debug information needs to be printed
- Live reload or Hot Reload is required
- Sourcemap is needed to locate problems
- .
Production environment:
- Need smaller package sizes, code compression +tree-shaking
- Code splitting is required
- Need to compress image volume
- .
For different needs, the first thing to do is to do a good job of environmental differentiation
- Install cross-env locally
npm install cross-env -D
Copy the code
- Configuring Startup Commands
Open. / package. Json
"scripts": {
"dev": "cross-env NODE_ENV=dev webpack serve --mode development"."test": "cross-env NODE_ENV=test webpack --mode production"."build": "cross-env NODE_ENV=prod webpack --mode production"
},
Copy the code
- Get the environment variables in the Webpack configuration file
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
console.log('process.env.NODE_ENV=', process.env.NODE_ENV) // Prints environment variables
const config = {
entry: './src/index.js'.// Package entry address
output: {
filename: 'bundle.js'.// Output the file name
path: path.join(__dirname, 'dist') // Output file directory
},
module: {
rules: [{test: /.css$/.// Matches all CSS files
use: 'css-loader' // use: indicates the Loader name}},plugins: [// Configure the plug-in
new HtmlWebpackPlugin({
template: './src/index.html'}})]module.exports = (env, argv) = > {
console.log('argv.mode=',argv.mode) // Prints the mode value
// The config configuration can be modified in different modes
return config;
}
Copy the code
4. Test it out
- perform
npm run build
process.env.NODE_ENV= prod
argv.mode= production
Copy the code
- perform
npm run test
process.env.NODE_ENV= test
argv.mode= production
Copy the code
- perform
npm run dev
process.env.NODE_ENV= dev
argv.mode= development
Copy the code
This allows us to dynamically modify the Webpack configuration for different environments
1.8 start devServer
1. Install webpack – dev – server
npm intall webpack-dev-server -D
Copy the code
2. Configure the local service
// webpack.config.js
const config = {
// ...
devServer: {
contentBase: path.resolve(__dirname, 'public'), // Static file directory
compress: true.// Whether to enable gzip compression
port: 8080./ / the port number
// open:true // Whether to automatically open the browser
},
// ...
}
module.exports = (env, argv) = > {
console.log('argv.mode=',argv.mode) // Prints the mode value
// The config configuration can be modified in different modes
return config;
}
Copy the code
Why configure contentBase?
Because when WebPack does its packaging, static files, such as images, are copied directly to the dist directory. However, this process is time-consuming and unnecessary for local development, so after setting up contentBase, you can go directly to the corresponding static directory to read the file without moving the file, saving time and performance overhead.
- Start a local service
$ npm run dev
Copy the code
To see the effect, I added a paragraph of text to the HTML and put an image logo.png under public
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>ITEM</title>
</head>
<body>
<p>ITEM</p>
</body>
</html>
Copy the code
Public β β logo. PNGCopy the code
Open the address http://localhost:8080/
Then go to http://localhost:8080/logo.png
OK, no problem π
1.9 the introduction of CSS
Above, we talked about using CSS-loader to handle CSS, but there is no way to use CSS-Loader alone to load the style to the page. At this point, we need to install another style-loader to complete this function
Style-loader adds processed CSS to the page in the form of style tags
- The installation
style-loader
[The document address]
npm install style-loader -D
Copy the code
- Configure the Loader
const config = {
// ...
module: {
rules: [{test: /.css$/.// Matches all CSS files
use: ['style-loader'.'css-loader']]}},// ...
}
Copy the code
β οΈ Note: The Loader execution sequence is fixed from back to front, that is, csS-loader -> style-loader
- Reference style file
Import the style file./ SRC /main.css in the entry file./ SRC /index.js
// ./src/index.js
import './main.css';
const a = 'Hello ITEM'
console.log(a)
module.exports = a;
Copy the code
/* ./src/main.css */
body {
margin: 10px auto;
background: cyan;
max-width: 800px;
}
Copy the code
- Restart the local service, access
http://localhost:8080/
Now that the style is working, go ahead and modify the style
body {
margin: 10px auto;
background: cyan;
max-width: 800px;
/ * new * /
font-size: 46px;
font-weight: 600;
color: white;
position: fixed;
left: 50%;
transform: translateX(-50%);
}
Copy the code
Once saved, the style changes automatically
Style-loader core logic equivalent to:
const content = `${style content}`
const style = document.createElement('style');
style.innerHTML = content;
document.head.appendChild(style);
Copy the code
Introduce styles to the page by dynamically adding style tags
1.10 CSS Compatibility
Use postCSS-loader to automatically add browser prefixes for some CSS3 attributes
Transform: translateX(-50%); The postCSs-loader can be used to help with this
npm install postcss-loader postcss -D
Copy the code
const config = {
// ...
module: {
rules: [{test: /.css$/.// Matches all CSS files
use: ['style-loader'.'css-loader'.'postcss-loader']]}},// ...
}
Copy the code
β οΈ there is a big pitfall here: after the reference document is configured, the runtime will report an error
Error: Loading PostCSS "postcss-import" plugin failed:
Cannot find module 'postcss-import'
Copy the code
Next try installing the plugin’s set postCSS-preset -env and change the configuration to
// webpack.config.js
// Failed to configure
{
loader: 'postcss-loader'.options: {
postcssOptions: {
plugins: [['postcss-preset-env',
{
// Other options},],],},},},Copy the code
After the operation will still report errors, after consulting information, finally found the correct way to open, we re π
npm install postcss postcss-loader postcss-preset-env -D
Copy the code
Example Add the postCSS-loader
const config = {
// ...
module: {
rules: [{test: /.css$/.// Matches all CSS files
use: [
'style-loader'.'css-loader'.'postcss-loader']]}},// ...
}
Copy the code
Create the postCSS configuration file postcss.config.js
// postcss.config.js
module.exports = {
plugins: [require('postcss-preset-env')]}Copy the code
Create the postcss-preset-env configuration file.browserslistrc
# newline is equivalent to and
last 2 versions # Roll back both browser versions
> 0.5% # For browsers used by more than 0.5% of the world's population, check out caniuse.com to see the share of different browsers
IE 10 # Compatible with IE 10
Copy the code
Let’s try it again
The prefix is automatically added to π
If you’re interested in seeing the effects of different configurations of.browserslistrc, you can use autoprefixer to perform online transformations to see the effects
1.11 Importing Less or Sass
Less and sass are also unrecognized by Webpack and need to be processed by the corresponding Loader
The file type | loader |
---|---|
Less | less-loader |
Sass | Sass – loader node – sass or dart – sass |
Less processing is relatively simple. Add the corresponding Loader directly
Sass requires not only installation of sass-Loader but also a Node-sass. Here, node-sass is recommended to be installed using Taobao image. The probability of successful installation of NPM is too small π€£
Let’s use Sass as an example
- The installation
$ npm install sass-loader -D
# Taobao Mirror
$ npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
Copy the code
- new
./src/sass.scss
Sass files can be suffixes.scss(common) or.sass
$color: rgb(190.23.168);
body {
p {
background-color: $color;
width: 300px;
height: 300px;
display: block;
text-align: center;
line-height: 300px; }}Copy the code
- Import Sass files
import './main.css';
import './sass.scss' // Import Sass files
const a = 'Hello ITEM'
console.log(a)
module.exports = a;
Copy the code
- Modify the configuration
const config = {
// ...
rules: [{test: /\.(s[ac]|c)ss$/i.// Matches all sass/ SCSS/CSS files
use: [
'style-loader'.'css-loader'.'postcss-loader'.'sass-loader',]},]},// ...
}
Copy the code
Take a look at the results
Successful π
1.12 Separate style files
Previously, we relied on style-loader to add styles to the page as style tags
However, more often than not, we want to be able to introduce it to the page in the form of A CSS file
- Install the mini – CSS – extract – the plugin
$ npm install mini-css-extract-plugin -D
Copy the code
- Modify the
webpack.config.js
configuration
// ...
// Import plug-ins
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const config = {
// ...
module: {
rules: [
// ...
{
test: /\.(s[ac]|c)ss$/i.// Matches all sass/ SCSS/CSS files
use: [
// 'style-loader',
MiniCssExtractPlugin.loader, / / add the loader
'css-loader'.'postcss-loader'.'sass-loader',]},]},// ...
plugins: [// Configure the plug-in
// ...
new MiniCssExtractPlugin({ // Add a plug-in
filename: '[name].[hash:8].css'
}),
// ...]}// ...
Copy the code
- View packaging results
β ββ avatar.d4d42d72.png β ββ design.html β ββ main.3bcbae64.css# Generated style file
Copy the code
1.13 Image and Font files
The contentBase can be set to read the static file of the image class directly, so take a look at the following two images
- Page direct import
<! -- Local access, production environment will not find the image -->
<img src="/logo.png" alt="">
Copy the code
- Background image introduction
<div id="imgBox"></div>
Copy the code
/* ./src/main.css */.#imgBox {
height: 400px;
width: 400px;
background: url('.. /public/logo.png');
background-size: contain;
}
Copy the code
An error is reported directly
So in fact, Webpack doesn’t recognize the image file and needs to deal with it at packaging time
Common loaders for processing image files include:
Loader | instructions |
---|---|
file-loader | Fix the image import problem and copy the image to the specified directory, default is dist |
url-loader | If the value of an image is smaller than the limit value, the image is converted to Base64 encoding. If the value is larger than the limit value, the image is copied using file-loader |
img-loader | The compressed image |
- The installation
file-loader
npm install file-loader -D
Copy the code
- Modify the configuration
const config = {
/ /...
module: {
rules: [{// ...
},
{
test: /\.(jpe? g|png|gif)$/i.// Match image files
use:[
'file-loader' / / using the file - loader]]}},// ...
}
Copy the code
3. Introduce pictures
<! -- ./src/index.html -->
<! DOCTYPEhtml>
<html lang="en">.<body>
<p></p>
<div id="imgBox"></div>
</body>
</html>
Copy the code
Introduced in the style file
/* ./src/sass.scss */
$color: rgb(190.23.168);
body {
p {
width: 300px;
height: 300px;
display: block;
text-align: center;
line-height: 300px;
background: url('.. /public/logo.png');
background-size: contain; }}Copy the code
Js file
import './main.css';
import './sass.scss'
import logo from '.. /public/avatar.png'
const a = 'Hello ITEM'
console.log(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
Copy the code
Start the service and let’s see what happens
Display normal βοΈ
We can see that the name of the image file has been changed and the hash value has been added. Then I look at the package directory
Dist β β 56482 c77280b3c4ad2f083b727dfcbf9. PNG β β bundle. Js β β d4d42d529da4b5120ac85878f6f69694. PNG β β index. The HTMLCopy the code
There are two additional files under the dist directory that file-loader copied from
If you want to change the name, you can add a configuration
const config = {
/ /...
module: {
rules: [{// ...
},
{
test: /\.(jpe? g|png|gif)$/i,
use:[
{
loader: 'file-loader'.options: {
name: '[name][hash:8].[ext]'}}]}, {loader: 'file-loader'.options: {
name: '[name][hash:8].[ext]'}}},// ...
}
Copy the code
Pack it again
Dist β β avatard4d42d52. PNG β β bundle. Js β β index. The HTML β β logo56482c77. PNGCopy the code
Take a look at url-loader again
- The installation
url-loader
$ npm install url-loader -D
Copy the code
- configuration
url-loader
The configuration is similar to file-loader, with a limit configuration added
const config = {
/ /...
module: {
rules: [{// ...
},
{
test: /\.(jpe? g|png|gif)$/i,
use:[
{
loader: 'url-loader'.options: {
name: '[name][hash:8].[ext]'.// Files smaller than 50K will be converted to Base64, files larger than 50K will be copied
limit: 50 * 1024}}]},]},// ...
}
Copy the code
Look at the size of our two image files
Public β β avatar. PNG# 167kbβ β logo. PNG# 43kb
Copy the code
Let’s pack it and see how it looks
It is obvious that the logo.png file has been converted to base64 π
Look at font file processing
- Configuring font files
First, download the font file locally from iconfont.cn
In your project, create a./ SRC /fonts folder to hold the font files
Then, import to the entry file
// ./src/index.js
import './main.css';
import './sass.scss'
import logo from '.. /public/avatar.png'
// Import the font icon file
import './fonts/iconfont.css'
const a = 'Hello ITEM'
console.log(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
Copy the code
Next, use it in./ SRC /index.html
<! DOCTYPEhtml>
<html lang="en">.<body>
<p></p>
<! -- Use font icon file -->
<! -- 1) iconfont = "iconfont" -->
<! You can find the name of the icon class in iconfont.
<i class="iconfont icon-member"></i>
<div id="imgBox"></div>
</body>
</html>
Copy the code
Finally, add the font file configuration
const config = {
// ...
{
test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i.// Matches the font file
use: [
{
loader: 'url-loader'.options: {
name: 'fonts/[name][hash:8].[ext]'.// If the size is greater than 10KB, pack it into the fonts directory
limit: 10 * 1024,}}]},// ...
}
Copy the code
Pack it up and see how it looks
However, in webpack5, there is a built-in resource processing module, file-loader and url-loader can not be installed
1.14 Use of Resource Modules
Webpack5 adds an asset Module that allows you to use resource files (fonts, ICONS, etc.) without having to configure additional loaders.
The resource module supports the following four configurations:
asset/resource
Splits resources into separate files and exports urls, similar to file-loader.asset/inline
Export the resource as a dataUrl, similar to the previous urL-loader less-than limit parameter.asset/source
Export resource as source code. Similar raw-loader function.asset
The type is selected based on the size of the file, asset/inline is used when the file is less than 8 KB (the default), and asset/ Resource is used otherwise
Post the modified complete code
// ./src/index.js
const config = {
// ...
module: {
rules: [
// ...
{
test: /\.(jpe? g|png|gif)$/i,
type: 'asset'.generator: {
// Outputs the file location and file name
// [ext] comes with a "." which is different from the URL-loader configuration
filename: "[name][hash:8][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 50 * 1024 If the value exceeds 50kb, base64 will not be transferred}}}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i,
type: 'asset'.generator: {
// Outputs the file location and file name
filename: "[name][hash:8][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 If the value exceeds 100kb, base64 will not be transferred}}},]},// ...
}
module.exports = (env, argv) = > {
console.log('argv.mode=',argv.mode) // Prints the mode value
// The config configuration can be modified in different modes
return config;
}
Copy the code
The result is the same as before
1.15 JS Compatibility (Babel)
We want to use the latest Js features in development, but some of the new features are not well supported by browsers, so Js also needs to do compatibility processing, common is to convert ES6 syntax to ES5.
Here comes Babel, the most beautiful girl in the room
- Not configured Babel
Let’s write something about ES6
// ./src/index.js
import './main.css';
import './sass.scss'
import logo from '.. /public/avatar.png'
import './fonts/iconfont.css'
// ...
class Author {
name = 'ITEM'
age = 18
email = '[email protected]'
info = () = > {
return {
name: this.name,
age: this.age,
email: this.email
}
}
}
module.exports = Author
Copy the code
To make it easier to see the source code, let’s change mode to development
Then execute the pack command
Once the package is complete, open bundle.js to see the result of the package
We can still find our code, but it’s a little less intuitive to read, so let’s set mode to None, package it in its original form, and see what happens
The packaged code does not change much, except that the image address is replaced. Now let’s see what happens to the packaged result after configuring Babel
- Install dependencies
$ npm install babel-loader @babel/core @babel/preset-env -D
Copy the code
babel-loader
Load ES2015+ code and convert it to ES5 using Babel@babel/core
Babel compiles the core package@babel/preset-env
The default for Babel compilation can be understood as a superset of Babel plug-ins
- Configure the Babel preset
// webpack.config.js
// ...
const config = {
entry: './src/index.js'.// Package entry address
output: {
filename: 'bundle.js'.// Output the file name
path: path.join(__dirname, 'dist'), // Output file directory
},
module: {
rules: [{test: /\.js$/i,
use: [
{
loader: 'babel-loader'.options: {
presets: [
'@babel/preset-env'],}}]},// ...]},/ /...
}
// ...
Copy the code
After the configuration is complete, perform the packaging
The ES6 class notation I just wrote has been converted to the ES5 constructor form
As far as compatibility is concerned, we can also specify which browsers are compatible
To avoid webpack.config.js being too bloated, it is recommended to extract the Babel configuration file
.babelrc.js is added to the root directory
// ./babelrc.js
module.exports = {
presets: [["@babel/preset-env",
{
// useBuiltIns: false default, regardless of browser compatibility configuration, to introduce all polyfills
// useBuiltIns: Entry introduces browser-incompatible polyfills based on configured browser compatibility
// useBuiltIns: Usage polyfills according to the browser compatibility configured and the API used in your code to implement on-demand additions
useBuiltIns: "entry".corejs: "3.9.1".// Is the core-js version number
targets: {
chrome: "58".ie: "11",},},],],};Copy the code
There you have it: a simple Babel preset
Other common Babel presets are:
@babel/preset-flow
@babel/preset-react
@babel/preset-typescript
If you are interested, you can learn about it yourself. There is no extension here. Let’s talk about the use of plug-ins
- Configure the Babel plug-in
For proposed new features that are not yet in the ECMA specification, Babel cannot handle them. Plug-ins must be installed, such as:
// ./ index.js
import './main.css';
import './sass.scss'
import logo from '.. /public/avatar.png'
import './fonts/iconfont.css'
const a = 'Hello ITEM'
console.log(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
// Add the use of decorators
@log('hi')
class MyClass {}function log(text) {
return function(target) {
target.prototype.logger = () = > `${text}.${target.name}`}}const test = new MyClass()
test.logger()
Copy the code
Let’s do the packing
Not surprisingly, no π π»βοΈ
How can I use it? Babel actually provides the corresponding plug-in:
@babel/plugin-proposal-decorators
@babel/plugin-proposal-class-properties
Install:
$ npm install babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D
Copy the code
Open.babelrc.js with plug-in configuration
module.exports = {
presets: [["@babel/preset-env",
{
useBuiltIns: "entry".corejs: "3.9.1".targets: {
chrome: "58".ie: "11",},},],plugins: [["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true}]]};Copy the code
This is packaged and converted to browser-supported JS code in bundle.js
Similarly, we can use different plug-ins according to our actual needs
2 SourceMap Configuration selection
SourceMap is a mapping that allows us to reverse locate the source code if an error occurs after the project is run
2.1 devtool configuration
const config = {
entry: './src/index.js'.// Package entry address
output: {
filename: 'bundle.js'.// Output the file name
path: path.join(__dirname, 'dist'), // Output file directory
},
devtool: 'source-map'.module: {
// ...
}
// ...
Copy the code
After packaging, the SourceMap file ending with.map is generated in the dist directory
ββ ββ avatard4d02.png ββ bundle.js ββ bundle.jsCopy the code
In addition to the source-map type, there are many other types available, such as:
eval
eval-source-map
cheap-source-map
inline-source-map
cheap-module-source-map
inline-cheap-source-map
cheap-module-eval-source-map
inline-cheap-module-source-map
hidden-source-map
nosources-source-map
So what’s the difference? How to choose?
2.2 Configuration Item Differences
- To make it easier to compare them, let’s create a new project
ββ ββ download.txt ββ download.txt ββ download.txtCopy the code
- Open the
./src/Author.js
class Author {
name = 'ITEM'
age = 18
email = '[email protected]'
info = () = > {
return {
name: this.name,
age: this.age,
email: this.email
}
}
}
module.exports = Author
Copy the code
- Open the
./src/index.js
import Author from './Author'
const a = 'Hello ITEM'
console.log(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
const author = new Author();
console.log(author.info)
Copy the code
- Open the
package.json
{
"name": "webpack-source-map"."version": "1.0.0"."description": ""."main": "index.js"."license": "MIT"."scripts": {
"build": "webpack"
},
"devDependencies": {
"@babel/core": "^ 7.6.4." "."@babel/preset-env": "^ 7.6.3." "."babel-loader": "^ 8.0.6"."html-webpack-plugin": "^ 3.2.0"."webpack": "^ 5.44.0"."webpack-cli": "^ 4.7.2." "}}Copy the code
- Open the
webpack.config.js
// Multi-entry packing
module.exports = [
{
entry: './src/index.js'.output: {
filename: 'a.js'}}, {entry: './src/index.js'.output: {
filename: 'b.js'}}]Copy the code
Run the pack command NPM run build to see the results
ββ a.exercises β b.exercisesCopy the code
Don’t worry about what is in the packing result a.js B.js, the purpose of this step is to test multi-entry packing
The purpose of the transformation into multiple entrances is to facilitate our later comparison
- Use separate package entry for different configuration items, open
webpack.config.js
Modify the
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 1) Define different packaging types
const allModes = [
'eval'.'source-map'.'eval-source-map'.'cheap-source-map'.'inline-source-map'.'cheap-eval-source-map'.'cheap-module-source-map'.'inline-cheap-source-map'.'cheap-module-eval-source-map'.'inline-cheap-module-source-map'.'hidden-source-map'.'nosources-source-map'
]
// 2) Loop through different SourceMap modes to generate multiple packaging entries
module.exports = allModes.map(item= > {
return {
devtool: item,
mode: 'none'.entry: './src/main.js'.output: {
filename: `js/${item}.js`
},
module: {
rules: [{test: /.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env']}}}]},plugins: [
3) output to different pagesnew HtmlWebpackPlugin({
filename: `${item}.html`}}})]Copy the code
- Mock code error
// ./src/index.js
import Author from './Author'
const a = 'Hello ITEM'
// Error console.log is intentionally used
console.log11(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
const author = new Author();
console.log(author.info)
Copy the code
- Try to pack
Error!!
Error: SourceMap schema name is incorrect, their concatenation is regular and meaningful
We check in accordance with the rules ^ (inline – | hidden – | eval -)? (nosources-)? (cheap-(module-)?) ? Source-map $Check
Cheap-eval-source-map and cheap-module-eval-source-map seem to have some problems
// After modification
const allModes = [
'eval'.'source-map'.'eval-source-map'.'cheap-source-map'.'inline-source-map'.'eval-cheap-source-map'.'cheap-module-source-map'.'inline-cheap-source-map'.'eval-cheap-module-source-map'.'inline-cheap-module-source-map'.'hidden-source-map'.'nosources-source-map'
]
Copy the code
Do the packaging again
There are still errors!! Then change
I checked the error message, most likely the version of HTML-webpack-pugin is too old, not compatible with Webpack5, let’s upgrade the version to “HTML-webpack-plugin “: “^5.3.2” and try again, OK
Dist ββ JS β ββ cheap-module-source-map.js#... There are corresponding.map filesβ ββ Heavy Exercises - Cheap -module-source-map.js#... There areβ ββ Anti-Flag - Cheap - Source-map.js β ββ Cheap - Module-source-Map.js β ββ Cheap - Source-Map.js β ββ Cheap - Module-Source-Map.js#... There is noβ β β eval - being - source - map. Js#... There is noβ β β eval - source - map. Js#... There is noβ β β eval. Js#... There is noβ β β hidden - source - map. Js#... There areβ ββ ββ Inline-cheap module-source-map.js. β ββ Inline-cheap module-source-Map.js#... There is noβ β β the inline - being - source - map. Js#... There is noβ β β the inline - source - map. Js#... There is noβ β β nosources - source - map. Js#... There areβ ββ Nosource-Map.js. β ββ Source-Map.js#... There areβ β β the source - map. Js. Map β β being - the module - the source - the map. The HTML β β being - source - map. HTML β β eval - being - the module - source - map. HTML β β Eval-cheap source-map.html ββ Eval.html ββ Eval.html ββ Hidden Source-Map.html ββ Inline-cheap source-map.html ββ Inline-cheap source-map.html ββ Inline-cheap Source-Map.html ββ Inline-cheap Source-Map.html ββ Inline-cheap Source-Map.html Nosources - source - map. HTML β β the source - map. HTMLCopy the code
We can easily see from the directory structure that eval and inline mode have no corresponding. Map file
Next, we create a service in the dist directory and open it in the browser
And then, let’s do it one by one
eval
Mode:
- The generated code executes via eval ππ»
- The source code location is marked ππ» at @sourceurl
-
The error location cannot be located, only a file can be located
-
No need to generate SourceMap file, fast packaging
source-map
Mode:
- The corresponding SourceMap file is generated, and the packaging speed is slow
- Locate the error line information in the source code ππ»
eval-source-map
Mode:
- The generated code executes via eval ππ»
2. IncludedataUrlSourceMap file in the form
- The error row information can be located in the compiled code
- Generate SourceMap in the form of dataUrl, which is slow to pack
eval-cheap-source-map
Mode:
- The generated code is executed through eval
- Contains SourceMap files in the form of dataUrl
- The error line information can be located in the compiled code
- No need to locate column information, fast packaging
eval-cheap-module-source-map
Mode:
- The generated code is executed through eval
- Contains SourceMap files in the form of dataUrl
- The error line information can be located in the compiled code
- No need to locate column information, fast packaging
- Locate the error line in the source code ππ»
inline-source-map
Mode:
- Import the SourceMap file as a dataUrl ππ»
. The rest is the same as source-map mode
hidden-source-map
Mode:
- The SourceMap effect is not visible, but the SourceMap file is generated
nosources-source-map
Mode:
- You can see the error location ππ»
- But there’s no way to actually source it
Next, let’s summarize a little bit:
devtool | build | rebuild | According to the code | SourceMap file | describe |
---|---|---|---|---|---|
(none) | soon | soon | There is no | There is no | Unable to locate error |
eval | fast | Fast (cache) | The compiled | There is no | Locate the file |
source-map | slow | slow | The source code | There are | Locate row and column |
eval-source-map | slow | General (cache) | The compiled | There are (dataUrl) | Locate row and column |
eval-cheap-source-map | general | Fast (cache) | The compiled | There are (dataUrl) | Locate the line |
eval-cheap-module-source-map | slow | Fast (cache) | The source code | There are (dataUrl) | Locate the line |
inline-source-map | slow | slow | The source code | There are (dataUrl) | Locate row and column |
hidden-source-map | slow | slow | The source code | There are | Unable to locate error |
nosource-source-map | slow | slow | The source code | There is no | Locate the file |
Compare validation rules ^ (inline – | hidden – | eval -)? (nosources-)? (cheap-(module-)?) ? Source-map $analyzes the keywords
The keyword | describe |
---|---|
inline | SourceMap is introduced in the code in the form of dataUrl |
hidden | Generate the SourceMap file, but do not use it |
eval | eval(...) Form to introduce SourceMap through the dataUrl form |
nosources | Don’t generate SourceMap |
cheap | You only need to locate row information, not column information |
module | Shows the error location in the source code |
Well, that’s it for SourceMap
2.3 Recommended Configuration
- Local development:
Recommendation: eval – being – the module – the source – the map
Reason:
- It doesn’t matter if native developers pack slowly for the first time because
eval
Because of caching, rebuild will be quick - In development, we don’t write too long per line of code, just need to locate the line, so plus
cheap
- We want to be able to find errors in source code, not packaged, so we need to add
modele
- Production environment:
Recommended: (none)
Reason:
- I just don’t want anyone to see my source code
3. Three hash values
The Fingerprint policy for Webpack files is to append the file name with a hash value. Caching is an advantage especially when using CDN, but if you pack filenames without hash suffixes, you will definitely suffer from caching π
For example: filename: “[name][hash:8][ext]”
What do they all mean? Please look at the table below ππ»
A placeholder | explain |
---|---|
ext | File name extension |
name | The file name |
path | File relative path |
folder | File folder |
hash | Unique hash value generated for each build |
chunkhash | Generates a hash value based on chunk |
contenthash | Generates a hash value based on the file content |
Hash, chunkhash, contenthash
- Hash: Any change to a file changes the build hash value of the entire project.
- Chunkhash: Changes only affect the hash value of the chunk where the file resides.
- Contenthash: Each file has a separate hash value. Changes to the file only affect its own hash value.
Two, Webpack advanced
In the second part, we will move in the direction of “can optimize” π
In addition to configuration optimization, we also need to learn how to develop Loader and Plugin
1. Optimize the construction speed
1.1 Construction time-consuming analysis
Here we need to use the speed-measure-webpack-plugin, we refer to the documentation to configure
- So let’s just install it
$ npm i -D speed-measure-webpack-plugin
Copy the code
- Modify our configuration file webpack.config.js
.// Take time to analyze
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = newSpeedMeasurePlugin(); .constconfig = {... }module.exports = (env, argv) = > {
// The config configuration can be modified in different modes
return smp.wrap(config);
}
Copy the code
- Perform packaging
The error π€¦ π» came οΈ
This exposes one of the drawbacks of using this plugin:
- Some Loader or Plugin versions are incompatible and need to be degraded
Here we downgrade the mini-CSS-extract-plugin to ^2.1.0 -> ^1.3.6
Reinstall the dependencies and pack again
Error: publicPath: ‘./’
output: {
filename: 'bundle.js'.// Output the file name
path: path.join(__dirname, 'dist'), // Output file directory
publicPath: '/'
},
Copy the code
Try again
Success!
Note: In Webpack 5.x it is not cost-effective to downgrade or change the configuration of the plugin to use time-wasting analysis. I will continue to use it for demonstration purposes, but it is not recommended to use it in normal development.
1.2 Optimize the Resolve Configuration
1.2.1 alias
Alias: an alias used to create an import or require, used to simplify module references.
const path = require('path')...// Path processing method
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
...
resolve: {// Configure the alias
alias: {
'~': resolve('src'),
The '@': resolve('src'),
'components': resolve('src/components'),}}};Copy the code
Once the configuration is complete, we can do it in the project
// Use the SRC alias ~
import '~/fonts/iconfont.css'
// Use the SRC alias @
import '@/fonts/iconfont.css'
// Use the components alias
import footer from "components/footer";
Copy the code
1.2.2 extensions
Webpack default configuration
const config = {
/ /...
resolve: {
extensions: ['.js'.'.json'.'.wasm'],}};Copy the code
If the user imports the module without an extension, for example
import file from '.. /path/to/file';
Copy the code
Webpack then attempts to parse modules in left-to-right order from the extensions configuration array
Note that:
- High frequency file name suffix in front;
- After manual configuration, the default configuration will be overwritten
If you want to keep the default configuration, you can use… The extended operator represents the default configuration, for example
const config = {
/ /...
resolve: {
extensions: ['.ts'.'... '],}};Copy the code
1.2.3 modules
Tells WebPack which directory to search for when parsing a module, the common configuration is as follows
const path = require('path');
// Path processing method
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
/ /...
resolve: {
modules: [resolve('src'), 'node_modules'],}};Copy the code
Telling Webpack to find the files that need to be parsed in the SRC directory first saves you a lot of time
1. ResolveLoader
ResolveLoader has the same set of attributes as the Resolve object above, but is only used to resolve the Loader package for WebPack.
In general, keep the default configuration, but if you have a custom Loader, you need to configure it, it may not be able to find the Loader error
- For example: we put our own loader under the loader folder
How can we configure it
const path = require('path');
// Path processing method
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
/ /...
resolveLoader: {
modules: ['node_modules',resolve('loader')]}};Copy the code
1.3 externals
The externals configuration option provides the method to “exclude dependencies from the output bundle”. This feature is usually most useful to library developers, but there are a variety of applications that use it.
For example, importing jQuery from CDN instead of packaging it:
- The introduction of the link
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"
></script>
Copy the code
- Configuration externals
const config = {
/ /...
externals: {
jquery: 'jQuery',}};Copy the code
- Using jQuery
import $ from 'jquery';
$('.my-element').animate(/ *... * /);
Copy the code
We can use this approach to strip away the dependencies that don’t need to be changed and save a lot of time packaging builds.
1.3 Narrowing the Scope
When configuring loader, specify the directory that loader uses or the directory that loader excludes more accurately. Use include and exclude to implement this function. Common examples are as follows:
- Include: resolves modules that meet the requirements
- Exclude: excludes the qualified modules
- Exclude has a higher priority
For example, when configuring Babel
const path = require('path');
// Path processing method
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
/ /...
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.js$/i,
include: resolve('src'),
exclude: /node_modules/,
use: [
'babel-loader',]},// ...]}};Copy the code
1.3 noParse
- You don’t need to parse dependent third-party large class libraries, etc., and you can configure this field to speed up builds
- Modules ignored with noParse are not parsed in their files
import
,require
Such as grammar
const config = {
/ /...
module: {
noParse: /jquery|lodash/, rules:[...] }};Copy the code
1.4 IgnorePlugin
Prevents the following regular expression matching module from being generated when import or require is called:
requestRegExp
A regular expression that matches (test) the resource request path.contextRegExp
Matches (test) a regular expression for the resource context (directory).
new webpack.IgnorePlugin({ resourceRegExp, contextRegExp });
Copy the code
The following examples demonstrate several uses of this plug-in.
- Install the moment plugin.
$ npm i -S moment
Copy the code
- Configuration IgnorePlugin
/ / introduce webpack
const webpack = require('webpack')
const config = {
...
plugins: [// Configure the plug-in.new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,})]};Copy the code
The purpose is to eliminate the non-Chinese voice in the plug-in, which can greatly save the volume of packaging
1.5 Multi-Process Configuration
Note: In fact, in small projects, enabling multi-process packaging can actually increase the time cost because of the overhead of starting the process and communicating between processes.
1.5.1 thread – loader
Loaders configured after thread-loader will run in a separate worker pool
- The installation
$ npm i -D thread-loader
Copy the code
- configuration
const path = require('path');
// Path processing method
function resolve(dir){
return path.join(__dirname, dir);
}
const config = {
/ /...
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.js$/i,
include: resolve('src'),
exclude: /node_modules/,
use: [
{
loader: 'thread-loader'.// Enable multi-process packaging
options: {
worker: 3,}},'babel-loader',]},// ...]}};Copy the code
1.5.2 happypack β
The same tool for enabling multi-process packaging, webpack5 has been deprecated.
1.6 Using cache
Using caching can greatly increase the rate of repeat builds
1.6.1 babel-loader Enables caching
- Babel has a large time cost ratio in the process of js translation, so it caches the execution results of babel-loader, and directly reads the cache when repackaging
- Cache location:
node_modules/.cache/babel-loader
The configuration is as follows:
const config = {
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.js$/i,
include: resolve('src'),
exclude: /node_modules/,
use: [
// ...
{
loader: 'babel-loader'.options: {
cacheDirectory: true // Enable caching}}},],// ...]}}Copy the code
How do other loaders cache results?
Cache-loader can do this for us
1.6.2 cache – loader
- Cache the processing results of some Loaders with high performance overhead
- Cache location:
node_modules/.cache/cache-loader
- The installation
$ npm i -D cache-loader
Copy the code
- Configure cache – loader
const config = {
module: {
// ...
rules: [{test: /\.(s[ac]|c)ss$/i.// Matches all sass/ SCSS/CSS files
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'cache-loader'.// Get the result of the previous Loader conversion
'css-loader'.'postcss-loader'.'sass-loader',]},// ...]}}Copy the code
1.6.3 hard – source – webpack – the plugin
- The hard-source-webpack-plugin provides an intermediate cache for modules, reducing the repeat build time by about 80%, but the module cache is already built into Webpack 5, so you don’t need to use this plug-in
1.6.4 dll β
This approach to module caching is no longer recommended in Webpack 5.x because it has a better experience of caching built in
1.6.5 Cache Persistent Cache
Improve build speed by configuring webpack modules and chunks generated by the cache cache.
const config = {
cache: {
type: 'filesystem',}};Copy the code
2. Optimize the construction results
2.1 Analysis of construction results
With the help of the plug-in Webpack-bundle-Analyzer, we can intuitively see problems in the packaging results, such as the size of files, dependencies of each module, and whether files are repetitive, which is greatly convenient for us to diagnose problems during project optimization.
- The installation
$ npm i -D webpack-bundle-analyzer
Copy the code
- Configure the plug-in
// Import plug-ins
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const config = {
// ...
plugins: [// ...
// Configure the plug-in
new BundleAnalyzerPlugin({
// analyzerMode: 'disabled', // do not start the HTTP server to display the packaged report
// generateStatsFile: true, // Whether to generate stats.json file})]};Copy the code
- Modifying a Startup Command
"scripts": {
// ...
"analyzer": "cross-env NODE_ENV=prod webpack --progress --mode production"
},
Copy the code
- Execute compile command
npm run analyzer
After the package is complete, the web service whose address is http://127.0.0.1:8888 is automatically started
If we just want to keep the data and not start the Web service, we can add two configurations
new BundleAnalyzerPlugin({
analyzerMode: 'disabled'.// Do not start the HTTP server that displays packaged reports
generateStatsFile: true.// Whether to generate stats.json file
})
Copy the code
This will only produce a state.json file when the packaging is performed again
2.2 compressed CSS
- Install optimize – CSS – assets – webpack – the plugin
$ npm install -D optimize-css-assets-webpack-plugin
Copy the code
- Modify the
webapck.config.js
configuration
// ...
/ / compress CSS
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
// ...
const config = {
// ...
optimization: {
minimize: true.minimizer: [
// Add the CSS compression configuration
new OptimizeCssAssetsPlugin({}),
]
},
// ...
}
// ...
Copy the code
- View packaging results
2.3 compressed JS
Packaging in a build environment turns JS compression on by default, but after manually configuring the Optimization option, js compression is no longer done by default, requiring manual configuration.
Because Webpack5 has built-in terser-webpack-plugin, we do not need to install it repeatedly and can refer to it directly. The specific configuration is as follows
const TerserPlugin = require('terser-webpack-plugin');
const config = {
// ...
optimization: {
minimize: true.// Enable minimization
minimizer: [
// ...
new TerserPlugin({})
]
},
// ...
}
Copy the code
2.4 Clearing Useless CSS
Purgecss-webpack-plugin extracts CSS separately and cleans up unused CSS
- Installing a plug-in
$ npm i -D purgecss-webpack-plugin
Copy the code
- Add the configuration
// ...
const PurgecssWebpackPlugin = require('purgecss-webpack-plugin')
const glob = require('glob'); // File matching mode
// ...
function resolve(dir){
return path.join(__dirname, dir);
}
const PATHS = {
src: resolve('src')}const config = {
plugins: [// Configure the plug-in
// ...
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/ * * / * `, {nodir: true]}})}),Copy the code
2.5 the Tree – shaking
Tree-shaking reduces the size of the package by weeding out unused code
- Webpack is supported by default and needs to be set up in.bablerc
Model: false
, can be enabled by default in the production environment
For more about tree-shaking, read ππ». From the past to the present, talk about tree-shaking
module.exports = {
presets: [["@babel/preset-env",
{
module: false.useBuiltIns: "entry".corejs: "3.9.1".targets: {
chrome: "58".ie: "11",},},],plugins: [["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true}]]};Copy the code
2.6 the Scope Hoisting
In this way, the function declaration and memory overhead can be reduced by placing multiple modules in the same Scope and renaming them to prevent naming conflicts.
- Webpack is supported by default and is enabled by default in production
- Only ES6 code is supported
3. Optimize the runtime experience
The core of runtime optimization is improving the loading speed of the first screen, and the main way is
- Reduce the volume of files to be loaded on the first screen. Files that are not needed on the first screen can be preloaded or loaded on demand
3.1 Entry point segmentation
Configure multiple packaging entry, multi-page packaging, here but more introduction
3.2 splitChunks subcontract configuration
Optimization.splitchunks is implemented based on the SplitChunksPlugin plug-in
By default, it only affects on-demand chunks, because modifying initial chunks affects script tags in the project’s HTML file.
Webpack will automatically split chunks based on the following criteria:
- New chunks can be shared, or modules can come from
node_modules
folder - The new chunk size is greater than 20KB (before min+gz)
- When chunks are loaded on demand, the maximum number of parallel requests is less than or equal to 30
- The maximum number of concurrent requests is less than or equal to 30 when the initialization page is loaded
- Default Configuration
module.exports = {
/ /...
optimization: {
splitChunks: {
chunks: 'async'.// Valid values are 'all', 'async' and 'initial'
minSize: 20000.// The minimum size of chunk generated (β 20KB)
minRemainingSize: 0.// Ensure that the minimum chunk size left after splitting exceeds the limit to avoid zero-size modules
minChunks: 1.// The minimum number of chunks that must be shared before splitting.
maxAsyncRequests: 30.// Maximum load times on demand (asynchronous)
maxInitialRequests: 30.// The number of js files that can be loaded at the same time (including the entry files)
enforceSizeThreshold: 50000.cacheGroups: { // Configure the extraction module scheme
defaultVendors: {
test: /[\/]node_modules[\/]/,
priority: -10.reuseExistingChunk: true,},default: {
minChunks: 2.priority: -20.reuseExistingChunk: true,},},},},};Copy the code
- Use in projects
const config = {
/ /...
optimization: {
splitChunks: {
cacheGroups: { // Configure the extraction module scheme
default: false.styles: {
name: 'styles'.test: /\.(s? css|less|sass)$/,
chunks: 'all'.enforce: true.priority: 10,},common: {
name: 'chunk-common'.chunks: 'all'.minChunks: 2.maxInitialRequests: 5.minSize: 0.priority: 1.enforce: true.reuseExistingChunk: true,},vendors: {
name: 'chunk-vendors'.test: /[\\/]node_modules[\\/]/,
chunks: 'all'.priority: 2.enforce: true.reuseExistingChunk: true,},/ /... According to different projects to refine the split content}},}},Copy the code
3.3 Code lazy loading
For some resources that are not needed for the first screen loading, we can achieve it by lazy loading. Here is a small π°
- Need: Click on the picture to add a description to the picture
1. Create an image description
desc.js
const ele = document.createElement('div')
ele.innerHTML = 'I'm a picture description'
module.exports = ele
Copy the code
2. Click on the picture to introduce the description
index.js
import './main.css';
import './sass.scss'
import logo from '.. /public/avatar.png'
import '@/fonts/iconfont.css'
const a = 'Hello ITEM'
console.log(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
// Load as needed
img.addEventListener('click'.() = > {
import('./desc').then(({ default: element }) = > {
console.log(element)
document.body.appendChild(element)
})
})
Copy the code
3. Check the effect
- Click on the former
- After clicking on
3.4 the prefetch and preload
Above, we used asynchronous loading to introduce the description of the picture. However, if the file that needs asynchronous loading is relatively large, loading when clicking will also affect our experience. At this time, we can consider using Prefetch to carry out pre-fetching
3.4.1 track prefetch
- Prefetch: A resource is fetched when the browser is idle
Modify the above code
// Load as needed
img.addEventListener('click'.() = > {
import( /* webpackPrefetch: true */ './desc').then(({ default: element }) = > {
console.log(element)
document.body.appendChild(element)
})
})
Copy the code
3.4.2 preload
- Preload: Preloads key resources that will be used later
- β οΈ will pull resources in advance, if not special needs, use with caution
Official website example:
import(/* webpackPreload: true */ 'ChartingLibrary');
Copy the code
4. Write a Loader
TODO
5. Write a Plugin
TODO
The mystery of the missing blogger
In fact, I intend to sort out a problem related to webpack knowledge system from August, but I did not expect to sort it out for several months π
And has not finished sorting π
In order to avoid the end of the article rotten, or decided to update the section
This will be supplemented by the next article: In-depth WebPack
The general contents include:
- Webpack debugging
- Webpack build process
- The Thermal renewal (HRM) principle
- Webpack core library Tapabel is introduced
- The tree – shaking principle
- Babel & AST syntax tree
Like, follow, comment, support a wave
Your support, is my writing power, like, attention, comment, support a wave of π
Pay close attention to my public number: the front end moves the brick worker, constructs the knowledge system together
The resources
- Webpack official documentation
- postcss-loader
- file-loader
- Learn the way to Webpack5