[Bao Zhen] my first webpack optimization, the first screen rendering from 9s to 1s

Hello, I'm Xiaobai. This article is based on vue2. It takes about 3 minutes to read the full text.
When it comes to webpack optimization, most people may be tired of it. It's just those moves. I've read many similar articles before, but I haven't really started it. Here's what I practiced with the company's projects. The loading speed of the first screen has been greatly improved (brushed). I hope it can help you.

No more nonsense. Let's see the comparison results first!

typeBefore optimizationAfter optimization
js file size24MB3MB
Homepage first screen display9s1s

That's an exaggeration. Eight times higher? I can imagine how slow it used to be. I have to wait for half a day. Manwang, a real man, has opened it up twice~

It can be seen that the loading speed of the first screen has been improved qualitatively before and after the optimization. We always wanted to optimize the loading time of the first screen of our project. It's OK to have a cache. If there is no cache, we have to wait for 7 or 8 seconds for the screen to be white. Especially when some customers open the system for the first time, it seems that 7 or 8 seconds have passed for a century, which is very embarrassing. What about the routine operations I did?

1. Close productionSourceMap and css sourceMap in the production environment

As we all know, SourceMap can locate a specific line of code when there are some errors on the page. SourceMap helps you establish this mapping relationship to facilitate code debugging. In the production environment, we don't need to turn on this function at all (who debugs the code in the production environment? It won't be you)

The configuration is as follows:

