Improve the Loading Speed of the Home Page

If the front-end and back-end separation projects are made in the form of SPA (single page), they will inevitably face a problem of loading above the fold. Because the home page file is relatively large by default, such as more than 1 MB, which brings the problem of slow loading of the home page. Therefore, we need to optimize the loading speed of the home page.

Generally speaking, there are several ways of thinking:

1. UI components are loaded on demand

2. Route lazy loading

3. Components are packaged repeatedly

4. gzip

Among these loading methods, UI component on-demand loading and gzip are two commonly used schemes for improving the loading speed. The other two optimization methods should be combined with specific projects to see if relevant conditions are met. Therefore, this article will talk about UI components lazy loading and gzip.

1. ElementUI Loads on Demand

Problem recurrence

Without any optimization, we generally introduce ElementUI in main.js as follows.

import ElementUI from'element-ui';
import'element-ui/lib/theme-chalk/index.css';
vue.use(ElementUI,{size:'small'});

Needless to say, CSS must be introduced. However, according to the above introduction method, all other components except CSS have been introduced into the project. There are nearly 60 components in the latest version of ElementUI, but there may not be so many components used in our project, and these are ultimately useless. The above components will cause a waste of resources.

Without any optimization, we use the following command to generate report.html for the project to help us analyze the package content.

vue-cli-service build --report

The log of the command execution is as follows (the key part is intercepted).

warning

entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  app (1.17 MiB)
      css/chunk-vendors.9948ce82.css
      js/chunk-vendors.11959501.js
      css/app.4e8a7623.css
      js/app.ce6f575c.js

  File                                    Size              Gzipped

  dist/js/chunk-vendors.11959501.js       840.77 KiB        227.94 KiB
  dist/js/app.ce6f575c.js                 99.08 KiB         30.95 KiB
  dist/js/chunk-64435448.d0a0516e.js      26.52 KiB         5.87 KiB
  dist/js/chunk-0c17a57a.d553638c.js      23.79 KiB         5.49 KiB
  dist/js/chunk-a3fdbb9c.ddc4c008.js      13.30 KiB         3.45 KiB
  dist/js/chunk-54277bc7.2882c4cd.js      10.40 KiB         2.95 KiB
  dist/js/chunk-4e552d82.c64f4d10.js      1.78 KiB          0.63 KiB
  dist/js/chunk-18458ebc.32fb57c9.js      1.54 KiB          0.62 KiB
  dist/js/chunk-2d0d03c8.3a093d55.js      0.52 KiB          0.36 KiB
  dist/js/chunk-2d237c54.0b312051.js      0.43 KiB          0.33 KiB
  dist/css/chunk-vendors.9948ce82.css     258.19 KiB        41.36 KiB
  dist/css/app.4e8a7623.css               3.46 KiB          1.09 KiB
  dist/css/chunk-0c17a57a.9fe19f94.css    0.86 KiB          0.35 KiB
  dist/css/chunk-64435448.3755e146.css    0.30 KiB          0.15 KiB

From this log, we can see that the size of the project entry file exceeds the official recommendation of 244KB, which may affect the performance of the web page. At this point, we copy the packaged files to the resources/static directory of Spring Boot and start the backend project.

From the browser's loading situation, the largest chunk-vendors.11959501.js file took 369ms to load. At the same time, there is also a file called report.html in the front-end dist directory at this time, which is the generated packaged report. We open this page in the browser. This HTML page, through the visual page, shows us who made the js file bigger. According to the test, we found that the chunk-vendors.11959501.js file is relatively large because the file element-ui.commons.js in it is relatively large.

In fact, each module can find ways to optimize, but the gun is the best. Because element-ui.commons.js is too big, we will optimize it first.

How to Solve It

The optimization method is actually very simple, and the ElementUI official website also gives a method. First, we load and install babel-plugin-component.

npm install babel-plugin-component -D

Then modify the babel.config.js file. The sample code is as follows.

