start

This chapter is about packaging volume optimization, which is also the most important one. I spent a lot of time looking up information about how to optimize packaging volume before. There are some differences between different versions of Webpack, so I have made a lot of mistakes, so this chapter will be quite long.

Here I have written a rough layout of the page. It looks like this:

yarn add webpack-bundle-analyzer -D
Copy the code

Add a line to the plugins in webpack.config.prod.js. Note that the ports can be modified to avoid collisions:

new BundleAnalyzerPlugin({ analyzerPort: 8081 })
Copy the code

After the modification is complete, run yarn run build command, in the browser pop-up window, mine looks like this:

1. Modify mode

Let’s go to webpack.config.prod.js:

//mode:'development'
mode:'production' // Change to production environment
Copy the code

Webpack will automatically optimize the package size, such as compress code and so on:

2. Antd is loaded on demand

Execute from the console:

yarn add babel-plugin-import -D
Copy the code

Then go to webpack.config.common.js to configure:

            plugins:[
               	"@babel/plugin-transform-runtime"['import', {libraryName:'antd'.libraryDirectory: 'es'.style:true}]]Copy the code

In less configuration:

	{
         loader:'less-loader'.options: {javascriptEnabled: true}}Copy the code

Then we go to use the ANTD component and modify it to the following form:

// import Col from 'antd/lib/col';
// import Row from 'antd/lib/row';
// import "antd/dist/antd.css"; / / CSS is also removed
import {Col,Row} from 'antd'
Copy the code

Then execute the package command to change to 601KB:

3. Mini-css-extract-plugin Extracts CSS

We use mini-CSs-extract-plugin to separate CSS from JS. Execute from the console:

yarn add mini-css-extract-plugin -D
Copy the code

In webpack.config.prod.js:

// Introduce at the top
const MiniCssExtractPlugin=require('mini-css-extract-plugin');

// Add it to the plugins
new MiniCssExtractPlugin({/ / CSS
            filename:'css/main.css'
        }),
Copy the code

This way we can separate the CSS into a CSS folder. Then pack and see:

Optimize – CSS-assets-webpack-plugin is a plugin that compresses JS with the ability to optimize- CSS-assets-webpack-plugin with the ability to optimize- CSS-assets-webpack-plugin with the ability to optimize- CSS-assets-webpack-plugin

yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
Copy the code

We configure webpack.config.common.js:

// This configuration is the same as module and plugins
optimization:{
        minimizer: [new UglifyJsPlugin({Js / / compression
                cache:true.parallel:true.sourceMap:true
            }),
            new OptimizeCSSAssetsPlugin()/ / compress CSS]},Copy the code

Then we went to pack, and we found that the CSS had become smaller:

4. DllPlugin and DllReferencePlugin

As we can see from the previous packaging diagram, most of the package volume is occupied by the React family bucket and Babel. Now we will separate these into a JS file, because we will not change these things.

DllPLugin == webPack.config.dll. Js == in the root directory, and then configure it in the root directory.

const path=require('path')
const webpack =require('webpack')
const CleanWebpackPlugin  = require('clean-webpack-plugin');