const isProduction = process.env.NODE_ENV === 'production' // Determine whether it is a production environment
module.exports = {
    productionSourceMap: !isProduction, //Close the SourceMap mapping file in the production environment
    css: {
        sourceMap: !isProduction, // css sourceMap configuration
        loaderOptions: {
            ...Other codes
     ...Other codes

At this time, when you pack npm run build, you will find that the speed is much faster and the volume is only a few megabytes in an instant!

2. Analyze big documents and find out the insider

Install NPM install webpack bundle Analyzer - D plug-in. After packaging, a local service will be produced to clearly show the inclusion relationship and size of the packaged file.

vue.config.js configuration:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
    configureWebpack: [
        plugins: [
            new BundleAnalyzerPlugin() // Analyze package size using default configuration

Automatically pop up a service to clearly show the file size of js after packaging:

It can be found from the figure:

  1. Element UI and ant design account for nearly a quarter of the size: 1.53MB.
  2. Excel JS is also a big thing: 1.3MB
  3. echarts.js file is also close to 1MB
  4. moment.js also has 700KB

After packing, the js file is 5MB in total, and these five brothers account for about 4M. If you don't analyze it, you'll be terrified~

Don't be vain! If you find the thorns, just pull them out one by one. Believe me, the process of pulling out is very cool.

One by one, pull out the thorn

1. Reference the necessary third-party js through cdn

It is found that element UI and ecarts must be used, packaging is time-consuming and page loading is very slow. It can be introduced directly through cdn, which is convenient and fast.

1. Element UI is the main framework used in our project, so it must be indispensable. But why does ant design exist in the project? It turns out that a page uses the progress bar component of antd, because the progress bar of element UI is not very good-looking. But I didn't expect this to lead the whole antd in.


  1. Abandon the antd component and find a similar vue plug-in or implement it yourself. (this method cannot be completed in a short time and does not want to move the previous code, so it is not considered temporarily)
  2. Partial loading using ant D. Loading only the desired progress bar components can reduce the file size (this method is simple and crude, that is, sacrificing some file size).

We use scheme 2 according to Official documents of antd Configure the introduction of some components.

Install NPM install Babel plugin import - D

1 main.js import required component Step

import { Steps } from 'ant-design-vue';
Vue.component(Steps.name, Steps);
Vue.component(Steps.Step.name, Steps.Step);

2 babel.config.js plus configuration:

module.exports = {
  presets: [
  //The following is the on-demand configuration++++
  plugins: [
        libraryName: "ant-design-vue",
        libraryDirectory: "es",
        style: true

At this time, the antd is much smaller.

2. Use cdn to load the third-party js.

There are many third-party js in our project, some of which will be large when packaged, and the loading speed is slow. We separate these js and use them directly in the script tags in html through cdn. On the one hand, we reduce the packaging volume and improve the loading speed.

Here is a free cdn: BootCDN . You can also use the paid cdn service purchased by yourself. We go to the website to search the js required by our project. For example: vue

Note that you must select the version corresponding to your project, otherwise all kinds of strange problems will occur

My project uses "vue": "^2.6.12", (package.json)

Step 1: configure Vue config. js, so that the webpack does not package these js, but adds them through the script tag.

const isProduction = process.env.NODE_ENV === 'production' // Determine whether it is a production environment
//The formal environment does not package public js
let externals = {}
//Files for storing CDNs
let cdn = {
    css: [
        'https://cdn. bootcdn. net/ajax/libs/element-ui/2.15.0/theme-chalk/index. Min.css' / / element UI CSS style sheet
    js: []
//Formal environment
if (isProduction) {
    externals = { //Exclude packaged js
        vue: 'Vue',
        'element-ui': 'ELEMENT',
        echarts: 'echarts',
    cdn.js = [
        'https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js', // vuejs
        'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/index.js', // element-ui js
module.exports = {
//... Other configurations
configureWebpack: {
        //Common public js are excluded. Instead of packaging, CDNs are added to the index,
        //... Other configurations
chainWebpack: config => {
        //... Other configurations  
        // Inject cdn variables (executed when packaging)
        config.plugin('html').tap(args => {
            args[0].cdn = cdn // Configure cdn to plug-in
            return args
//... Other configurations     

Step 2: add the code used by the defined cdn variable to the html template

<!DOCTYPE html>
<html lang="">

<meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!-- Import style -->
    <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
       <link rel="stylesheet" href="<%=css%>" >
    <% } %>

    <!-- introduce JS -->
    <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
       <script src="<%=js%>"></script>
    <% } %>
<body style="font-size:14px">
    <div id="app"></div>

CDNs can be found JS, I added vue, ecarts and ELEMENT UI. In the externals object, the name of the npm package is on the left and the global variables exposed in the code are on the right. Note that ELEMENT UI corresponds to ELEMENT.

There is no Ant Design Vue because we use the partial loading method above. If cdn is used to load all the code, it is a bit wasteful.

exclejs is not used because excel JS is not directly referenced in my business code, but an indirect dependency called table2excel. So even if I exclude it through the above method, I will find it and package it through the dependence of table2excel.

In this inevitable situation, how to optimize so that the loading speed is not affected?

The answer is lazy loading:

1.script Note it out of the label import Table2Excel from "table2excel.js";

2.Download method:
    //Use import() Then () mode
    import("table2excel.js").then((Table2Excel) => {
        new Table2Excel.default("#table").export('filename ') / / one more layer of default 

In this way, Table2Excel and excel JS will not be loaded when entering the system. They will be loaded when necessary. It will be slower for the first time, and it will not need to be loaded later, which will become faster.

3 moment.js optimization

We found that monentjs is used in the project to format the time, but the frequency of use is not high. You can implement a format method yourself or use a 6kb day js.

But we won't replace it here. We can make the moment smaller and delete language packs other than Chinese.

Step 1: Vue config. js

...Other configurations
 chainWebpack: config => {
        //Ignore all files under / moment/locale
     .use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
...Other configurations

Step 2: main js

import moment from 'moment'
//Manually import the required language pack
import 'moment/locale/zh-cn';
// Specifies the language to use

This time, let's see how big the moment is after packaging:

Only 174kb. However, it is still day JS fragrance~

After doing the above actions, the total size of our js file is 3.04MB, including 1.3MB lazy loading js. The remaining js of about 1.7MB basically won't cause a big jam on the page.

Is there room for improvement?

1. Compress the code into gzip through the compression webpack plugin plug-in. But! Server support required

webpack end Vue config. JS is configured as follows:

//Package compressed static file plug-in
const CompressionPlugin = require("compression-webpack-plugin")

//... Other configurations
module.exports = {
    //... Other configurations
    chainWebpack: config => {
        //Start js\css compression in production environment
        if (isProduction) {
            config.plugin('compressionPlugin').use(new CompressionPlugin({
                test: /\.(js)$/, // Match file name
                threshold: 10240, // Compress data over 10k
                minRatio: 0.8,
                deleteOriginalAssets: true // Delete source file
    //... Other configurations

The package size is from 3MB to 860KB. It feels like it's taking off~

The server-side configuration is not described in detail here. You can find the answer by turning on static compression in nginx.

Finally, paste the comparison of the first screen loading time without cache before and after optimization (chrome browser), which is absolutely true:

Data loaded on the first screen of the project website before optimization: 9.17s

Data loaded on the first screen of the optimized project website: 1.24s

These are all the posts of the bosses that I took the time to check after work. Although they are all some techniques that play the bar, it still takes some time and energy to implement them in my own project. Most of them ignore the original purpose of the process in order to complete the rapid iteration of functions, which is to let users have a good use experience.

Please don't forget to give me some likes, comments and collections.

Previous highlights:

1. What is an iterator? How does the Generator relate to it

2. Wechat applet UI components, charts and custom bar s all help you step on them

Keywords: Javascript Front-end Webpack

Added by wattee on Sun, 06 Mar 2022 14:45:09 +0200