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:

  • reactAsynchronous loading of routes
  • cssTo deal with
    • usemini-css-extract-pluginthecssfrombundlePackage of
    • useoptimize-css-assets-webpack-pluginThe compressioncsscode
    • useAutoprefixer postcss - loaderFor browser compatibilitycssCode prefixes
  • jsThe processing of
    • useuglifyjs-webpack-pluginCode compression
    • Unpacking,jsthebundlePackage extraction (unpacking)

preface

Pay attention toantdversion"Antd" : "^ 3.8.3",, advanced versionantdThe official icon library was also built into the Release package, so the packaging became very large, justiconThe icon library is several hundred kilobytes, as shown below. If you encounter this problem, lower itantdUse 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.jsMore than 200 K are packed separately, which is included in the picture belowantdThis 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 compressioncsscode

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 itoptimizationProperties of theminimizerWebpack 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 addsplitChunksPacking 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"forbundleThe split. If a component is loaded synchronously in the projectchunkNot large, can not be synchronously loaded component split, usechunks:async. Of course if the components in the project load asynchronouslychunkNot 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, unpackedchunkThe 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

If you often order take-out small friends, xiaobian to recommend a benefit. You can get a large takeaway red envelope for free every day, get it every day, no longer need to open a membership, save a breakfast every day.Click for detailsThe attached small program code is shown below: