1. Getting started (let’s use these small examples to familiarize you with the configuration of webpack)
1.1 initialization items
Create a new directory and initialize NPM
npm init
Webpack runs in the node environment. We need to install the following two NPM packages
npm i -D webpack webpack-cli
- NPM I – D is the abbreviation of NPM install — save dev
- NPM I – s is the abbreviation of NPM install — save
Create a new foldersrc
, and then create a new filemain.js
, write some code to test it
console. Log ('call me Yuan ')
Configure package JSON command

implement
npm run build
At this point, if a dist folder is generated and contains main JS indicates that the package has been successfully packaged
1.2 start our own configuration
The above simple example is only the default configuration of webpack. Next, we want to implement richer custom configurations
Create a newbuild
Folder, create a new one insidewebpack.config.js
// webpack.config.js
const path = require('path');
module.exports = {
Mode: 'development', // development mode
entry: path.resolve(__dirname, '../src/main.js'),
//Entry file
output: {
filename: 'output. JS', // packaged file name
path: path. Resolve (_dirname, '.. / dist') // packaged directory
}
}
Change our packaging command

implementnpm run build
You will find that the following directories (pictures) have been generated
amongdist
In foldermain.js
Is the file we need to actually run in the browser
Of course, it’s not just that in practical application. Let’s take you to quickly start webpack through practical cases
1.3 configuring HTML templates
The JS file is packaged, but we can’t do it every timehtml
Manually import the packaged in the filejs
Some friends here may think that the name of our packaged JS file is not always fixed(
output.js
)? So you don’t have to change the name of the imported file every time? In fact, we often configure this in our daily development:
module. Exports = {// omit other configurations
output: {
filename: '[name]. [hash:8]. JS', // packaged file name
path: path. Resolve (_dirname, '.. / dist') // packaged directory
}
}
Generated at this timedist
The catalog file is as follows

For caching, you will find that the name of the packaged JS file is different every time. The JS file packaged by webpack needs to be introduced into HTML, but it is very troublesome for us to manually modify the JS file name every time, so we need a plug-in to help us do this
npm i -D html-webpack-plugin
Create a newbuild
Peer folderpublic
, create a new index html
The specific configuration files are as follows
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = {
Mode: 'development', // development mode
entry: path. Resolve (_dirname, '.. / SRC / main. JS'), // entry file
output: {
filename: '[name]. [hash:8]. JS', // packaged file name
path: path. Resolve (_dirname, '.. / dist') // packaged directory
},
plugins: [new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
})]
}
The generated directory is as follows (picture)

It can be found that the JS file generated by packaging has been automatically introduced into the HTML file
1.3.1. How to develop multi entry files
Generate multiple
html-webpack-plugin
Examples to solve this problem
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
Mode: 'development', // development mode
entry: {
main: path.resolve(__dirname, '../src/main.js'),
header: path.resolve(__dirname, '../src/header.js')
},
output: {
filename: '[name]. [hash:8]. JS', // packaged file name
path: path. Resolve (_dirname, '.. / dist') // packaged directory
},
plugins: [new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'),
filename: 'index.html',
Chunks: ['main '] // module name corresponding to the entry file
}), new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/header.html'),
filename: 'header.html',
Chunks: ['header '] // module name corresponding to the entry file
}), ]
}
The following directories will be found:

1.3.2 clean-webpack-plugin
Every time you execute NPM run build, you will find that the last packaged file will remain in the dist folder. Here we recommend a plugin to help us empty the folder before packaging and output
clean-webpack-plugin
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module. Exports = {//... Omit other configurations
plugins:[new CleanWebpackPlugin()]
}
1.4 reference CSS
Our entry file is JS, so we introduce our CSS file into the entry JS

At the same time, we also need some loaders to parse our CSS files
npm i -D style-loader css-loader
If we use less to build styles, we need to install two more
npm i -D less less-loader
The configuration file is as follows
// webpack.config.js
module. Exports = {//... Omit other configurations
module: {
rules: [{
test: /.css$/,
Use: ['style loader', 'CSS loader'] // parse the policy from right to left
}, {
test: /.less$/,
Use: ['style loader', 'CSS loader', 'less loader'] // parse the policy from right to left
}]
}
}
Browser openhtml
as follows

