The full text of 6511 words/words, reading about 13 minutes, too long do not look at the party please go directly to 👉 “start optimization” section directly view optimization means

background

Some performance issues have been exposed as the company’s server network has fluctuated and website access has slowed. Feedback in such weak network conditions, visit the new project, loaded nearly a minute did not load out, and visit other pages at most 30-40s.

After the network was restored, I tried to access the next page, but it took nearly 11s to open the first time without cache, and the maximum resource reached 3.7m…

After some optimization of the project, it can be found that the web page is almost open in seconds when opened without cache again, and the average time is less than 1s

Summary record here, basically are some conventional replication of optimization means, I hope you can also want to optimize the performance of the page to provide ideas ~

The optimization effect




Network

Slow3G condition with 22-25s loading complete






lighthouse






hiper

About Performance Optimization

Before we begin, we need to understand one principle: the ultimate goal of performance optimization is to improve the user experience. The short answer is to make the site feel “fast” (or at least not slow hh). There are two kinds of “fast” here, one is “really fast” and one is “feel fast”.

  • “Really fast” : things that can be measured objectively, such as page access time, interactive response time, and page jump time
  • “Feel fast” : users’ subjective perception of performance, through visual guidance and other means to divert users’ attention on waiting time

Doing these two things well will improve the performance evaluation of the website.

trade-offs

Another is that there is no silver bullet in software engineering. One optimization solution may work for most projects, but in some special cases it may be counterproductive.

For example, 🌰, because the browser has restrictions on concurrent requests under a single domain name, we usually put the dependencies into a vendor package (vue-CLI default policy) to reduce the number of first-screen requests, and the file fingerprint remains unchanged when the dependencies remain unchanged, so 304 cache can be effectively used. In the case of few dependencies, such processing does help to improve the loading speed, but once there are many dependencies, vendor will be particularly large, which will seriously slow down the page display under the condition of weak network. This is obviously not what we want, so we split vendor according to the situation, such as split to the CDN, or directly split to the page

Therefore, in the process of performance optimization, we must make a choice suitable for the current project based on the ultimate improvement to user experience

Indicators and targets

Goals influence the decisions we make in the process and indicators measure our goals

The target

First of all, we need to determine the goals. The goals may vary according to the complexity of the scene and project, such as 20% faster than competing products, or meeting the standard “2-5-10” principle, etc

So my goal here is

  • Under normal network speed, the load is completed in 2s
  • Under weak network, loading is completed within 30 seconds

indicators

About the indicators, a brief introduction of common indicators

  • FCP (First Contentful Paint) : White screen time (First text drawing time)
  • Speed Index: first screen time
  • TTI (Time To Interactive) : indicates the Time of the first interaction
  • Lighthouse Score (Performance) -g Lighthouse Score (NPM install -g Lighthouse programmatically)

A debugging tool

You can use performance debugging tools such as Newwork, K6, Hiper, Lighthouse… . For details, see my other article on performance debugging tools

Bottleneck analysis

The Network analysis




To optimize the Network before


From the Network, we found that the main problem was in 3.2m chunk-vendor.js

  • It’s too bulky and slow to download
  • Other resource downloads are blocked

Lighthouse analysis




Optimize the Lighthouse before


The Performance analysis

Because this time does not involve Performance optimization in application scenarios, Performance analysis skips…

Dist Directory Analysis

  • The overall volume is too large, nearly 5M
  • There are several static resources that should not be present, such as small diagrams that should be inlined on pages that do not refer to SVG ICONS
  • Part of the image resources are large, the largest up to only 400KB

Webpack Bundle analysis




Optimize the Bundle before

As you can see from webPack Bundle, there are quite a few problems

  • Redundant dependencies used by project templates, such as G2, Quill, wangEditor, Mock, and so on, are not removed
  • Some unused Ant-Design components are also packaged with global registration
  • Only a few ant-design/ICONS are used in the project, but they are all introduced
  • Moment and moment-timezone are repeated and larger
  • Core-js is bulky
  • The chunk-vendor is too large due to improper packaging policies

To optimize

🛫 🛫 🛫

