For a website to open speed is a very important indicator, but most of the time our energy may be used to deal with the demand, especially when we do some internal projects, we often ignore this aspect of optimization. Actually to a page open speed to make some more common optimization did not imagine the difficulties in this article will take you to do some optimization is neither easy nor time consuming operations, these operations involve the compression, caching, preload load key resources, the prefetch cache lazy loading resources and some Suggestions and reference component library to deal with common tools.

Enable Gzip compression

When we use Webpack to package and compress JS codes, some JS (such as vendor) are still very large, which may reach about 1MB size. Although this is not a big problem if we are PC side projects with the current bandwidth, there is obviously considerable room for optimization. Gzip is one such form. The browser header contains the accept-encoding :gzip, deflate, which tells us that the browser recognizes gzip compression and that files compressed using gzip are significantly reduced, in many cases up to 70%. Now services are basically using Nginx to do forwarding, it is quite easy for us to start gzip, just configure the following code.

server {
    gzip on;
    gzip_types       text/xml text/css text/plain text/javascript application/javascript application/x-javascript;
}
Copy the code

As can be seen from the above figure, vendor is nearly 800K when gzip is not enabled, but only about 250K after Gzip is enabled.

It’s safe to say that if we didn’t even have Gzip enabled, any other optimizations would be a bit redundant, because there probably isn’t another optimization that can compress such a high percentage.

Browser cache

In addition to the usual gzip compression, another optimization point to take advantage of is the browser cache. I’m going to introduce the browser caching method in passing, but I won’t go into too much detail, so if you are interested, you can find some additional resources to learn about it.

Browsers have two types of caches, strong caches and negotiated caches (also known as weak caches). Negotiated caches don’t have to be configured by ourselves. Let’s take a look at negotiated caches by refreshing the page twice in a row.

Last-Modified: sometime

location ~* \.(css|js)$ {
    proxy_set_header        Host  $host;
    proxy_pass              http://tomcat_xxx;
    expires                 7d;
}
location ~* \.(jpg|jpeg|png|gif|webp)$ {
    proxy_set_header        Host  $host;
    proxy_pass              http://tomcat_xxx;
    expires                 30d;
}
Copy the code

Note that we’re using Tomcat here, and you probably won’t need the same expires configuration as I did, but that’s not the point. The main thing we need is the Expires configuration, which indicates the time we want to cache. Our JS and CSS cache is set to 10 days, and our images are set to 30 days. Open the browser together to see the effect.

from memory cache

We can briefly summarize how browsers cache and add a few points of caution. Browser will first test the cache, if it is returned to the cache file directly, not sending HTTP requests, if missed to check the weak cache, return a status code of 304, when the weak cache hit the browser still get resource from the cache, if they aren’t in weak cache hit return 200 status code to load on the server resources.

Note:

  1. Strong cache and weak cache is just a name difference, there is no strong or weak cache. In fact, for ordinary browsers, the refresh will invalidate the strong cache of the resource you are currently requesting, because the refresh will carry one in the request headerMax - age = 0 or no - cacheNote that when I say the current requested resource here, I usually refer to the HTML document of your page, but for javascript, IMG, etc. linked to the document, there is no strong cache invalidation due to refreshing. However, if you request a JS file directly, the strong cache of the JS file will be invalidated after refreshing.
  2. Since strong caching does not initiate HTTP requests, what if the server resource changes. In fact, the hash code generated by Webpack is used to help us solve this problem. When app.123456.js becomes app.654321.js, the browser will naturally initiate the request again. This also reminds us that we should try not to change the vendor’s hash to cause cache invalidation.

Priority loading of critical resources and preloading of lazy resources

Since our technology stack is VUE, we will use VUE for the following example, but it is essentially the same regardless of the technology stack. Assuming our project is a single page application, the first thing we should optimize is the lazy loading of the route. That is to say, instead of returning all the code at once, we only request the code corresponding to the current route when we switch to the current route. For vue-CLI initializing projects, the configuration is very simple, just change the way import is done on the Router.

const router = new Router({
  routes: [
    {
      path: '/',
      redirect: '/a',
    },
    {
      path: '/a',
      component: () => import('.. /components/a/index.vue'),
    },
    {
      path: '/b',
      component: () => import('.. /components/b/index.vue'),},]Copy the code

Now we can dynamically load js files based on the router we access. However, there is still room for optimization. Suppose we request route A now and load public JS such as Vendor and JS of A, then why don’t we load the JS of route B into the browser’s cache in the spare time when we visit page A? Instead of sending an HTTP request when switching to route B, the user can use the file in the cache.

Here we are going to use a webpack plugin, PreloadWebpackPlugin, This is what the MDN documentation says about preload.

Preload before the browser’s main rendering mechanism kicks in. This mechanism allows resources to be loaded and available earlier and is less likely to block the initial rendering of the page, thus improving performance.

Specific relevant is the browser’s critical path knowledge, not detailed here, you can find other information.

In the case of Prefetch, the href browser will preload it, again quoting the words in the MDN document

It uses browser idle time to download or prefetch documents that the user is likely to access in the near future. The Web page provides a set of prefetch prompts to the browser and silently starts pulling the specified document and storing it in the cache after the browser finishes loading the current page. When the user accesses one of the prefetched documents, it can be quickly retrieved from the browser cache.

Therefore, for vue-CLI-generated projects, preload is used to load the three JS of Vendor, MANIFEST and app, while prefetch is used to load the files corresponding to all routes. In this way, when we visit route A, we will first download the JS and CSS required, and then the browser will automatically load other route files. The request is sent when the user does not click to access another route. Add the following code to webpack.prod.conf.js, under new HtmlWebpackPlugin(). Since our project is made up only of JS and CSS, you can configure img and font resources yourself.

new PreloadWebpackPlugin({
  rel: 'prefetch',
}),
new PreloadWebpackPlugin({
  rel: 'preload',
  as(entry) {
    if (/\.css$/.test(entry)) return 'style'
    return 'script';
  },
  include: ['app'.'vendor'.'manifest']})Copy the code

Registration of global components

The way many third-party components let us use is to import the component in main.js and pass it throughVue.component()To register the global components, in fact, in many cases, we should not use this plan, because it can increase the volume of the vendor, especially when this component is only used in one of the routing), into the vendor is not reasonable, because the cache we didn’t have a lot of benefits of this component code, assuming that page has five routing, None of this code makes sense for four other routes, so in many cases it is better for a local registry component to package it into the routing code. In addition, if it is a huge library like Echarts, it is recommended to package it into vendor, because the business code is always changing, so the hash value of routing code is always changing, so the weight of echarts code should not be reloaded by users every time it goes online.

After I think again about this think I may be wrong, because as the introduction of third-party components we is used as an external dependence, even smaller, each pack into the corresponding js routing will change because of the business code causes the user to reload this code, and bulky like I said cannot packed into more business in the code. I can think of only one scenario that may be different, that is, when the code goes online, we develop new requirements and need to introduce new dependencies, but we don’t want the vendor of the user cache to become invalid, so we can package a new dependency package, but this will increase the number of HTTP requests. We know that in HTTP1 we are optimizing the direction of domain name distribution and reducing the number of requests, so it is a matter of opinion whether this is good or not, but I should not do so.

Some libraries may require us to do some extra processing

Our common libraries of tools like LoDash and Moment are really, really big, and often we only use a few small features. It’s a waste of time to introduce such a huge library for those small features. Here are some basic solutions.

Babel-plugin-lodash: install “plugins” in. Babelrc: [” LoDash “], to introduce LoDash on demand, but to be honest, on-demand can be quite a bit, and writing your own might be a better choice if you really use a few very simple features.

Moment: Replace with day.js. The 2KB library, which has the same API as moment, is simply uncool. I have not read the source code, and I don’t know how 2KB can achieve the same functionality as moment. A bit confusing

There are also large libraries like Echarts that can be introduced on demand, so you can try to optimize the size of your own vendor

Finally, thank you for reading, if you help meThe originalEven better, click a star, after all, you know this year’s star can change money ~ ~ ~