1.4.1 add browser prefix to CSS
npm i -D postcss-loader autoprefixer
The configuration is as follows
// webpack.config.js
module.exports = {
module: {
Rules: [test /. Less $/, use: ['style loader', 'CSS loader', 'postcss loader', 'less loader'] // parse the policy from right to left
]
}
}
Next, we need to introduceautoprefixer
There are two ways to make it effective
1. Create one under the project root directorypostcss.config.js
File, the configuration is as follows:
module. Exports = {plugins: [require ('autoprefixer ')] // just reference the plug-in}
2. Directly inwebpack.config.js
Interior configuration
// webpack.config.js
module. Exports = {//... Omit other configurations
module: {
rules: [{
test: /.less$/,
use: ['style-loader', 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}, 'less loader'] // parse the policy from right to left
}]
}
}
At this time, we find that CSS is added to HTML files through style tags, but if there are many style files, all of them are added to HTML, it will inevitably appear chaotic. At this time, we want to split the CSS and introduce the CSS file in the form of external chain. What should we do? At this time, we need to use plug-ins to help us
1.4.2 splitting CSS
npm i -D mini-css-extract-plugin
Before webpack 4.0, we passed
extract-text-webpack-plugin
Plug in to extract CSS styles from JS files into separate CSS files. webpack4. After 0, it is officially recommendedmini-css-extract-plugin
Plug in to package CSS files
The configuration file is as follows
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module. Exports = {//... Omit other configurations
module: {
rules: [{
test: /.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
}]
},
plugins: [new MiniCssExtractPlugin({
filename: "[name].[hash].css",
chunkFilename: "[id].css",
})]
}
1.4.3 splitting multiple CSS
We need to be more specific here, as we used above
mini-css-extract-plugin
All CSS styles will be merged into one CSS file. If you want to split multiple CSS files into one-to-one correspondence, we need to useextract-text-webpack-plugin
At presentmini-css-extract-plugin
This feature is not yet supported. We need to install the @ next versionextract-text-webpack-plugin
npm i - D extract - text - webpack - plugin @next // webpack.config.js
const path = require('path');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
let indexLess = new ExtractTextWebpackPlugin('index.less');
let indexCss = new ExtractTextWebpackPlugin('index.css');
module.exports = {
module: {
rules: [{
test: /.css$/,
use: indexCss.extract({
use: ['css-loader']
})
}, {
test: /.less$/,
use: indexLess.extract({
use: ['css-loader', 'less-loader']
})
}]
},
plugins: [indexLess, indexCss]
}
1.5 package pictures, fonts, media, and other documents
file-loader
After some processing (mainly processing the file name and path, parsing the file URL), the file is moved to the output directoryurl-loader
General andfile-loader
When used together, the function is similar to that of file loader. If the file size is less than the limit. Base64 encoding will be returned. Otherwise, use file loader to move the file to the output directory
// webpack.config.js
module. Exports = {// omit other configurations
module: {
rules: [ // ...
{
test: /. (JPE? G|png|gif) $/ I, // image file
use: [{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}]
}, {
test: /. (mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, // Media files
use: [{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}]
}, {
test: /. (woff2?|eot|ttf|otf)(?.*)?$/ i. // font
use: [{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}]
},
]
}
}
1.6 escaping JS files with Babel
In order to make our JS code compatible with more environments, we need to install dependencies
npm i babel-loader @babel/preset-env @babel/core
- be careful
babel-loader
Andbabel-core
Version correspondence of
-
babel-loader
8. X correspondencebabel-core
7.x -
babel-loader
7. X correspondencebabel-core
6.x
The configuration is as follows
// webpack.config.js
module. Exports = {// omit other configurations
module: {
rules: [{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
exclude: /node_modules/
}, ]
}
}
abovebabel-loader
Only ES6 / 7 / 8 syntax will be converted to Es5 syntax, but the new API will not be converted (e.g. promise, generator, set, maps, proxy, etc.)
At this time, we need to use Babel Polyfill to help us transform
npm i @babel/polyfill
// webpack.config.js
const path = require('path')module.exports = {
Entry: ["@ Babel / Polyfill, path. Resolve (_dirname,'.. / SRC / index. JS')"], // entry file}
- Typing the above demo manually is more beneficial to reading the following articles. It is recommended that the introductory students knock it more than three times
The above practice is that we have a preliminary understanding of the functions of webpack, but we need a systematic practice in order to skillfully apply it to development. Let’s get rid of scaffolding and try to build a Vue development environment ourselves
2. Build Vue development environment
The above small example has helped us to package CSS, images, JS, HTML and other files.
However, we also need the following configurations
2.1 analysis Vue file
npm i -D vue-loader vue-template-compiler vue-style-loadernpm i -S vue
vue-loader
For parsing.vue
filevue-template-compiler
Used to compile templates
The configuration is as follows
const vueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
module: {
rules: [{
test: /.vue$/,
use: ['vue-loader']
}, ]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js',
' @': path.resolve(__dirname, '../src')
},
extensions: ['*', '.js', '.json', '.vue']
},
plugins: [new vueLoaderPlugin()]
}
2.2 configure webpack dev server for hot update
npm i -D webpack-dev-server
The configuration is as follows
const Webpack = require('webpack')
module. Exports = {//... Omit other configurations
devServer: {
port: 3000,
hot: true,
contentBase: '../dist'
},
plugins: [new Webpack.HotModuleReplacementPlugin()]
}
The complete configuration is as follows
// webpack.config.js
const path = require('path');
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const Webpack = require('webpack')
module.exports = {
Mode: 'development', // development mode
entry: {
main: path.resolve(__dirname, '../src/main.js'),
},
output: {
filename: '[name]. [hash:8]. JS', // packaged file name
path: path. Resolve (_dirname, '.. / dist') // packaged directory
},
module: {
rules: [{
test: /.vue$/,
use: ['vue-loader']
}, {
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env']
]
}
}
}, {
test: /.css$/,
use: ['vue-style-loader', 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}]
}, {
test: /.less$/,
use: ['vue-style-loader', 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}, 'less-loader']
}]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js',
' @': path.resolve(__dirname, '../src')
},
extensions: ['*', '.js', '.json', '.vue']
},
devServer: {
port: 3000,
hot: true,
contentBase: '../dist'
},
plugins: [new CleanWebpackPlugin(), new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'),
filename: 'index.html'
}), new vueLoaderPlugin(), new Webpack.HotModuleReplacementPlugin()]
}
2.3 configuring packaging commands