Volume optimization

⚡ Check and remove redundant dependencies and static resources

Content (Click expand/Fold up)
  • Remove redundant project template dependencies
  • Move public static resources into assets. Static resources should be placed under assets, public will simply copy to Dist, files that are not processed by WebPack should be placed, such as webpack-incompatible libraries, files that need to specify file names, etc

Before: 4.96m after: 4.12m

⚡ Compress images while building

Content (Click expand/Fold up)

Manual compression is more cumbersome each time using an online service, so you can add compressed images directly to the build process

useimage-webpack-loader

// install npm i image-webpack-loader -D // vue.config.js chainWebpack: (config) => {if (isProd) {// Image compression const imgRule = config.module.rule('images') imgRule .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/) .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true }) .end() } }Copy the code
  1. If the Imagemin library fails to be downloaded during install or build, try changing the source, configuring github hosts, or adding the imagemin library during Install--user=rootTo solve
  2. Since the image has been manually compressed by online tools after downloading, this part is not improved much

Before: 4.12m after: 4.00m

⚡ Use webP images

Content (Click expand/Fold up)

WebP is Google launched a new picture format (2010), the same quality under the volume of boxing PNG kick JPG, the current compatibility is ok, apple home performance is not ideal

Convert to a webP image

You can do this either manually or by adding build automation.

  • Manual, you can use webP-Converter, smart map and other tools, but it is recommended to use the official WebP-Converter, in addition to convenience, with the same quality of volume is better than smart map in all aspects.
./cwebp -q 75 login_plane_2.png -o login_plane_2.webp
Copy the code
  • Automated generation, using image-min-webp or other Webpack plug-ins

Page use (compatible with lower versions)

  • In HTML,<picture>The label is compatible with
<picture>
    <source srcset="hehe.webp" type="image/webp">
    <img src="hehe.png" alt="hehe>
</picture>
Copy the code
  • It is used in CSS and needs to be judged with JS
// main.js
window.addEventListener('DOMContentLoaded', () => {
    const isSupportWebP = document.createElement('canvas')
    .toDataURL('image/webp')
    .indexOf('data:image/webp') === 0
    document.documentElement.classList.add(isSupportWebP ? '' : '.no-support-webp');
})
// css
.support-webp .bg{
    background-image: url("hehe.webp");
}

.no-support-webp .bg {
    background-image: url("hehe.png");
}
Copy the code
  1. Be sure to use the original image for webP conversion, otherwise the volume will be affected
  2. There are not many large images of the project. The largest 400KB image is only 48.9KB after conversion

⚡ Optimize SVG ICONS

Content (Click expand/Fold up)

In this step, we will optimize the packaging of some redundant old SVG ICONS. In general, SVG is used in iconfont to generate JS and then import. This kind of practice

  • Unintuitive, you have to go to iconfont to copy the name every time
  • Every time you add, delete, or change an icon, you need to replace the entire JS
  • Can not load as needed, not used will also be packaged together, especially when UI ICONS are generally not deleted….
  • Adding custom SVG is not friendly and iconFONT must be uploaded to add together before downloading

Better SVG gameplay

  • Added or modified ICONS
    • Download any SVG icon from iconFont UI upload or elsewhere and place it under ICONS/SVG /
    • Use the global SVG component in the page, pass in the file name of the copied SVG
  • delete
    • Just remove the place where it is used and then delete the corresponding icon

To achieve this, all you need is

  • The introduction of SVG – Sprite – loader
// install npm i svg-sprite-loader -D // vue.config.js chainWebpack: Rule (' SVG ').exclude. Add (resolve(' SRC/ICONS/SVG ')).end() config.module .rule('icons') .test(/\.svg$/) .include.add(resolve('src/icons/svg')) .end() .use('svg-sprite-loader') .loader('svg-sprite-loader') .options({ symbolId: 'icon-[name]' }) .end() }Copy the code
  • Create SRC/ICONS/SVG and put the ICONS in it and import them automatically via webpack require.context
// src/icons/index.js
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

// main.js
import '@/icons'
Copy the code
  • Create the global component CA-SVG
