preface
The React + WebPack4 Front-end construction project is divided into three chapters. The link is below. The purpose is to build a React backend management system from scratch
React + WebPack4 Build front-end projects (1) Build infrastructure projects
React + WebPack4 设 置 Front-End project
React + WebPack4 Build front-end project (3) Package optimization
Webpack configuration tutorial
React + webPack4.x build front-end project (4) Configure extraction and differentiation environment
React + WebPackage 4.x build front-end project (5) Configure multiple pages
React + WebPack4. x Multi-module package configuration
This is chapter 3, WebPack packaging optimization
React + WebPack4 build a front-end project (1). React + WebPack4 build a front-end project (2). React + WebPack4 build a front-end project (2). No more nonsense! Roll up your sleeves and start working!
Mainly from the following aspects:
react
Asynchronous loading of routescss
To deal with- use
mini-css-extract-plugin
thecss
frombundle
Package of - use
optimize-css-assets-webpack-plugin
The compressioncss
code - use
Autoprefixer postcss - loader
For browser compatibilitycss
Code prefixes
- use
js
The processing of- use
uglifyjs-webpack-plugin
Code compression - Unpacking,
js
thebundle
Package extraction (unpacking)
- use
preface
Pay attention toantd
version"Antd" : "^ 3.8.3",
, advanced versionantd
The official icon library was also built into the Release package, so the packaging became very large, justicon
The icon library is several hundred kilobytes, as shown below. If you encounter this problem, lower itantd
Use versions prior to 3.8.3
For the basic package optimization code, please click source 1.0.3. For those unfamiliar, download version 1.0.3 and run NPM run dev in the project root directory. At the same time, switch to the mock directory and execute NPM run dev. Open http://localhost:8081 and you can see the main functions of the effect as follows:
Resume management query, delete, modify:
User module query, modify:
Adding user modules:
First let’s look at the js package size before optimization and run NPM run build
Packaging at this time the file only three index. The HTML template file reset. Min. CSS from a static catalog copy in app. 1 a9adec2b6012290869f. Js is we use webpack packaged generated. This includes all the JS code, CSS code and image data resources in the project
We’ll start by installing two very useful WebPack plug-ins
npm install -D clean-webpack-plugin webpack-bundle-analyzer
Copy the code
- The clean-webpack-plugin removes the previous packing directory when packaging
- Webpack-bundle-analyzer starts a service at the end of a package that looks at the size and content of the package in the browser
Modify webpack.prod.config.js and add it under the plugins property
new CleanWebpackPlugin(),
new BundleAnalyzerPlugin(),
Copy the code
Start packing optimization
Asynchronous loading of routes
We know that asynchronous loading of files requires import(” XXX “), or require.ensure works with Webapck1.x 2.x. So import(” XXX “) is used.
It’s easy to load routes asynchronously in Vue by using ()=>import(” XXX “). React also loads routes asynchronously
Here we implement asynchronous loading of routes using the React-loadable plugin
For details, see React-loadable
1. Write a loadable. Js to implement asynchronous loading components
import Loadable from 'react-loadable';
const LoadableComponent = (component) => Loadable({
loader: component,
loading: ()=>null,
});
export default LoadableComponent;
Copy the code
2. Modify the loading mode of routing components
Import the container/index.js component directly
import BlogIndex from "@/blog"
import ResumeIndex from "@/resume"
import UserIndex from "@/user"
Copy the code
Instead, use the React-loadable plugin to wrap a layer of loaded components
import LoadableComponent from "@/loadable"
const BlogListPage = LoadableComponent(()=>import("./pages/list"))
const AddBlogPage = LoadableComponent(()=>import("./pages/add"))
Copy the code
And then modifyuser/index.js
.blog/index.js
, change the routing component to asynchronous loading, and then test the packaging as shown in the following figure
The asynchronously loaded routing components are packaged separately into separate files. I went from 922K to 487K.
You will find1.a64085be1c517b7e1ef2.js
More than 200 K are packed separately, which is included in the picture belowantd
This also proves the successful use of ANTD load on demand
CSS
Extract CSS from the bundle
Before Webpack 4.x we used extract-text-webpack-plugin to extract CSS.
In Webpack4. x, we need to use the mini-CSs-extract-plugin to extract CSS. The mini-CSs-extract-plugin uses the detailed document to modify the processing of CSS and less files in webpack.base.config.js. The following
{ test: /\.css$/, use:[ { loader:MiniCssExtractPlugin.loader, options:{ hmr: ReloadAll :true,}}, // {// loader: 'style-loader', // create <style></style> // MiniCssExtractPlugin conflicts, delete //}, {loader: 'css-loader', // convert CSS options: { importLoaders: 1 } } ] }, { test: /\.less$/, use: [ { loader:MiniCssExtractPlugin.loader, options:{ hmr: ReloadAll :true,}}, // {// loader: 'style-loader', //}, {loader: 'CSS - loader,}, {loader:' less - loader, / / compile less - > CSS}],},Copy the code
Because style – loader and MiniCssExtractPlugin. Loader have conflict, in the configuration of deleted when the style – the loader’s handling of the style, pack test results as follows
At this point the CSS styles have been successfully extracted from the bundle. Bundle reduced from 487K to 381K.
The compressioncss
code
We open any of the packaged CSS files and find that the CSS code is not compressed. So we need to compress the CSS. Optimize – CSS-assets-webpack-plugin install optimize- CSs-assets-webpack-plugin
npm install -D optimize-css-assets-webpack-plugin
Copy the code
Add the optimization ‘attribute to webpack.prod.config.js (code compression and unpacking for Webpack 4.x are handled here, unlike WebPack 3.x)
Minimizer: [new OptimizeCSSAssetsPlugin({cssProcessorOptions: {discardComments: {removeAll: true}})]}Copy the code
Test package:
Compare the size of the CSS file with the size of the CSS file. If the size of the CSS file has been reduced or the code of the CSS file has been compressed after opening the package, it means that the compression is successful.
But we find that js bundles are getting bigger. Why? Because we rewrote itoptimization
Properties of theminimizer
Webpack compression mode will be overwritten, here we need to define our own JS compression mode.
Js code compression
The uglifyjs-webpack-plugin plugin is used as webpack3.x. The uglifyjs-webpack-plugin plugin is used as webpack3
npm install -D uglifyjs-webpack-plugin
Copy the code
Then add the following code under the Minimizer property
New UglifyJsPlugin({parallel: true, // Use multiple processes to run in parallel to improve build speed sourceMap: false, uglifyOptions: { warnings: false, compress: { unused: true, drop_debugger: true, drop_console: true, }, output: { comments: False // uncomment}}})Copy the code
Retest the package comparison and the size of the previous JS file! This is the end of CSS!
Js processing
Code compression has been covered above and will not be repeated here
unpacking
In Webpack 3.x we used CommonsChunkPlugin built into WebPack to unpack. Webpack 4.x has changed a lot. To unpack WebPack4.x, you need to know splitChunks. SplitChunks works even if you don’t do any configuration at all, because WebPack has a default configuration, which is in line with the out-of-the-box nature of WebPack 4.
The default configuration of splitChunks is as follows
SplitChunks: {// async means only the chunks loaded asynchronously (dynamic load import())) // Initial means only the chunks loaded asynchronously (dynamic load import())) // all means both chunks: "async", minSize: // If the value is greater than 30K, the chunks will be unpacked by Webpack: // The import() file itself counts as one. // Only js, not CSS. // If there are two modules that meet the cacheGroup rule to split, However, the value of maxInitialRequests allows only one additional module to be partitioned, and larger modules can be partitioned off with maxAsyncRequests: 5, // The maximum number of on-demand (asynchronous) load requests // the maximum number of initial load requests, in order to limit the number of requests, not to split too many modules // entry file count one // if the module has asynchronous load does not count // only count js, // If two modules that meet the cacheGroup rule are being split, but the value of maxInitialRequests allows only one more module to be split, The larger modules would be split out maxInitialRequests: 3, automaticNameDelimiter: '~', // package separators name:true, cacheGroups: {// Default configuration vendors: {test: /[\\/]node_modules[\\/]/, priority: -10}, and vendors rules, then default: {minChunks: 2, // reference modules more than twice -> default priority: -20, reuseExistingChunk: true},},}Copy the code
Package tests, and do not addsplitChunks
Packing results consistent
Since the default is async, only modules loaded asynchronously are split. You can see that only app.js is the entry file (synchronous loading) without app.js split. This project loads asynchronously using react-loadable, and there are seven components in this project that load this way. However, from the packaging results, we can see that the asynchronously loaded components are split into 10 chunks. So why?
Using Webpack-bundle-Analyzer analysis, it can be seen that there are three chunks that are split by asynchronous components referencing components in ANTD.
Suppose we change chunks:async to chunks: “initial” for the package test:
The packing result is shown below
The packaging results are completely different because app.js is loaded synchronously, app.js is split, and app.js is found to be very small. Instead of split vendors to app. 4 fd9181b8f618e9fcac6. Js is bigger, this is because the chunk containing project entry documents contain all third-party libraries. And asynchronous loading of seven components or final packaging out 7 the chunk, the asynchronous loading of packaging components of each chunk contains in addition to the vendors to app. 4 fd9181b8f618e9fcac6. Js packaged in third-party libraries outside of the code and the component itself.
So you might think, what happens if I change “chunks:initial” to “all”? So let’s test that out
The packing result is shown below
We know that all is split not only from synchronous components, but also from asynchronous loads.
From the packaging result, it is a merge of initial and Async. Split asynchronous components as well as synchronous components.
So the conclusion comes, because this project contains asynchronous loading, asynchronous components and synchronous components need to be split at the same time, so this project useschunks: "all"
forbundle
The split. If a component is loaded synchronously in the projectchunk
Not large, can not be synchronously loaded component split, usechunks:async
. Of course if the components in the project load asynchronouslychunk
Not large, also can not be asynchronously loaded component split, usechunks:initial
. Of course, it can also be mixed, for the cache group set separately
And even with chunks: “all” we find that. The chunk of venders~app.js (the third party library for node_modules) is also larger. As the use of third-party plugins increases, this chunk will get bigger and bigger. So let’s break it up here. That is, the plugins used in node_modules are also split into different chunks
Our unpacking strategy is to reclassify our packages by size, usage, and update frequency to make the most of the browser cache.
Analyze the plugins for the project, which can be categorized by several steps
- UI Component Library (ANTD)
- Basic plugins (react, react-dom, react-router-dom, Mobx, Axios, etc.)
These are the update frequency is very low, high utility rate, mention large, so separate extraction. As long as these packages are not updated, unpackedchunk
The file name won’t change. It’s always cached in the browser
Next we’ll unpack according to this classification and add the rules for cacheGroups teabags
antdui: { priority: 2, test: / / \ \ / node_modules / \ \ / (antd) \ \ / /, / / (module) = > (/ antd /. The test (module. The context)),}, / / split base plug-ins, basic: {priority: 3, test: /[\\/]node_modules[\\/](moment|react|react-dom|react-router|react-router-dom|mobx|mobx-react|axios)[\\/]/, }Copy the code
Package test:
Antdui ~app.js, basic~app.js. Using webpack – bundle – analyzer analysis can see antd, precise moment | react | react – dom | react – the router | react – the router – dom | mobx | mobx – react | axios plug-ins are broken up.
I don’t know if you see any problems? 1. The packaged hash is the same, and the packaged hash is different every time. Solution, output add
chunkFilename: utils.assetsPath("js/[name].[chunkhash].js")
Copy the code
New MiniCssExtractPlugin(options) Initialization parameters
chunkFilename: utils.assetsPath('css/[id].[chunkhash].css'),
Copy the code
Antdui ~app.js, venders~app.js, Basic ~ app. Js just split antdui | moment | react | react – dom | react – the router | react – the router – dom | mobx | mobx – react | axios these plug-ins. There are other node_modules plugins that will be split into venders~app.js. This is where the maxInitialRequests attribute comes in.
MaxInitialRequests: The maximum number of initial load requests to limit the number of requests without splitting too many modules
- Entry file counts as one
- If the module has asynchronously loaded does not count
- Only js, not CSS
- RuntimeChunk split runtime does not count
- If two more modules that meet cacheGroup rules are being split, but the value of maxInitialRequests allows only one more module to be split, the larger module will be split
It can be found that three files, antdui~app.js and basic~app.js, will load app.js synchronously when app.js is loaded.
You need to change the value of maxInitialRequests to a larger value of 5
maxInitialRequests: 5,
Copy the code
The packaging test is shown below:
Venders ~app.js split from app.js
Github 1.0.4 Github source code
React + webPack4 + React – Router5 + React -loadable+mobx
React + WebPack4 Build front-end projects (1) Build infrastructure projects
React + WebPack4 设 置 Front-End project
React + WebPack4 Build front-end project (3) Package optimization
React + WebPack 4.x build front-end project (4) Configure extraction and differentiate environment