The package file has been configured. Let’s test it
First, create a new main. In SRC js

Create a new app vue

Create a new public folder with an index html

implementnpm run dev
At this time, if the Vue development environment runs successfully in the browser, congratulations. You have successfully taken the first step
2.4 distinguish between development environment and production environment
In the actual application of the project, we need to distinguish between the development environment and the production environment config. JS and add two more files
-
webpack.dev.js
Development environment profile
The development environment mainly realizes the hot update, does not compress the code, and the complete sourcemap
-
webpack.prod.js
Production environment profile
The production environment mainly realizes the compression of code, extraction of CSS files, reasonable sourcemap and code segmentation. The following modules need to be installed: NPM I - D webpack merge copy webpack plugin optimize CSS assets webpack plugin uglifyjs webpack plugin
-
webpack-merge
Merge configuration -
copy-webpack-plugin
Copy static resources -
optimize-css-assets-webpack-plugin
Compress CSS -
uglifyjs-webpack-plugin
Compress JS
webpack mode
set upproduction
JS code will be automatically compressed when. In principle, there is no need to introduceuglifyjs-webpack-plugin
Repeat the work. howeveroptimize-css-assets-webpack-plugin
Compressing CSS will destroy the original JS compression at the same time, so we introduce it hereuglifyjs
Compress
2.4.1 webpack.config.js
const path = require('path')
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const devMode = process.argv.indexOf('--mode=production') === -1;
module.exports = {
entry: {
main: path.resolve(__dirname, '../src/main.js')
},
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'js/[name].[hash:8].js',
chunkFilename: 'js/[name].[hash:8].js'
},
module: {
rules: [{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
exclude: /node_modules/
}, {
test: /.vue$/,
use: ['cache-loader', 'thread-loader', {
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
}]
}, {
test: /.css$/,
use: [{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options: {
publicPath: "../dist/css/",
hmr: devMode
}
}, 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}]
}, {
test: /.less$/,
use: [{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options: {
publicPath: "../dist/css/",
hmr: devMode
}
}, 'css-loader', 'less-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}]
}, {
test: /.(jep?g|png|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
}, {
test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
}, {
test: /.(woff2?|eot|ttf|otf)(?.*)?$/i,
use: {
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
}]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js',
' @': path.resolve(__dirname, '../src')
},
extensions: ['*', '.js', '.json', '.vue']
},
plugins: [new CleanWebpackPlugin(), new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}), new vueLoaderPlugin(), new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
})]
}
2.4.2 webpack.dev.js
const Webpack = require('webpack')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
module.exports = WebpackMerge(webpackConfig, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
port: 3000,
hot: true,
contentBase: '../dist'
},
plugins: [new Webpack.HotModuleReplacementPlugin()]
})
2.4.3 webpack.prod.js
const path = require('path')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = WebpackMerge(webpackConfig, {
mode: 'production',
devtool: 'cheap-module-source-map',
plugins: [
new CopyWebpackPlugin([{
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist')
}]),
],
optimization: {
Minizer: [new uglifyjsplugin ({// compress JS
cache: true,
parallel: true,
sourceMap: true
}), new OptimizeCssAssetsPlugin({})],
splitChunks: {
chunks: 'all',
cacheGroups: {
libs: {
name: "chunk-libs",
test: /[/]node_modules[/]/,
priority: 10,
Chunks: "initial" // only package the third party that you depend on initially
}
}
}
}
})
2.5 optimize webpack configuration
You may be a little tired to see here, but in order to get a better offer and higher salary, you must continue to go deeper

