The performance optimization strategy of SPA(single page application) has many differences from the strategy straight out of traditional MVC framework. This paper introduces SPA optimization strategy of blog front end and some common general optimization methods

SPA strategy

XHR filters attributes that are not needed

Taking the homepage of this blog as an example, the requested POST model has three large attributes summary, content and markdownContent. Content and markdownContent are not used for the homepage

This blog has made a filter according to this, the previous request without optimization is 160ms, and the optimized request is only 40ms. However,SSR after the first screen, this optimization brought little acceleration.

Unidirectional data flow

In order to get the most out of each request, one-way data flow is the best choice

If you have two different components that depend on the same data, instead of one-way data flow, you have to make two identical requests. In this case, I don’t think LocalStorage can be used to solve the problem, after all, it is not decided which of the two components will be mounted first

Before the use of one-way data flow, the front desk of this blog sent the same request twice to/API/Option, each request 50ms, and obtained 50ms improvement after optimization

Server Side Rendering (SSR)

SSR is the ultimate SPA destination. In addition to solving SEO, it can also significantly reduce the first screen loading speed. As for the loading speed of non-first screen, you should know that SPA non-first screen pages most likely only need to send one XHR, so only need to solve the problem of first screen rendering

The SSR server can be Express or KOA2. It is recommended that the SSR server and the database be placed on the same server as the Intranet. In this way, the time of XHR requests can be greatly reduced through Intranet access.

In the SINGLE page SSR application of the display type, the _id attribute is of little use in the data obtained and can also be filtered out, saving 1K or 1K

Through SSR, this blog reduces the first screen access time from an average of 800ms to an average of 300ms, and other simple pages, such as about pages, even reduce to less than 200ms

Block lazy loading

Block asynchronous loading is also a common first-screen optimization strategy of SPA. It means to split the components that are not needed in the first screen and load another block of the server to obtain the required components when accessing other paths

There are some conflicts with SSR, for example, SSR and block lazy loading are currently incompatible with VUe2, but the good news is that one of vue2’s core developers is working on this issue

SSR component level cache

Each piece of data in the list is cached by ID + update time, thus bringing 50ms optimization to the first screen of the blog

Reduce home page data

For example, Ququ’s first screen only had several hundred words, while mine had several thousand words. Especially, SSR needed to serialize vuex’s initial state into the page, so the text size in my first screen was actually about 20 times larger than Ququ’s

After minimizing the DOM, the page size was reduced by 30KB and the GZIP was reduced from 96KB to 90KB

Merging JS files

This policy is for spAs that do not have HTTP2 multiplexing enabled. In particular, be sure to incorporate vendors when packaging

When multiplexing is enabled, packaging can increase the time, after all, the reuse of a TCP connection can save a lot of time

MongoDB paging optimization

MongoDB skip is very slow.

One optimization strategy is as follows:

Suppose 10 items per page, then when requesting the first page, one additional item is requested, that is, 11 items are requested. Find ({“_id”:{“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: {“$gt”: ‘the id’}}). Limit (11) Query the number of entries on the next page.

One disadvantage of this is that you cannot access the non-first page directly because there is no base ID. However, for a low-traffic system like a blog, we can cache the _id of 1, 11, 21, and so on through Redis, and query the next 10 items directly with the _id in redis when the client requests paging

Avoid using large class libraries

React and Vue both support direct access to the DOM via mount refs, so it’s time to use native JS. I think this point should be the progress of the front end, no matter how the front end changes, native JS is always the foundation of the building

Tree-shaking packaging reduces useless code

Webpack2 supports this by default, and after changing babelrc, the foreground package was reduced from 142K to 122K, although I felt completely unnerved: node_modules does not have a library for es6 modules, how did it compress into?

However, tree-shaking is different from packaging by vendor. If you divide vendors, all vendor libraries are not shaken by tree-shaking. For example, in the foreground of this blog, Tree-shaking is packaged as a 122K APP block regardless of vendor. Tree-shaking is packaged as a 22K APP block and a 120K vendor block.

If http2 multiplexing is enabled, it’s not really time saving for vendor-multiplexed TCP links, or for tree-shaking saved 20K code. But without considering HTTP2, tree-shaking is undeniably better than vendor

General strategy

Picture optimization strategy

  1. Favicon doesn’t have to be 128×128, just 32×32 is enough, saving 15KB or so here
  2. SPA application static picture resources are generally placed on THE CDN, can be uploaded through the multimedia processing function provided by THE CDN to generate thumbnail, so that in addition to accelerating access, but also can be watermarking anti-theft
  3. Frequently used images can be changed to webP format. For example, the logo of a blog is 20KB in JPG format and only 3KB in WebP format.

However, the WebP format is relatively new and some older browsers don’t support it (specifically Firefox V41.0, which I still use), so you can use the following code to change the unsupported webP format to another format

img.onerror = ({ target }) => (img.src = target.currentSrc.replace('.webp', '.png'))
Copy the code

Note that the code above is before Babel transcoding, to use directly you need to convert to ES5 form

LocalStorage Data cache

LocalStorage I dare not use it, there is no verification policy if it is simply a time bomb ah, and SPA one-way data, the data needed can be obtained from the global state tree, there is no need to LocalStorage

However, it is very powerful when used, for example, ququqi’s blog, the first screen loads 150ms, I am also drunk, just make a blog with MVC framework straight out into a single page application, and ensure that the first screen does not have useless global state data (usually 20KB).

Use Gzip compression

Gzip typically compresses up to 70% of the file size and is easy to configure for Nginx, turning on a few lines by default. For single page applications, don’t forget to make the REST API gzip as well. For example, a blog that returns a 3K XHR can save 2ms by gzip, rather than pressing the response header to get the same 2ms speed.

DOM loading optimization

This is evident in the blog’s homepage, where the summary is not an HTML tag parsed by Markdown, but pure text, optimized for detail

Upgrade to the latest version of nginx

Older Linux distributions tend to ship nginx at lower versions, such as 1.4.4 before this blog, but with the upgrade from 1.4.4 to 1.11.5, access speeds are stable and significantly improved, even if HTTPS and H2 are not enabled

Open the HSTS

HSTS can avoid HTTP to HTTPS hops. In addition to security, HSTS can also save the time for a full HTTP request. It is also very important for the first screen access.

Don’t forget to apply for the HSTS Preload List last

Enable HTTP2 multiplexing

Lazy loading of images

This is also a common common strategy, so I’m going to skip it

The effect

Before, vue2 single page application, and did not open SSR, the first screen strong brush 976ms:

Then, after optimization according to the order in this paper, and SSR was turned on, the first screen was strongly brushed 163ms:

In fact, the 163ms image was cut before the optimization was completed. Now after changing the HK server with very low delay, the blogger can even press to less than 150ms

Smallpath. me/post/spa-op… smallpath.me/post/ SPa-op…