Compressing the size of the packaged project and improving the packaging speed are very important links in the front-end performance optimization. I combine the practice summary in the work and sort out some conventional and effective performance optimization suggestions.

Background of the project

  • Technology stack: vue-cli3 + vue2 + webpack4
  • Main plug-ins: elementUI + echarts + axios + momentjs
  • Goal: Through a series of optimization schemes, compare the changes in packaging volume and speed before and after to verify the effectiveness of the scheme.

Project initial size and velocity

  • Initial volume: 2.25M

The vue project can add the –report command: “build”: “vue-cli-service build –report”, the dist directory will generate a report.html file after packaging, which is used to analyze the size of each file.

Or analyze by installing webpack-bundle-analyzer. The steps are as follows:

1) Install

1
$ npm install webpack-bundle-analyzer -D

2) Introduced in vue.config.js

1
2
3
4
5
6
7
8
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
}

3) After running npm run serve, you can see the analysis page by openning http://127.0.0.1:xxxx in the browser.

Start optimizing ✈︎

1. Externals extracts project dependencies

As can be seen from the above packaging analysis page, chunk-vendors.js the volume is 2.21M, and the largest files are some public dependency packages, so as long as these dependencies are extracted, the problem of chunk-vendors.js being too large can be solved.

You can use externals to extract these dependent packages, tell webpack that these dependencies are provided by the external environment, you can ignore them when packaging, and they will not be typed into chunk-vendors.js.

1) Configuration in vue.config.js:

1
2
3
4
5
6
7
8
9
module.exports = {
configureWebpack: {
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
echarts: 'echarts'
}
}

2) Use CDN to introduce dependencies in index.html

1
2
3
4
5
6
<body>
<script src="http://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>
<script src="http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js"></script>
<script src="http://lib.baomitu.com/axios/1.2.1/axios.min.js"></script>
<script src="http://lib.baomitu.com/echarts/5.3.2/echarts.min.js"></script>
</body>

Verify the validity of externals:

Repackage, the latest data is as follows:

  • Packing volume: 1.12M

  • Packing speed: 18879ms

After using externals, the package size is compressed by 50%, and the packaging speed is increased by 26%.

2. On-demand introduction of component library

Why not use externals to handle component libraries?

Disadvantages of externals: imported directly in html, loses the function of importing on demand, and can only import the complete js and css of the component library.

The principle of on-demand introduction of component libraries: only the specified components and corresponding styles are finally introduced.

Element-UI needs to be implemented with the help of the babel-plugin-componentplugin. The functions of the plugin are as follows:

To import the Button component as needed:

1
2
3
import { Button } from 'element-ui'

Vue.component(Button.name, Button)

Compiled file (automatically import button.css):

1
2
3
4
5
6
import _Button from "element-ui/lib/button";
import _Button2 from "element-ui/lib/theme-chalk/button.css";
// base.css is a public style
import "element-ui/lib/theme-chalk/base.css";

Vue.component(_Button.name, _Button);

Through this plugin, only the specified components and styles are finally introduced to reduce the size of the component library.

1) Install babel-plugin-component

1
$ npm install babel-plugin-component -D

2) Introduced in babel.config.js

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
presets: ['@vue/app'],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
]
]
};

Verify the validity of the on-demand import of the component library:

Repackage, the latest data is as follows:

  • Packing volume: 648KB
  • Packing speed: 15135ms

After the component library is introduced on demand, the package volume is reduced by 72%, and the packaging speed is increased by 40%.

At the same chunk-vendors.css time the volume has also been significantly reduced, from 206KB down to 82KB.

3. Reduce the volume of tripartite dependencies

Continue to analyze the packaged file, momentjs is used in the project, and it is found that there are many unused language packs after packaging.

Use moment-locales-webpack-plugin to remove useless language packs.

1) Install

1
npm install moment-locales-webpack-plugin -D

2) Introduced in vue.config.js

1
2
3
4
5
6
7
8
9
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');

module.exports = {
configureWebpack: {
plugins: [
new MomentLocalesPlugin({localesToKeep: ['zh-cn']})
]
}
}

Verify the validity of the plugin:

Repackage, the latest data is as follows:

  • Packing volume: 407KB

  • Packing speed: 10505ms