Optimizing the configuration is of great practical significance to us, which is actually related to the size and speed of your packaged files.
The specific optimization can be divided into the following points:
2.5.1 optimize packing speed
Build speed refers to the speed of hot updates after each code modification and the speed of packaging files before release.
2.5.1.1 reasonably configure mode parameters and devtool parameters
mode
Settabledevelopment
production
Two parameters
If not set,webpack4
Willmode
The default value for is set toproduction``production
In modetree shaking
(remove useless code) anduglifyjs
(code compression confusion)
2.5.1.2 narrow the search scope of files (configure include exclude alias noparse extensions)
-
alias
: when we appear in the codeimport 'vue'
When, webpack will use the way of upward recursive search to searchnode_modules
Under the directory. In order to reduce the search scope, we can directly tell webpack which path to find. Alias(alias
)Configuration of. -
include exclude
Same configurationinclude exclude
Can also reducewebpack loader
Search conversion time. -
noParse
When we use it in our codeimport jq from 'jquery'
When,webpack
It will resolve JQ whether the library depends on other packages. But we have similarjquery
Such dependent libraries are generally considered not to refer to other packages (except for special ones, at your own discretion). increasenoParse
Properties, tellwebpack
There is no need to parse, so as to increase the packaging speed. -
extensions
webpack
Will be based onextensions
Find files with defined suffixes (file types with higher frequency are written first)

2.5.1.3 start multi process loader conversion with happypack
In the process of webpack construction, it actually takes time, and most of it is used in loader parsing and conversion and code compression. In daily development, we need to use loader to convert JS, CSS, pictures, fonts and other files, and the amount of file data converted is also very large. Due to the characteristics of JS single thread, these conversion operations cannot process files concurrently, but need to process files one by one. The basic principle of happypack is to decompose these tasks into multiple sub processes for parallel processing, and send the results to the main process after the sub process processing, so as to reduce the total construction time
npm i -D happypack

2.5.1.4 using webpack parallel uglify plugin to enhance code compression
The loader conversion has been optimized above, so another difficulty is to optimize the compression time of the code.
npm i -D webpack-parallel-uglify-plugin

