preface

Recently, I spent some time on the performance optimization of the project, and did a lot of work behind the scenes. However, I still failed to achieve the result I wanted. I was a little disappointed, but I still recorded my perseverance.

Summary of performance optimization: reduce the number of requests, reduce the size of resources, improve the response and loading speed, optimize the loading time of resources, optimize the loading mode.

Performance classification

I think the optimization of front-end engineering performance can be divided into two categories:

  • Subjective and perceived performance from the user’s perspective.
  • Objectively measurable performance from a developer’s perspective.

Perceived performance

To the user, the user perception performance is the most important, simply put, is to make the user feel that your site is fast, and there is no measurement of perception performance.

However, there are always exceptions, and if a page takes a long time to load, there are ways to make it feel slower.

In short, your page can be fast, but you can make your users feel fast.

Objective performance

For developers, performance metrics can be measured objectively, and there are ways to optimize Web performance to meet the standards set by developers.

Objective performance is a measure of time from the time the user enters the URL to the time all resources are downloaded, parsed, and executed, and eventually drawn.

Performance metrics are a very complex standard, and I will write a separate article on performance metrics later.

Build optimization

Because our company is using

@vue/cli

So a lot of webPack configuration scaffolding has already been done for you, I won’t go into it, just base on it

@vue/cli

Do some optimization configuration

Gzip compression

Gzip compression is very efficient, usually up to 70% compression, which means that if your web page is 30K, it’s compressed to about 9K.

//npm i -D compression-webpack-pluginconfigureWebpack: config => {  const CompressionPlugin = require('compression-webpack-plugin')  config.plugins.push(new CompressionPlugin())}Copy the code

Remove the console log

Online projects are naturally not supposed to see console print logs, so we need to remove console.log.

//npm i -D terser-webpack-plugin  configureWebpack: config => {   const TerserPlugin = require('terser-webpack-plugin')   config.optimization.minimizer.push(     new TerserPlugin({       extractComments: false,       terserOptions: { compress: { drop_console: true}},}))}Copy the code

Remove SourceMap

Because packaged files are compressed, merged, and obfuscated, Babel compiled code is not conducive to locating analysis bugs.

module.exports = {  productionSourceMap: false,}Copy the code

CDN reduces packaging volume

Use CDN files to reduce the project to package volume and can also be loaded on demand.

Import the required JS and CSS files in /public/index.html

Remove dependencies on vue, element-UI and other related resources from package.json

SRC /main.js, remove vue, element-ui and other related resources import and vue.use statements

Configuration externals. Because the default configuration of Vue Cli 3 is used, the new project does not have the build directory. First, you need to create a new Vue. Config. js file in the root directory of the project and add the following code:

module.exports = {    configureWebpack:{        externals:{            'Vue': 'Vue'.'element-ui': 'element-ui'.'clipboard':'VueClipboard'}}}Copy the code

pre-rendered

There are three rendering methods: client rendering, server rendering and pre-rendering.

Our default development mode is through client rendering, but the client rendering page content, the key link is long, the first screen rendering will have a certain delay, and for

SEO

Very unfriendly and not feasible for c-end products.

Therefore, many companies will solve these two problems through SSR or pre-rendering. Due to the reasons of the company’s technology stack, we use pre-rendering to optimize.

What is pre-rendering?

To put it simply, the browser’s part of the job of parsing javascript dynamically rendered pages is done in the packaging phase. In other words, during the build process, WebPack generates statically structured HTML using the prerender-spa-plugin.

// npm i -D prerender-spa-plugin configureWebpack: config => {   const path = require('path')   const PrerenderSPAPlugin = require('prerender-spa-plugin')   config.plugins.push(     new PrerenderSPAPlugin({       staticDir: path.join(__dirname, 'dist'),       routes: ['/'],       minify: {         collapseBooleanAttributes: true,         collapseWhitespace: true,         keepClosingSlash: true,         decodeEntities: true,         sortAttributes: true,       },       renderer: new PrerenderSPAPlugin.PuppeteerRenderer({         renderAfterDocumentEvent: 'render-event',         renderAfterTime: 5000,         // headless: false,}),}))}Copy the code

Note: The routing mode must behistoryIf no value is sethistoryModes can also run and generate files for eachindex.htmlThe contents of the file will be the same.

Network Resource optimization

Service Worker

ServiceWorker is a SECTION of JS running in the browser background process. It can do many things, such as intercepting client requests, sending messages to clients, and making requests to servers. One of the most important functions is offline resource caching.

The ServiceWorker has rich and flexible control over the caching process. When a page request is made to the ServiceWorker, the ServiceWorker requests the cache and the network at the same time, gives the cached content directly to the user, and then overwrites the cache. Our company has used ServiceWorker to replace the HTTP cache policy.

Note: You need HTTPS to use ServiceWorker

