Demo address
This article project code location: source code address
Why do you need a build tool
What does WebPack do?
- Start the local service at development time
- Solve the dependency problem of JS and CSS. (Often in the past, CSS didn’t work or a JS variable couldn’t be found because of order issues introduced)
- Compile ES6, VUE/React, and JSX syntax into browser-aware code
- Merge, compress and optimize the volume after packaging
- CSS prefix complement/preprocessor
- Use ESLint to validate code
- Unit testing
Webpack configuration component
module.exports = {
entry: ' '.// Specify the entry file
output: ' '.// Specify the output directory and output file name
mode: ' './ / environment
module: {
rules: [ / / a loader configuration
{test: ' '.use: ' '}},plugins: [ // Plug-in configuration
new xxxPlugin()
]
}
Copy the code
Basic common Loader
Why is loader needed?
Webpack native supports only JS and JSON module types, so loader needs to convert files of other types into valid modules and add them to the dependency graph.
Loader itself is a function that takes the source file as an argument and returns the result of the conversion
function | loader | instructions |
---|---|---|
Parsing es6 | babel-loader | Use with. Babelrc |
Parsing the vue | vue-loader | |
Parsing the CSS | css-loader | Use to load the.css file and convert it to a CommonJS object |
style-loader | Pass styles through<style> The label is inserted into the head |
|
Parsing the less | less-loader | Convert less to CSS |
Parse images and fonts | file-loader | For processing files (images, fonts) |
url-loader | It can also handle images and fonts, similar to file-loader, but it can also set smaller resources to automatically transfer to base64. Options: {limit: XXX} |
The basic common Plugin
Plug-ins are used for bundle file optimization, resource management, and environment variable injection, and are used throughout the build process
- Clean-webpack-plugin: Automatically clean up the dist directory before packaging
- Html-webpack-plugin: Automatically generates HTML and inserts packed JS into it
- Mini-css-extract-plugin: Extract CSS into a separate file, with
style-loader
The functions are mutually exclusive and cannot be used at the same time - About code compression:
The built-in Terser-webpack-plugin is enabled by default. Webpack automatically compresses THE compression of JS code and CSS files: Optimize – CSS-assets-webpack-plugin with CSSNano
plugins: [
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')})]Copy the code
HTML file compression: modify html-webpack-plugin, set compression parameters
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html'.chunks: ['main'.'other'].// Which chunks to include
inject: true.// Automatically inject chunks into HTML
minify: { // Compress correlation
html5: true.collapseWhitespace: true.// Compress whitespace characters
preserveLineBreaks: false.minifyCSS: true.minifyJS: true.removeComments: true}})]Copy the code
Webpack performance optimization
Development environment performance optimization
Module hot replacement
By default, dev-server will be rebuilt to refresh the browser page whenever a file changes.
Module hot replacement: only repackage the changed modules, partially refresh, preserving the data state (rather than repackage all modules and refresh the page) to speed up the build and make development easier
Through devServer. Hot, its internal dependence webpack. HotModuleReplacementPlugin implementation, HotModuleReplacementPlugin in hot: true automatically was introduced, can not write
- Style files: You can use the HMR function directly because
style-loader
Internally implemented - Js file: The HMR function cannot be used by default. You need to modify the JS code to add the code supporting the HMR function
if(module.hot){ // If the HMR function is enabled
// Listen for changes in the xxx.js file. Once changes occur, other modules do not repackage and execute callback functions
module.hot.accept('./xxx.js'.function(){
fn()
})
}
Copy the code
- HTML files: There are no hot replacements, nor hot updates, which can be opened by adding the HTML file path to the entry file, but are usually not necessary
Use the source – the map
Since webpacked code is a large JS file after various loaders and plugins have been converted, it cannot be debugged during development. Source-map is a technique that provides a source-to-build-code map that can be used to locate source code when an error is reported. Enabling mode:
module.exports = {
devtool: 'source-map'
}
Copy the code
Options: [the inline – | hidden – | eval -] [nosources -] [being – [module -]] source – the map
- The source – the map: produce
.map
File that provides accurate information about the error code and the source code’s error location - Inline: inline, will
.map
As aDataURI
Embedded, not generated separately.map
File, build faster - Eval: inline, used
eval
Wrap the module code, specifying the corresponding file of the module - Cheap: Accurate to rows only, not columns
- The module: includes
loader
的sourcemap
Recommended combination:
- Development environment: fast and debug friendly
Eval-source-map (eval is the fastest and source-map debugging is the friendliest)
- Production environment: Inlining makes code larger, so production environment does not use inlining
1. Consider whether to hide source code? Nosource-source-map — hidden all hidden hidden-source-map — only hidden source code, will prompt error message 2 after build code. Consider whether to be debug-friendly? source-map
Production environment performance optimization
Use file fingerprints for version control and caching
When you set a strong HTTP cache, for example, valid for one day, if you don’t use hash, when the file changes, the file name stays the same, so the client will still use the old cache. If a hash is used, the file name is changed and a new resource is requested, while the unchanged file continues to be cached
- Hash: build
hash
, which changes with each build and is not recommended - Chunkhash:
webpack
packagedchunk
Relevant, differententry
It’s going to be differentchunkhash
值 - Contenthash: Defines hash based on the file content
contenthash
Unchanged, recommended incss
Use on file
Js file fingerprint setting:
// Set filename for output using [chunkhash]
module.exports = {
output: {
filename: '[name][chunkhash:8].js'.path:__dirname+'/dist'}}Copy the code
Fingerprint Settings for CSS files:
Use the MiniCssExtractPlugin to pull CSS out of JS, then use the [contenthash]
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css'})]Copy the code
Add: The difference between Module, chunk, and bundle
- A file in the source code is a module
- Chunk: A chunk of an entry file that depends on one
chunk
Can be interpreted as oneentry
Corresponds to achunk
- Bundle: A packaged resource, usually one
chunk
That corresponds to onebundle
But it is also possible to unpack a large one through some plug-inschunk
Split into multiplebundle
, such asMiniCssExtractPlugin
tree shaking
Tree shaking: A module may have multiple methods, and as long as one of them is used, the whole file will be sent to the bundle. Tree shaking is simply pouring used methods into the bundle, while unused methods are erased during the Uglify phase.
Use: Webpack by default, set module: false in.babelrc
Tree Shaking is enabled by default in Production Mode. It must be es6 syntax, CJS is not supported
The tree shaking principle
DCE: code that is never used, such as introducing a method but not calling it or if(false){XXX}
Using the features of ES6 module:
- Can only appear as a statement at the top level of a module
import
Can only be string constantsimport binding
isimmutable
the
Static analysis files before packaging, useless code is removed during the UGlify phase
code split
Unpacking a large bundle can be configured in cacheGroups
- splitChunks
// splitChunks default configuration
optimization: {
splitChunks: {
chunks: 'all'.// Both synchronous and asynchronous import
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/.// Matches files in the node_modules directory
priority: -10 // Priority configuration item
},
default: {
minChunks: 2.// At least 2 times
priority: -20.// Priority configuration item
reuseExistingChunk: true}}}}Copy the code
In default Settings
- will
node_mudules
The modules in the folder are packed into a folder calledvendors
的bundle
中 - All modules that reference more than twice are assigned to
default bundle
Medium, yespriority
To set the priority.
DLL
Separate third-party libraries and business base packages into a single file, only for the first time, or when you need to update dependencies, and then you can only type your own source code each time, speeding up the build.
Method: The DLLPlugin is used for subcontracting, and the DllReferencePlugin references manifest.json
Subcontracting requires separate configuration files:
// webpack.dll.js
module.exports={
entry: {
lib: [
'lodash'.'jquery']},output: {
filename: '[name]_[chunkhash].dll.js'.path: path.join(__dirname, 'build/lib'),
library: '[name]' // Global variable name exposed after packaging
},
plugins: [
new webpack.DllPlugin({
name: '[name]'.// In manifest.json, the name must be the same as ouput.library
path: path.join(__dirname, 'build/lib/manifest.json'),}})]Copy the code
Add commands to package.json to package DLLS separately:
"scripts": {
"dll": "webpack --config webpack.dll.js"
},
Copy the code
Manifest.json is referenced using the DllReferencePlugin to tell WebPack what dynamic link libraries are used without packing them
// webpack.prod.js
new webpack.DllReferencePlugin({
manifest: require('./build/lib/manifest.json')}),Copy the code
Using addAssetHtmlWebpackPlugin put the DLL resources in HTML
// webpack.prod.js
new addAssetHtmlWebpackPlugin([
{
filepath: path.resolve(__dirname, './build/lib/*.dll.js'),
outputPath: 'static'.// The output path after copying *.dll. Js, relative to the HTML file
publicPath: 'static'}])Copy the code
Demo address: Webpack practice – DLL -plugin branch
Comparison before and after use:
usedllplugin
Before, the base library hitmain.js
And accounted for160kb
: After use:main.js
only1.23 KB
Difference between splitChunks and DLLS
splitChunks
Is unpacking at build time,dll
Build the base library in advance, so when you pack it, you don’t need to build the base librarydll
比splitChunks
A bit fasterdll
You need to configure one morewebpack.dll.config.js
And oncedll
The dependencies in the update, have to go twice to pack, thansplitChunks
Some trouble- It is recommended to use
splitChunks
To extract commonality between pagesjs
File.DllPlugin
Used for the separation of base packages (framework packages, business packages).
Multi-process packaging
Use thread-Loader to enable multi-process packaging and speed up packaging! Note: it takes around 600ms to start a process, interprocess communication is also expensive, and it is not worth the cost to start multiple processes on a small project, so use multiple processes only when the project is large and the packaging takes a long time.
module: {
rules: [{test: /.js$/,
use: [
{
loader: 'thread-loader'.options: {
workers: 2 // Start two processes}}, {loader: 'babel-loader'.options: {
presets: ['@babel/preset-env'].cacheDirectory: true}}]},]}Copy the code
Multi-page packaging common configuration
Multi-page packaging requires multiple entry files, and multiple HTMLWebpackplugins generate multiple HTML. It is impossible to write many entries and HtmlWebpackPlugin by hand
Solution: Dynamically get entry and set the number of HTML-webpack-plugin
// Core method
const setMPA = () = > {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));
entryFiles.forEach(entryFile= > {
const match = entryFile.match(/src\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
template: path.join(__dirname, `src/${pageName}/index.html`),
filename: `${pageName}.html`.chunks: [pageName], // Which chunks to include
inject: true.// Automatically inject chunks into HTML
minify: {
html5: true.collapseWhitespace: true.preserveLineBreaks: false.minifyCSS: true.minifyJS: true.removeComments: false}}})))return {
entry,
htmlWebpackPlugins
}
}
Copy the code
See the WebPack practice-MPA-Build branch for additional configurations