2.5.1.5 pull out the third-party module
For static dependency files that do not change frequently in development projects. Similar to ours
elementUi、vue
Family bucket, etc. Because there are few changes, we don’t want these dependencies to be integrated into each build logic. The advantage of this is that every time I change the file of my local code,webpack
I only need to package the file code of my project itself without compiling the third-party library. In the future, as long as we don’t upgrade the third-party package, thenwebpack
These libraries will not be packaged, which can quickly improve the packaging speed.
Here we usewebpack
Built inDllPlugin DllReferencePlugin
Pull off
In andwebpack
New under the same level directory of the configuration filewebpack.dll.config.js
The code is as follows
// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
module. Exports = {// the array of modules you want to package
entry: {
vendor: ['vue', 'element-ui']
},
output: {
path: path. Resolve (_dirname, 'static / JS'), // location of file output after packaging
filename: '[name].dll.js',
library: '[name]_library'
//You need to communicate with webpack In dllplugin ` Name: '[name]_ Library ', ` keep consistent.
},
plugins: [
new webpack.DllPlugin({
path: path.resolve(__dirname, '[name]-manifest.json'),
name: '[name]_library',
context: __dirname
})
]
};
staypackage.json
The following commands are configured in
"dll": "webpack --config build/webpack.dll.config.js"
Next, in ourwebpack.config.js
Add the following code in
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./vendor-manifest.json')
}),
New copywebpackplugin ([// copy the generated file to the dist directory, so you don't have to manually CV {from: 'static', to: 'static'}]),
]
};
implement
npm run dll
You will find that the third place of the set we need is generated
Codedvendor.dll.js
We need to behtml
Manually import this filejs
file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
< title > old yuan < / Title >
<script src="static/js/vendor.dll.js"></script>
</head>
<body>
<div></div>
</body>
</html>
In this way, if we don’t update the third-party dependency package, we don’t have tonpm run dll
。 Direct executionnpm run dev npm run build
You will find that our packing speed has improved significantly. Because we have passeddllPlugin
Pulled out the third-party dependency package.
2.5.1.6 configure cache
Every time we execute the build, we will compile all the files repeatedly. Can such repeated work be cached? The answer is yes. At present, most of them are
loader
All providedcache
Configuration item. Like inbabel-loader
In, you can setcacheDirectory
To turn on the cache,babel-loader?cacheDirectory=true
Each compilation result will be written into the hard disk file (the default is in the project root directory)node_modules/.cache/babel-loader
Directory, of course, you can also customize)
<p>But ifloader
Does not support caching? We also have methods that we can passcache-loader
, what it does is very simplebabel-loader
opencache
After doing things, willloader
The compilation results of are written to the hard disk cache. If the file has not changed from the previous one, the cache will be used directly. The usage method is shown in the official demo. You can add this loader before some loaders with high performance overhead</p>
npm i -D cache-loader

2.5.2 optimize the volume of packaged files
We have optimized the speed of packaging, but the volume of packaged files is very large, resulting in slow page loading and waste of traffic. Let’s continue to optimize the volume of files
2.5.2.1 introduce webpack bundle analyzer to analyze packaged files
webpack-bundle-analyzer
The packaged content bundle is displayed as an intuitive tree view to facilitate interaction, so that we can know the content really introduced in the package we build
npm i -D webpack-bundle-analyzer