After reducing the size of the three-party dependencies, the package volume is reduced by 82%, and the packaging speed is increased by 59%.

4. HappyPack multi-thread packaging

Since webpack running on Node.js is a single-threaded model, we need webpack to be able to process multiple tasks at the same time and take advantage of the power of multi-core CPU computers.

HappyPack Multi-thread packaging can be realized. It decomposes tasks to multiple sub-processes for concurrent execution. After the sub-processes are processed, the results are sent to the main process to increase the packaging speed.

1) Install

1
npm install HappyPack -D

2) Introduced in vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const HappyPack = require('happypack');
const os = require('os');
// Open a thread pool to get the core CPU, happypack will use all threads to compile work
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

module.exports = {
configureWebpack: {
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool
})
]
}
}

Verify the validity of HappyPack:

Repackage, the latest data is as follows:

Packing speed: 8949ms

After using HappyPack, the packaging speed has been further increased by 65%.

Since the test project is small, the packaging time is not shortened too much. The actual measurement found that the more complex the project, the more obvious the improvement of the packaging speed of HappyPack.

5. Gzip compression

Online projects are generally combined with the construction tool webpack plug-in or server-side configuration nginx to achieve gzip compression for http transmission. The purpose is to minimize the size of the server-side response file and optimize the return speed.

html, js, css resources, after using gzip, the volume can usually be compressed by more than 70%.

Here is how to use webpack for gzip compression, using compression-webpack-plugin

1) install

1
npm install compression-webpack-plugin -D

2) Introduced in vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
configureWebpack: {
plugins: [
new CompressionPlugin({
test: /\.(js|css)(\?.*)?$/i, // The file that needs to be compressed is regular
threshold: 1024, // Enable compression when the file size is greater than this value
deleteOriginalAssets: false // Keep the original file after compression
})
]
}
}

Verify the validity of the plugin:

Repackage, 407KB the original volume is compressed to 108KB.

DllPlugin similar to the role of externals, they both pull out dependencies and save packaging time. The difference is that DllPlugin packages the dependencies separately, so that only the business code is built each time in the future, while externals is imported by converting dependencies into CDN.

When the company does not have good CDN resources or does not support CDN, you can consider using DllPlugin to replace externals.

The DllPlugin configuration process is roughly divided into three steps:

1) Create dll.config.js configuration file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { DllPlugin } from "webpack";

export default {
// Dependence that needs to be drawn
entry: {
vendor: ["vue", "vue-router", "axios", "echarts"]
},
mode: "production",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: "all",
name: "vendor",
test: /node_modules/
}
}
}
},
output: {
filename: "[name].dll.js", // Output path and file name
library: "[name]", // Global variable name: other modules will get the module from this variable
path: AbsPath("dist/static") // Output directory path
},
plugins: [
new DllPlugin({
name: "[name]", // Global variable name: reduce search range, combined with Output.library
path: AbsPath("dist/static/[name]-manifest.json") // Output directory path
})
]
};

2) package.json configuration script

1
"build:dll": "webpack --config ./dll.config.js",

3) Use to DllReferencePlugin reference the dll file generated by packaging to the required precompiled dependencies, and html-webpack-tags-plugin automatically insert the dll file when packaging.

vue.config.js is configured as follows

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { DllReferencePlugin } from "webpack";
import HtmlTagsPlugin from "html-webpack-tags-plugin";

export default {
configureWebpack: {
plugins: [
new DllReferencePlugin({
manifest: AbsPath("dist/static/vendor-manifest.json") // Manifest file path
}),
new HtmlTagsPlugin({
append: false, // Insert after generating resources
publicPath: "/", // Public path
tags: ["static/vendor.dll.js"] // Resource path
})
]
}
};

Run npm run build:dll to package and generate dependency files, and then just run npm run build to build business code.

Optimization summary

After a series of optimizations above, we can see:

  • The package size 2.25M is reduced 407KB to 82% compressed.

  • The packaging speed 25386ms is reduced to 8949ms, which is increased by 65%.

Although these methods are very conventional, they can effectively improve the performance of the project.

This article mainly introduces the optimization method of project packaging and construction. The next article will talk about performance optimization at the business code level, and there will be many interesting solutions.