// src/icons/index.js import Vue from 'vue' import CaSVG from '@/components/ca-svg' Vue.component('ca-svg', CaSVG) // src/components/ca-svg.vue <template> <svg :class="svgClass" aria-hidden="true" v-on="$listeners" :style="svgStyle"> <use :xlink:href="iconName" /> </svg> </template> ... // The name attribute is a required field, and other sizes or colors can be customizedCopy the code

Compression optimization

SVG usually has some redundant information that affects the volume, and here we can use svGo-Loader to compress it further

// install NPM I svgo-loader -d // vue. Config. js // Install NPM I svgo-loader -d // vue. .end() .use('svgo-loader') .loader('svgo-loader') .end()Copy the code

⚡ Optimize ant-design-vue volume

Content (Click expand/Fold up)

As you can see, this is a large proportion of chunk-vendor

According to the need to introduce

In fact, this part has already been processed, refer to the ant-design-vue document for specific operations, there is no big mistake to do according to the instructions, the effect is also expected.

Get started quickly – Ant Design Vue

Delete redundant components

Some components are not used often, but are introduced globally using vue.use (). Drop the global import, which is not used or used, and replace it with the in-page import() import

⚡ Optimize ant-Design-Icon volume

Content (Click expand/Fold up)

This section, since we only used a few Ant built-in ICONS in the project, could not be 530+KB. According to the Ant documentation, this is due to the fact that it fully introduces the ICON, saying that the current usage if loaded on demand is uncertain whether the user will change the ICON at run time, such as the configured ICON.

Redirect to local control

This issue has been addressed in the React version of Ant-Design, but there is still no official solution in ant-Design-vuE-1. x. Two scenarios are known

  • Use webpack-ant-icon-loader (asynchronous loading)
  • Redirect to a local file for control (recommended), using alia will@ant-design/icons/lib/distPoint to the projectantd-icon.jsAnd then inantd-iconExport as needed
Resolve: {alias: {'@ant-design/ ICONS /lib/dist$': path.resolve(__dirname, './src/icons/antd-icon.js') } } // src/icons/antd-icon.js export { default as LoadingOutline } from '@ant-design/icons/lib/outline/LoadingOutline'Copy the code
  1. Note that ICONS used in projects and Ant components are exported
  2. Optimized from 530K+ to 30K+

⚡ Optimize moment and moment-timezone volume

Content (Click expand/Fold up)

These two packets are 300K + 160K, adding up to 460K, which is also a relatively large item

Do not pack the moment time zone file

This is done using the built-in IgnorePlugin