Next inpackage.json
Configure startup command in
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
Please install windowsnpm i -D cross-env
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
nextnpm run analyz
The browser will automatically open the web page of the file dependency graph
2.5.2.3 externals
According to the official documentation, if we want to reference a library, but we don’t want to
webpack
Packaging without affecting our ability toCMD、AMD
perhapswindow/global
Global and other methods can be used through configurationExternals
。 This function is mainly used when creating a library, but it can also be fully used in our project developmentExternals
In this way, we eliminate these static resources that do not need to be packaged from the construction logic and use them insteadCDN
To reference them.
<p>Sometimes we want us to passscript
Imported library, such as CDNjquery
, when we use it, we still use itrequire
But I don’t want to use itwebpack
Compile it into a file again. The case on the official website here is clear enough. If you are interested, you can click to understand it</p>
webpack
The cases on the official website are as follows
<script src="https://code.jquery.com/jquery-3.1.0.js" integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk=" crossorigin="anonymous"></script>module.exports = {
//...
externals: { jquery: 'jQuery' }};
import $ from 'jquery';
$('.my-element').animate(/* ... */);
2.5.2.3 Tree-shaking
Let me mention it alone
tree-shaking
, because there’s a pit here.tree-shaking
The main function of is to remove useless parts of the code. Currently inwebpack4
We setmode
byproduction
It has been turned on automatically by the time oftree-shaking
。 But for it to work, the generated code must be an ES6 module. Other types of modules such asCommonJS
And the like. If usedBabel
If so, there is a small problem becauseBabel
By default, any module type will be translated intoCommonJS
Type. It’s also easy to fix this problem.babelrc
File or inwebpack.config.js
Set in filemodules: false
Just fine
// .babelrc{ "presets": [ ["@babel/preset-env", { "modules": false } ] ]}
perhaps
// webpack.config.js
module: {
rules: [{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', {
modules: false
}]
}
},
exclude: /(node_modules)/
}]
}
After the baptism of the above two series, we have become a qualified webpack configuration engineer. However, the replaceability of screwing is still very high. Next, we will go deep into the principle of webpack