module.exports = {
    presets: [
        '@vue/app',
        ['@babel/preset-env', {
            modules: false
        }]
    ],
    plugins: [
        [
            "component",
            {
                "libraryName": "element-ui",
                "styleLibraryName": "theme-chalk"
            }
        ]
    ]
}

After the configuration is complete, modify the main.js file and introduce the components we need to use one by one.

import {
    Button,
    Input,
    Table,
    TableColumn,
    Dialog,
    Card,
    Container,
    Icon,
    Select,
    Form,
    Tag,
    Tree,
    Pagination,
    Badge,
    Loading,
    Message,
    MessageBox,
    Menu,
    Tabs,
    TabPane,
    Breadcrumb,
    BreadcrumbItem,
    Dropdown,
    Steps,
    Tooltip,
    Popover,
    Collapse,
    FormItem,
    Checkbox,
    Header,
    DropdownMenu,
    DropdownItem,
    Aside,
    Main,
    MenuItem,
    Submenu,
    Option,
    Col,
    Row,
    Upload,
    Radio,
    DatePicker,
    RadioGroup,
    CollapseItem,
    Switch
} from'element-ui';
import'element-ui/lib/theme-chalk/index.css';
Vue.prototype.$ELEMENT = {size: 'small', zIndex: 3000};
Vue.use(Switch);
Vue.use(CollapseItem);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(DatePicker);
Vue.use(Upload);
Vue.use(Row);
Vue.use(Col);
Vue.use(Option);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(Header);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Aside);
Vue.use(Main);
Vue.use(Checkbox);
Vue.use(FormItem);
Vue.use(Collapse);
Vue.use(Popover);
Vue.use(Menu);
Vue.use(Tabs);
Vue.use(TabPane);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Dropdown);
Vue.use(Steps);
Vue.use(Tooltip);
Vue.use(Tree);
Vue.use(Pagination);
Vue.use(Badge);
Vue.use(Loading);
Vue.use(Button);
Vue.use(Input);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(Dialog);
Vue.use(Card);
Vue.use(Container);
Vue.use(Icon);
Vue.use(Select);
Vue.use(Form);
Vue.use(Tag);
Vue.prototype.$alert = MessageBox.alert
Vue.prototype.$confirm = MessageBox.confirm

The code here is not difficult, there are two points to pay attention to.

The introduction method of MessageBox is different from other components, so you need to pay attention.

The way to uniformly customize size and zIndex for components has changed.

After the configuration is complete, we execute vue-cli-service build --report again to view the packaging results.

entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  app (1.03 MiB)
      css/chunk-vendors.26d2c5b9.css
      js/chunk-vendors.e2a11728.js
      css/app.4e8a7623.css
      js/app.c5dd78e5.js

  File                                    Size              Gzipped

  dist/js/chunk-vendors.e2a11728.js       683.05 KiB        177.91 KiB
  dist/js/app.c5dd78e5.js                 101.70 KiB        31.90 KiB
  dist/js/chunk-64435448.d0a0516e.js      26.52 KiB         5.87 KiB
  dist/js/chunk-0c17a57a.d553638c.js      23.79 KiB         5.49 KiB
  dist/js/chunk-33b8cd94.7bbae1a0.js      13.30 KiB         3.46 KiB
  dist/js/chunk-df7e035a.414b548f.js      10.40 KiB         2.95 KiB
  dist/js/chunk-4e552d82.c64f4d10.js      1.78 KiB          0.63 KiB
  dist/js/chunk-18458ebc.32fb57c9.js      1.54 KiB          0.62 KiB
  dist/js/chunk-2d0d03c8.3a093d55.js      0.52 KiB          0.36 KiB
  dist/js/chunk-2d237c54.0b312051.js      0.43 KiB          0.33 KiB
  dist/css/chunk-vendors.26d2c5b9.css     262.71 KiB        42.11 KiB
  dist/css/app.4e8a7623.css               3.46 KiB          1.09 KiB
  dist/css/chunk-0c17a57a.9fe19f94.css    0.86 KiB          0.35 KiB
  dist/css/chunk-64435448.3755e146.css    0.30 KiB          0.15 KiB