// You only need to use yarn Run DLL once
module.exports={
    mode:'production'.entry: {// Put the React stuff and Babel here
        vendor:['react'.'react-dom'.'react-router-dom']},output: {filename:'dll/_dll_[name].js'.path:path.resolve(__dirname,'dist'),
        library:'_dll_[name]'
    },
    plugins: [new webpack.DllPlugin({
            name:'_dll_[name]'.path:path.resolve(__dirname,'dist/dll'.'mainfist.json')}),new CleanWebpackPlugin(['./dist/dll']),// Delete files in the DLL directory]}Copy the code

==webpack.config.common.js==

// Add it under plugins
new webpack.DllReferencePlugin({
     manifest: path.resolve(__dirname, 'dist/dll'.'mainfist.json')}),Copy the code

Then go to package.json.

// Add a new one under scripts
"dll": "webpack --config webpack.config.dll.js"
Copy the code

Execute from the console:

yarn run dll
Copy the code

// Add it at the end of the body
<script src="dll/_dll_vendor.js"></script>
Copy the code

Then run yarn Run build:

5. @babel/polyfill

As you can see in the previous diagram, core-js takes up a lot of volume, and this is the library that Babel/Polyfill uses. I offer two approaches here.

1.@baebl/ Polyfill is loaded on demand

We can use the useBuiltIns property, which is new to Babel7, and we need to configure it like this:

presets:[
    [
        '@babel/preset-env',
        {
            "targets": {
                "browsers": [
                    "ie >=9"."last 2 version"."5%" >."not dead"]},"useBuiltIns":"usage"}].'@babel/preset-react'].Copy the code

When configured this way, we can add the index.js top

//import '@babel/polyfill' // drop this line
Copy the code

Then we package and execute YARN Run Build:

2. To extract @ baebl/polyfill

The second way, we can extract @babel/polyfill directly, just like the React family bucket. We go to ==webpack.config.dll. Js == to configure:

/ / add @ Babel/polyfill
vendor:['react'.'react-dom'.'react-router-dom'.'@babel/polyfill']
Copy the code

Then go to the top of index.js and add:

import '@babel/polyfill'
Copy the code

Then we run the YARN Run DLL, and we can see that vendor’s package is larger:

6. React router load dynamically

We used to load all the components on the page, so that the components we didn’t click on would load, which would lead to waste. It is much better to use dynamic loading to load components that are clicked on.

We execute on the console:

yarn add react-loadable babel-plugin-syntax-dynamic-import -D
Copy the code

==webpack.config.common.js==

plugins:[
    "@babel/plugin-transform-runtime".'babel-plugin-syntax-dynamic-import'.// Add this line
    ['import', {libraryName:'antd'.libraryDirectory: 'es'.style:true}]]Copy the code

Then we go to the place where routing is used:

import Loadable from 'react-loadable';// Note the addition of this line
// import A from '.. /pages/A/A'
// import B from '.. /pages/B/B'

// Write it like this
const A = Loadable({
    loader: (a)= > import('.. /pages/A/A'),
    loading:(a)= > {
        return <div>Loading...</div>}});const B = Loadable({
    loader: (a)= > import('.. /pages/B/B'),
    loading:(a)= > {
        return <div>Loading...</div>}});Copy the code

Then execute the package command and view:

We can see the effect:

This is what the page looks like when it first loads

Index. js volume interpretation

Here’s a bit more about the packaged graph. I actually wrote very little code under SRC, but there is an index.js in the packaged graph that is nearly 90KB in size. Why is this? We can try it. Here’s the code for most antD components I use on my home page:

<div>
    <Header/>
    <Row>
        <Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>
            <Aside/>
        </Col>
        <Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>
            <div className="content">
                {this.props.children}
            </div>
        </Col>
    </Row>
</div>
Copy the code

We comment out all antD components we use, leaving only the Header:

//import {Col,Row} from 'antd' <div> <Header/> {/*<Row>*/} {/*<Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>*/} {/*<Aside/>*/} {/*</Col>*/} {/*<Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>*/} {/*<div className="content">*/}  {/*{this.props.children}*/} {/*</div>*/} {/*</Col>*/} {/*</Row>*/} </div>Copy the code

Then we go to pack:

7. splitChunks

Then we separate third-party libraries like ANTD from the main package.

We configure it in optimization == webPack.config.common.js ==, at the same level as we did before we wrote js and CSS compression ==minimizer== :

splitChunks:{
    cacheGroups: {vendors: {//node_modules
            test:/[\\/]node_modules[\\/]/.chunks: "initial".name:'vendors'.//chunks name
            priority:10./ / priority
            enforce:true}}}Copy the code

Then execute the package command:

Although ANTD’s components are large, they are packaged only once, and can be reduced by more than a third with gZIP configured on the server, which is acceptable.

At the end

We ended up optimizing the main package size from 2.75M to around 5KB, but we were actually breaking up a large package into smaller packages and extracting common code.

In fact, there is another optimization method using externals, and then using CDN to introduce, but I have already used DllPlugin, do not use that method, you can use the two methods reasonably.

This chapter is too much stuff, and a little bit messy, but it should be quite detailed, but I think there is more to webPack volume optimization than that, if you have other ways to optimize, let me know, thanks.

Github address: github.com/xw-Zhou/web…

(PS: If there are any mistakes in this article, please point them out in the comments, thanks)