3. Handwritten webpack series
Having experienced the above two parts, we can skillfully use the relevant loaders and plugins to convert and parse our code. Next, we manually implement the loader and plugin to make it more fun in normal development.
3.1 handwritten webpack loader
loader
In essence, it is anode
modular. Equivalent to a juicer(loader)
The file code of the relevant type will be(code)
Give it. According to the rules we set, after a series of processing, we will return the processed fruit juice to us(code)
。
loader
Compilation principles
- Single principle: each
Loader
Do only one thing; - Chained call:
Webpack
Each is called in a sequential chainLoader
; - Principle of unification: follow
Webpack
The design rules and structure are formulated. The input and output are stringsLoader
Completely independent, plug and play;
In the daily development environment, in order to facilitate debugging, we often add manyconsole
Print. However, we do not want printed values to exist in the production environment. So here we implement one by ourselvesloader
Remove from codeconsole
Popularization of knowledge points
AST
。AST
Generally speaking, suppose we have a filea.js
, we’re righta.js
The 1000 lines inside are used for some operations, such as for allawait
increasetry catch
, and other operations, buta.js
The code inside is essentially a pile of strings. What should we do? That is, we can easily add, delete, modify and query objects (abstract syntax trees) with marked information. The marked object (abstract syntax tree) isAST
。 Here is a good ast article to get started with
npm i -D @babel/parser @babel/traverse @babel/generator @babel/types
-
@babel/parser
Parse the source code intoAST
-
@babel/traverse
yesAST
Nodes are traversed recursively to generate a code that is convenient for operation and conversionpath
object -
@babel/generator
takeAST
Decoding generationjs
code -
@babel/types
Through this module, the specificAST
Nodes can be added, deleted, modified and queried
newly builddrop-console.js
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const generator = require('@babel/generator').default
const t = require('@babel/types')
module.exports = function(source) {
const ast = parser.parse(source, {
sourceType: 'module'
}) traverse(ast, {
CallExpression(path) {
if (t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.object, {
name: "console"
})) {
path.remove()
}
}
}) const output = generator(ast, {}, source);
return output.code
}
How to use
const path = require('path')
module.exports = {
mode: 'development',
entry: path.resolve(__dirname, 'index.js'),
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /.js$/,
use: path.resolve(__dirname, 'drop-console.js')
}]
}
}
Actually
webpack4
Removal has been integrated inconsole
Function, inminimizer
Configurable console in
Attach how to write a loader on the official website
3.2 handwritten webpack plugin
stay
Webpack
Many events will be broadcast in the life cycle of operation,Plugin
You can monitor these events and pass them at the right timeWebpack
ProvidedAPI
Change the output. Generally speaking, a plate of delicious fried eggs with salt beans needs to go through the process of burning oil, frying, seasoning and finally loadingplugin
It is equivalent to monitoring each link and operating it. For example, you can write a message with less pepperplugin
, monitoringwebpack
Exposed life cycle events (seasoning), perform the operation of putting less pepper during seasoning. So it’s withloader
What is the difference between? We also mentioned aboveloader
A single principle,loader
There can only be one thing, for exampleless-loader
, can only be resolvedless
Documents,plugin
It is to perform a wide range of tasks for the whole process.
A basic plugin structure is as follows
class firstPlugin {
constructor(options) {
console.log('firstPlugin options', options)
}
apply(compiler) {
compiler.plugin('done', compilation => {
console.log('firstPlugin')))
}
}
module.exports = firstPlugin
What are compiler and compilation?
-
compiler
Object containsWebpack
All configuration information of the environment. This object is startingwebpack
It is established at one time, and all operable settings are configured, includingoptions
,loader
andplugin
。 When inwebpack
When a plug-in is applied in the environment, the plug-in will receive this messagecompiler
Object. You can use it to accesswebpack
Main environment. -
compilation
Object contains current module resources, compiled resources, changed files, etc. When runningwebpack
When developing environment middleware, whenever a file change is detected, a new one will be createdcompilation
To generate a new set of compilation resources.compilation
Object also provides many callbacks at critical times for plug-ins to choose when doing custom processing.
The difference between compiler and compilation is
- Compiler represents the whole life cycle of webpack from Startup to shutdown, while compilation only represents a new compilation process
- Compiler and compilation expose many hooks, which can be customized according to the actual demand scenario
Compiler hook document
Compilation hook document
Let’s manually develop a simple requirement to automatically generate information about the size of the packaged file before generating the packaged file
Create a newwebpack-firstPlugin.js
class firstPlugin {
constructor(options) {
this.options = options
}
apply(compiler) {
compiler.plugin('emit', (compilation, callback) => {
let str = ''
for (let filename in compilation.assets) {
STR + = ` file: ${filename} size ${compilation. Assets [filename] ['size '] ()} n`
}// through compilation Assets can obtain the static resource information after packaging, and can also be written to resources
compilation.assets['fileSize.md'] = {
source: function() {
return str
},
size: function() {
return str.length
}
}
callback()
})
}
}
module.exports = firstPlugin
How to use
const path = require('path')const firstPlugin = require('webpack-firstPlugin.js')module. Exports = {// omit other code plugins: [new firstplugin()]}
implementnpm run build
You can see indist
A folder containing information about the package file is generatedfileSize.md
Top two
loader
Andplugin
The case is just a guide, which is in the actual development needsloader
Andplugin
There are many aspects to consider. I suggest you try it yourself.
Attach how to write a plugin on the official website
3.3 handwritten webpack
Because the length is too long and the principle is more in-depth. In view of the principle of applying this article to practical development quickly, it is decided to start another new article to analyze it in detail
webpack
Principle and implementation of ademo
edition. After the format is calibrated, the article link will be posted below
4. webpack5. 0 Era
The update speed of both front-end framework and construction tools is far faster than we imagined. In previous yearsjquery
The era of a shuttle is gone forever. What we want to embrace is the constant updating and iterationvue、react、node、serverless、docker、k8s
….

Webpack, which is unwilling to lag behind, has also recently released webpack 5.0.0 beta 10. The author also mentioned beforewebpack5.0
It aims to reduce the complexity of configuration and make it easier to use(webpack4
And some performance improvements
- Use persistent cache to improve build performance;
- Use better algorithms and default values to improve long-term caching;
- Clean up the internal structure without introducing any destructive changes;
- Introduce some breaking changes to use V5 version as long as possible.
At present, the updates of maintainers are very frequent. I believe it won’t take longwebpack5.0
Will embrace the public. Interested students can install it firstbeta
Try the new version. But before that, I suggest you firstwebpack4
Master it, so that the road behind will be better and better.

Original author’s name: front end Xiaobu
Original source: segmentfault
(Collection)