Compared with the previous log, it is found that after introducing ElementUI on demand, it is still effective, but the effect is not obvious. At this time, let's open the report.html page again, and we can see that the huge element-ui.commons.js is gone, replaced by a bunch of little guys. The associated file size has also been reduced by around 150kb. This has limited effect.

2. Compress with gzip

So, on the basis of the previous code, let's continue to compress through gzip. To compress by gzip, we have two ideas. These two ideas are related to the two different deployment methods of front-end and back-end separation.

The front-end is compiled and packaged, copied to the back-end, and the back-end project can be deployed directly.

The front-end and back-end are deployed separately, and the front-end is deployed through Nginx (recommended).

Server configuration

If you use the first method, the front-end can still be the compiled file without doing extra work. We add the following configuration to the backend application.yml to enable gzip compression.

server:
  compression:
    enabled:true

After the configuration is complete, restart the backend project. Visit the project homepage and you can see that the files are basically compressed. Click on a request and you can see that gzip has taken effect.

Front-end configuration

There are two ideas for configuring front-end gzip compression in Nginx.

Nginx compresses dynamically. Static files are still ordinary files. When the request comes, it is compressed again, and then returned to the front end.

Nginx statically compresses the file into .gz format in advance. When the request comes, just return it directly.

Nginx dynamic compression

Dynamically compressing Vue still uses ordinary packaged and compiled files, and copies the front-end compiled and packaged files to the HTML directory of Nginx. After ensuring that Nginx is running successfully, configure Nginx next.

gzip  on;
gzip_min_length 2k;
gzip_disable msie6;
gzip_types text/css application/javascript text/javascript image/jpeg image/png image/gif;

After the configuration is complete, restart Nginx. After the startup is successful, go to the front-end page again, and you can see the compression effect.

./nginx -s reload

Nginx static compression

The above dynamic compression has a problem, that is, it needs to be compressed every time a request responds. In fact, they are all the same files, and it is a bit of a waste of resources to always compress.

We can compress the file in advance and save it on the server. It will be much more convenient to return it directly when you need it. This requires us to first install the compression plugin on the front end.

npm install compression-webpack-plugin -D

After the installation is successful, configure it in vue.config.js.

const CompressionPlugin = require("compression-webpack-plugin")
module.exports = {
    devServer: {
        host: 'localhost',
        port: 8080,
        proxy: proxyObj
    },
    configureWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
            return {
                plugins: [
                    new CompressionPlugin({
                        test: /\.js$|\.html$|\.css/,
                        threshold: 1024,
                        deleteOriginalAssets: false
                    })
                ]
            }
        }
    }
}

The threshold indicates that files larger than 1kb will be compressed.

deleteOriginalAssets indicates whether to delete the original file after compression.

After the configuration is complete, execute the packaging command vue-cli-service build again. After the packaging is completed this time, we can see the .gz file in the js directory.

Next, upload the file to the Nginx server, and then recompile and package Nginx. To make Nginx return the compressed files, you need to use the http_gzip_static_module module in Nginx. This module can send pre-compressed files with a .gz file extension, so we need to recompile and package Nginx.

./configure --with-http_gzip_static_module
make
make install

Then enable gzip_static in the Nginx configuration file.

gzip_static  on;

Please note that gzip_types will be invalid when gzip_static is enabled, so there is no need to configure this property. After the configuration is complete, restart Nginx and access it again. Looking at the browser log, you will find that gzip has taken effect.

Moreover, the gzip-compressed files returned by static compression are prepared in advance, and files without .gz format will automatically return to the original files. This is a different response strategy than dynamic compression. Dynamic compression is based on the configuration in Nginx, and compression will be performed automatically if the size exceeds the configuration.

Well, after doing this, the loading speed of the first screen is increased by about 5 times.



Leave a reply



Submit