HTTP cache

HTTP caches generally fall into two categories: strong caches (also known as local caches) and negotiated caches (also known as 304 caches).

A normal refresh enables negotiated caching and ignores strong caching. Strong caching is enabled only when you enter a url in the address bar or favorites, reference a resource through a link, and so on.

Strong cache (200)

Local caching is the fastest way of caching. As long as the resource is still in the cache, the browser will read it directly locally without asking the server.

Negotiation cache (304)

Negotiation cache, as the name implies, is negotiated between the browser and the server, after deciding whether to read the local cache. If the server notifies the browser that it can read the local cache, the 304 status code will be returned, and the negotiation process is very simple, only the header message will be sent, not the response body.

The cache location

The Cache location is usually divided into Memory Cache and Disk Cache.

Memory cache: fast read, short duration, small capacity

Hard disk cache: Reads data slowly, lasts for a long time, and has a large capacity

Cache priority

Service Worker -> Memory Cache -> Disk Cache -> Push Cache

HTTP2

Four new features of HTTP2:

  • Multiplexing eliminates the need for multiple TCP connections because it allows multiple requests to be made on a single HTTP2 connection and therefore does not rely on establishing multiple TCP connections.
  • Binary framing, which encodes all messages to be transmitted in binary and divides the information into smaller message blocks.
  • Header compression: Uses the HPACK technology to compress the header and reduce the packet size
  • Server push. The server can send data before the client initiates a request. In other words, the server can send multiple responses to a request from the client, and the resources can be properly cached.
server { listen 443 ssl http2; }Copy the code

Note: To use HTTP2, you must use HTTPS.

Resource preloading

Simply put, resources are loaded ahead of time and rendered directly from the local cache when the user needs to view them.

Summary: Use preload to preload resources required by the current page and prefetch to preload resources required by other pages.

preload

Preload is loaded during page loading before the browser begins body rendering.

<! -- Preload sty1e.cs5 and index.js with pre1oAD --><link rel="preload" href="style.css" as="style"><link rel="preload" href="index.js" as="script">Copy the code

prefetch

After the prefetch page is loaded, it is loaded in advance in idle time.

<! Prefetch --><link rel="prefetch" href="next.css"><link rel="prefetch" href="next.js">Copy the code

Note: Vue-CLI enables Prefetch by default. You can disable prefetch globally in vue.config.js and enable prefetch for a specific module.

chainWebpack: config => {  config.plugins.delete('prefetch')}Copy the code

dns-prefetch

After the page is loaded, use the idle time to load in advance.

<link rel="dns-prefetch" href="//example.com">Copy the code

Load JS asynchronously without blocking

Load js files asynchronously without blocking page rendering.

Let’s start with a common script tag parsing process.

<script src="a.js" ></script>Copy the code
  1. Stop parsing the document.
  2. Request a. s.
  3. Execute the script in A. js
  4. Continue parsing the document

defer

<script src="d.js" defer></script><script src="e.js" defer></script>Copy the code
  1. Do not prevent document parsing, parallel downloading of D. js, e.js
  2. E.js continues parsing document even after downloading D.js
  3. Execute d.js and e.js in the order that they appear on the page, after the execution of the other synchronization scripts, and before the DOMContentLoaded event.

async

<script src="b.js" async></script><script src="c.js" async></script>Copy the code
  1. Do not prevent document parsing, parallel downloading of B. js, C. js
  2. Execute the script immediately after it is downloaded. (The execution sequence and execution stage are uncertain, which may be before or after the DOMContentLoaded event)

webp

Webp is a new image format, which is only 2/3 of the size of JPEG. Switching image resources to WebP can speed up requests.

Most of our picture resources are on Ali’s OSS, and Ali provides an interface to convert PNG/JPEG to WebP format online.

Note: WebP has some browser compatibility issues, so you need to determine whether your browser supports webP.

function check_webp_feature(feature, callback) {    var kTestImages = {        lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",        lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",        alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",        animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gc A"    };    var img = new Image();    img.onload = function () {        var result = (img.width > 0) && (img.height > 0);        callback(feature, result);    };    img.onerror = function () {        callback(feature, false);    };    img.src = "data:image/webp; base64,"+ kTestImages[feature]; }Copy the code

Perceptual performance optimization

Loading load

Rivers and lakes known as chrysanthemum map….

However, there is now a better way to load a design experience than chrysanthemum loading.

Skeleton screen

The skeleton screen provides a better user experience and a strong sense of loading.

Unfortunately, ElementUI doesn’t provide skeleton screen components. Antd, on the other hand, is delicious.

Compare the experience

The first one is skeleton screen, the second one is chrysanthemum chart, and the third one is no optimization. Compared with the traditional chrysanthemum chart, it can be seen that the content appears smoothly but not obscenely, and the experience is better.