// webpack plugins
plugins: [
  // Ignore all locale files of moment.js
  new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
Copy the code

Remove the moment – timezone

Moment-timezone contains moment, which is used in only one place in the project to get the current time of the east 8 zone. You can do this without adding moment-timezone

// old
moment.tz('Asia/Shanghai').format('YYYYMMDDHHmmss')
// new
moment.utcOffset(480).format('YYYYMMDDHHmmss')
Copy the code

Replace moment with dayjs

Dayjs implements most of the functions of Moment. The Api is basically the same, but the compressed volume is less than 2K, which is an excellent alternative. In most cases, DayJS can be a perfect substitute for Moment.

Ant Design uses moment to implement date-picker, so it won’t work if you don’t use moment in your project. It will be packaged in….

This problem is already addressed in the React version of Ant-Design, which allows the user to choose dayJS or moment. Also, ant-design-Vue still hasn’t followed through…

Fortunately, the dayjs author provides a plugin that can replace the moment of ant-design-vue with dayjs👍. Although the documentation only says that ant-design-react works, you can actually see in the issue that it also works with antdV, but requires some configuration adjustments

useantd-dayjs-webpack-plugin

// vue.config.js
const AntdDayjsWebpackPlugin = require('antd-dayjs-webpack-plugin')
configureWebpack: {
    ...
    plugins: [
      new AntdDayjsWebpackPlugin({ preset: 'antdv3', replaceMoment: true })
    ],
}
Copy the code

The replaceMoment parameter is used to redirect a moment to dayJS with the Webpack alias. Since moment is used in many places in the project, doing so can continue to use dayJS that moment actually calls, implementing a perceptionless replacement 👍

  1. When dayJS is replaced, some functions need to be consistent by introducing plug-ins, such as UTC and updateLocale
  2. Some optimizations for moment need to be changed to dayjs or removed after being replaced with dayjs

⚡ Optimize core-JS volume

Content (Click expand/Fold up)

Core-js is actually a polyfill of the new BROWSER API. The project is PC side, so it is mainly for compatibility with IE…

Adjust browserslistrc.

  • Make Babel and auto-prefix less compatible by specifying the version your project needs to be compatible with, such as mobile Internet explorer, iOS6.0, etc

Adjust the useBuiltIns

The default in the project is useBuiltIns: ‘Entry’ brings in all polyfills, resulting in a large package. We can use useBuiltIns: ‘Entry’ to adjust the policy and import as needed, so that apis not used in the project are not polyfilled

// babel.config.js module.exports = { presets: ['@vue/cli-plugin-babel/preset', ['@babel/preset-env', {'useBuiltIns': 'usage', // entry, usage' corejs': 3 } ] ], plugins }Copy the code

BTW, the better thing to do here would be to use dynamic polyfill and let the server decide whether to return polyfill based on UA

Before: 4.96m after: 2.96m


Transmission optimization

⚡ Optimize the subcontracting strategy

Content (Click expand/Fold up)

The default optimization for VUE-CLI3 is to dump all NPM dependencies into chunk-vendor, but this can lead to chunk-vendor oversize in the case of too many dependencies

optimization: isProd ? {splitChunks: {chunks: 'all', maxInitialRequests: Infinity, // Default to 3, adjust to allow unlimited entry resources minSize: 20K, // dependencies below 20K do not split cacheGroups: {vendors: {// Split dependencies to avoid single file size and slow page display // Thanks to HTTP2 multiplexing, Name (module) {// Unpack const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)) (/ / \ \ | $) /) [1] / / further split Ant components, please according to the situation / / const packageName = module. The context. The match (/ / \ \ / node_modules / \ \ / (? :ant-design-vue[\\/]es[\\/])? (. *?) (/ / \ \ | $) /) [1] return ` NPM. ${packageName. Replace (' @ ', ')} ` / part/server does not allow urls with @}, the test: /[\\/]node_modules[\\/]/, priority: -10, chunks: 'initial' } } }, runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` } } : {}Copy the code
  1. Vue inspect > output.js –mode production
  2. Subcontracting needs to be handled according to the actual situation in order to achieve better results. In short, it is right to read more documents and try more

⚡ Optimized lazy route loading

Content (Click expand/Fold up)

One of the most important ways to speed up SPA is routing lazy loading, which only loads corresponding files when the page is opened. We can easily achieve lazy loading by using Vue’s asynchronous component and webpack’s code segmentation (import()).

However, when there are too many routes, please use webpack magic annotation to group the routes properly, too many chunks will affect the speed of the build

{
    path: 'register',
    name: 'register',
    component: () => import(/* webpackChunkName: "user" */ '@/views/user/register'),
}
Copy the code

Please only load lazily during production, otherwise the build speed will be impressive when there are many routes

Open HTTP2 ⚡

Content (Click expand/Fold up)

HTTP2 is the second version of the HTTP protocol. It is faster, has lower latency, and has more features than HTTP1. So far, the compatibility is good, with more than 50% coverage in China.

The HTTP2 protocol can process multiple requests in a single TCP connection frame (multiplexing) without this limitation. The HTTP2 protocol can process multiple requests in a single TCP connection frame (multiplexing) without this limitation. (The rest of the header compression and so on also provide some performance improvements)

If the site supports HTTPS, please enable HTTP2 as well. The cost is low and the benefits are high for pages with many requests, especially when the network speed is poor

Nginx enable HTTP2 (>V1.95)

  • Adjust the Nginx configuration
// nginx.conf
listen 443 http2;
Copy the code
  • Restart the Nginx
nginx -s stop && nginx
Copy the code
  • Verify the effect of




After HTTP2 open

Multiplexing avoids resource concurrency limits, but too many resources can cause browser performance penalties (Interprocess communication in Chrome depends on the number of resources)

⚡Gzip compressed transmission

Content (Click expand/Fold up)

Gzip compression is a powerful compression method that typically reduces the size of text files by two-thirds.

The HTTP protocol uses the accept-encoding and Content-encoding header fields to agree on which Encoding to transmit the body in. The accept-Encoding of the request header lists the Encoding supported by the client. When the content-encoding of the response header specifies gzip, the browser decompresses it

General browsers support gzip, so accept-Encoding will automatically carry gzip, so we need to have the resource server specify gzip in Content-Encoding and return the gzip file

Nginx configuration Gzip

Enable and disable gzip mode gzip on; Gzip_min_length 1k; # gzip_comp_level 6; # gzip_level 6; # gzip_level 6 The type of file to compress. gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ; Gzip_static on # Whether to add Vary to HTTP headers: Accept-encoding, gzip_vary on is recommended; Gzip_http_version 1.1;Copy the code

Gzip files are generated at build time

Although Nginx already compresses and returns Gzip in response to requests, the compression itself consumes CPU and time on the server. The higher the compression level, the more expensive it is, so we usually upload the Gzip file together and let the server return the compressed file directly

// vue.config.js const CompressionPlugin = require('compression-webpack-plugin') (config) => { if(isProd) { config.plugin('compression-webpack-plugin') .use(new CompressionPlugin({ test: / \. Js $| \. HTML $| \. CSS $/, / / matching filename threshold: 10240, the data of more than 10 k / / compression deleteOriginalAssets: false / / not to delete the source file}}}))Copy the code
  1. The default compression level for plug-ins is 9, the highest compression
  2. Image files are not recommended to be compressed by gzip

⚡ Prefetch, Preload

Content (Click expand/Fold up)

Two optional values for the REL attribute of the tag. Prefetch is to remind the browser that the user may need to load target resources in the future. Therefore, the browser may obtain and cache corresponding resources in advance to optimize the user experience. Preload: indicates that the user may need to load the target resource during the current browsing. Therefore, the browser must obtain and cache the target resource in advance.

Prefetch and Preload can effectively optimize user experience in some scenarios. Give some scenarios

  • The font on the first screen and large image is loaded, and the font introduced into the CSS is loaded only after the CSS is parsed. Before this, the browser uses the default font, which is replaced by a customized font after loadingFont styles flashAnd we usePreloadThis is much better when fonts are pre-loaded, as is the case with large images
  • Similarly, url references in CSS will not load images before DOM is mounted. Prefetch can be used to load images in advance when entering the card package page/cash register, so that users can immediately see the loaded images when carrying out the coupon page

By default, vuE-cli3 uses preload-webpack-plugin to perform preload and prefetch processing for chunk resources, import file preload, and route chunk prefetch.

Generally speaking, no special operation is required. If no adjustment is required, you can configure it in vue.config.js

  1. Theoretically, Prefetch does not affect the loading speed, but in the actual test, it has a slight impact. However, it depends on one’s opinion, I think the overall experience is improved.
  2. Preload is recommended for key first-screen resources such as font files hidden in scripts and styles
  3. Exercise caution when accessing traffic on mobile devices

⚡ Hosting to OSS + CDN acceleration

Content (Click expand/Fold up)

When dealing with weak network areas, OSS + CDN is undoubtedly a powerful means of speed up.

OSS, object storage

Massive, secure, low-cost, highly reliable cloud storage services. Data can be uploaded and downloaded anytime, anywhere through a simple REST interface, or managed using WEB pages.

Features of OSS:

  • Stable, high service availability, multiple backup to ensure data security
  • Security, multi-level security protection, anti-ddos
  • Large scale, high performance, easy to handle high concurrency

OSS also provides some convenient services

  • Image processing, support compression, cropping, watermarking, format conversion, etc
  • Transmission acceleration, optimize transmission link and protocol strategy to achieve high-speed transmission

It is recommended to purchase ALI’s OSS directly. Although OSS also has transmission acceleration service, CDN acceleration is still required for static hotspot file download acceleration scenario

CDN, content delivery network

The principle of CDN acceleration is to take the domain name provided as the source station and cache the source content to the edge node. When the customer reads the data, the cache file is fetched from the most suitable node (typically the nearest one) to speed up the download.

Due to the failure to apply for resources, the project is not enrolled in OSS+CDN. But if there are conditions or suggestions, improve very much


Perceptual performance optimization

😎 Loading animation in a blank screen

Content (Click expand/Fold up)

The first screen is optimized to enable users to see Loading animation before JS is parsed and executed, thus reducing waiting anxiety. It is common to write simple CSS animations on index.html until Vue is mounted to replace the contents of the mounted node. However, this method also produces a brief blank screen. It is recommended to manually control CSS animations to turn off

😎 First screen skeleton loading

Content (Click expand/Fold up)

The first screen is optimized, and the gray color blocks are common in APP when loading. For the automatic generation of skeleton screen page, there are many solutions in the industry.


Some additions to perceptual optimization

Some scene optimization outside the first screen, more relevant content such as lazy loading of pictures, lazy loading of components and other subsequent articles will be introduced

😎 progressive loading of images

Content (Click expand/Fold up)

Generally speaking, there are two ways to load images, one is top-down scanning, and the other is a fuzzy display of the original image, and then gradually/load clear. The former has a poor user experience when the network speed is poor, while the gradual/staggered loading of the latter can reduce the user’s waiting anxiety and bring a better experience

Progressive/interleaved format images

The browser itself supports the blurry to sharp scanning loading of images, as long as the resources are handled properly

  • UI generation, select “Continuous” for PS export and “Progressive/Interleaved” for Sketch export
  • Transformations, handled using third-party libraries

Progressive loading of images

First load the small image, blur rendering, and replace the image with the original image after loading. The most typical example is Medium. Blur can be processed by filter or canvas

Load a placeholder map

Load the global loading diagram or fill the color block with CSS, and replace the image with the original one after loading. Simple and crude, useful in weak mesh conditions

  1. Several methods can be used together
  2. Progressive/interleaved images take up a certain amount of CPU and memory

😎 Animation of route jump Loading

Content (Click expand/Fold up)

Weak network optimization means, after using lazy loading, if the user clicks on the next page under weak network conditions, the page content is not available before the next page is loaded, the user will understand as stuck. Do this in VueRouter’s routing guard

At the end

This paper only introduces the performance optimization under the first-screen loading scenario. In fact, the performance optimization is far more than these contents. Is it really credible that the loading performance indicators of SPA are collected by Lighthouse and slow 3G simulation? What about other aspects besides loading scenarios? Build speed, smooth operation…

business

Performance optimization affects not only the user experience, but also conversion rates, search engine rankings, and ultimately traffic, sales, and other revenue

Data from Google shows that a page with 10 pieces of data that load in 0.4 seconds turns into 30 pieces of data that load in 0.9 seconds, and traffic and AD revenue drop by 90%.

When the Google Map homepage file size was reduced from 100KB to 70-80KB, traffic increased by 10% in the first week and 25% in the next three weeks.

According to Amazon, an increase of 100 milliseconds in load time leads to a 1% drop in sales.

Position is different, look at the point of view of the problem will also change, for example, the ultimate goal for the boss is to make money HH, user experience these flashy, others may not understand.




User Experience x Money √


Therefore, if necessary, perform data monitoring and analysis of performance benefits before and after the process to establish a positive relationship between performance optimization and product indicators, so as to facilitate top-down implementation of technical solutions. This is the key to convincing your boss or leader to invest in performance optimization

Personal ascension

Performance optimization is a cliche topic, but some people in the face of how to do performance optimization question, only lists various common optimization method, the deeper the answer should be what performance problems, around certain performance index is adopted to solve this problem what means, whether the other problem, how to weigh, achieved what kind of result finally.

reference

  • 2018 Front-end Performance Optimization list
  • How did I make the company’s back office management system look new (I)- performance optimization
  • .