Vue framework, through two-way data binding and virtual DOM technology, helps us deal with the dirtiest and most tiring PART of DOM manipulation in front-end development. We no longer need to think about how to manipulate DOM and how to efficiently manipulate DOM. However, there are still some problems in the VUE project, such as the optimization of the first screen and webpack compilation and configuration, so we still need to pay attention to the optimization of the performance of the VUE project, so that the project can have more efficient performance and better user experience. This paper summarizes the optimization practice of the actual project.

  • Vue code level optimization;
  • Optimization of webpack setup level;
  • Basic Web technology level optimization.

I. Optimization at the code level

1.1 V-if and V-show are used in different scenarios

V-if is true conditional rendering because it ensures that event listeners and subcomponents of conditional blocks are destroyed and rebuilt locally during switching; Also lazy: if the condition is false during the initial render, nothing is done — the conditional block does not start rendering until the condition is true for the first time.

V-show is much simpler. Regardless of the initial conditions, elements are always rendered and simply switched based on the display property of CSS.

Therefore, V-IF is suitable for scenarios where conditions are rarely changed during operation and conditions do not need to be switched frequently; V-show is suitable for scenarios that require frequent switching of conditions.

1.2 Use scenarios of computed and Watch are distinguished

Computed: Computed attributes depend on other attribute values, and computed values are cached. Only when the dependent attribute values change, computed values will be recalculated the next time it obtains computed values.

Watch: More of an observation function, similar to listening for callbacks to some data, executing callbacks whenever there is a change in firm data.

Application scenario:

  • When we need to do numerical calculations and rely on other data, we should use computed because we can take advantage of the caching nature of computed and avoid recalculating every time we get a value.
  • Watch should be used when we need to perform asynchronous or expensive operations when data changes. Using the Watch option allows us to perform asynchronous operations (accessing an API), limiting the intermediate state before we get the final result. These are all things you can’t do with computed properties.

1.3 v-for traversal must add a key to the item and avoid using v-if at the same time

(1) V-for traversal must add a key to item

During the traversal rendering of the list data, a unique key value should be set for each item to facilitate the accurate finding of the list data by vue.js internal mechanism. When state is updated, the new state value is compared to the old state value to locate the DIFF faster.

(2) V-for traversal avoids using V-if at the same time

V-for has a higher priority than V-IF, and if you need to traverse the entire array each time, it will affect speed, especially if you need to render a small part of the array. If necessary, use computed attributes.

Recommendation:

<ul> <li v-for="user in activeUsers" :key="user.id"> {{ user.name }} </li></ul>computed: { activeUsers: function () { return this.users.filter(function (user) {     return user.isActive }) }}
Copy the code

Is not recommended:

<ul> <li v-for="user in users" v-if="user.isActive" :key="user.id"> {{ user.name }} </li></ul>
Copy the code

1.4 long list performance optimization

Vue hijacks data via Object.defineProperty to make the view respond to data changes. However, sometimes our component is purely a data presentation and nothing will change. We don’t need vue to hijack our data. This significantly reduces component initialization time, so how do we prevent VUE from hijacking our data? Freeze can be used to freeze an Object. Once the Object is frozen, it cannot be modified again.

export default{
 dat:()=>({
  users:{}
 }),
 async created(){
  const users = await axios.get("/api/users");
  this.users = Object.freeze(users)
 }
}
Copy the code

1.5. Destruction of events

When a VUE component is destroyed, it automatically cleans up its connections to other instances and unties all its instructions and event listeners, but only for the component’s own events. If addEventListener is used in js, it will not be automatically destroyed. We need to manually remove the listener of these events when the component is destroyed to avoid memory leaks. For example:

created(){
 addEventListener('click',this.click,false)
},
beforeDestroy(){
 removeEventListener('click',this.click,false)
}
Copy the code

1.6. Lazy loading of image resources

For pages with too many pictures, in order to accelerate the page loading speed, we often need to not load the pictures that do not appear in the visual area of the page, and then load them after scrolling to the visual area. This will greatly improve page loading performance and improve the user experience. We used vue’s vuE-Lazyload plugin in the project:

(1) Install the plug-in

npm install vue-lazyload --save-dev
Copy the code

(2) Import and use in the entry file main.js

import VueLazyload form 'vue-lazyload'
Copy the code

It is then used directly in VUE

Vue.use(VueLazyload)
Copy the code

Or add custom options

Vue.use(VueLazyload,{
 preLoad:1.3,
 error:'dist/error.png',
 loading:'dist/loading.git',
 attempt:1
})
Copy the code

(3) Change the SRC attribute of the IMG tag to V-lazy in the vue file, so that the image display mode is changed to lazy loading:

<img v-lazy="/static/img/1.png" >
Copy the code

Vue – LazyLoad GitHub address for vue- LazyLoad

1.7. Lazy route loading

Vue is a single-page application, which may have many routes imported. As a result, the file packed with Webpack is very large. When entering the home page, too many resources are loaded, and the page will appear white screen, which is not conducive to user experience. It would be much more efficient if we could split the components corresponding to different routes into different code blocks and then load the components only when the routes are accessed. This will greatly speed up the first screen, but may slow down the rest of the page.

Route lazy loading:

const Fooo = () => import('./Foo.vue')
const router = new VueRouter({
 routes:{
  path:'/foo',component:Foo
 }
})
Copy the code

1.8. Introduction of third-party plug-ins on demand

We often need to introduce third party plug-ins in a project. If we introduce the whole plug-in directly, it will cause the project to become too large. We can use babel-plugin-Component to reduce the size of the project by introducing only the required components. For example, introduce the element-UI component library into your project:

(1) Install the nanel-plugin-Component:

npm install babel-plugin-component -D
Copy the code

(2) Then change.babelrc to:

{ 
 "presets": [["es2015", { "modules": false }]], 
 "plugins": [[
   "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
]}
Copy the code

(3) Introduce some components in main.js:

import Vue from 'vue'; import { Button, Select } from 'element-ui'; Vue.use(Button) Vue.use(Select)Copy the code

1.9. Optimize infinite list performance

If your application has very long or infinitely scrolling lists, you may need to use windowing techniques to optimize performance, rendering only a few areas of content, reducing the time to re-render components and create DOM nodes. You can optimize this infinite list scenario by referring to the following open source projects vue-virtual-Scroll list and vue-virtual-scroller.

1.10. Server rendering SSR or pre-rendering

Server-side rendering refers to the process of Vue rendering the entire HTML fragment of the tag on the client side at the server side. The HTML fragment formed by the server side is directly returned to the client side. This process is called server-side rendering.

(1) Advantages of server-side rendering:

  • Better SEO: Because the content of SPA page is obtained through Ajax, and the search engine crawl tool does not wait for the completion of Ajax asynchronism before grabbing the page content, so the content of SPA page obtained through Ajax cannot be captured; SSR is directly returned by the server to the rendered page (data has been included in the page), so the search engine crawler can grab the rendered page;

  • Faster content arrival time (faster loading on the first screen) : SPA will wait for all Vue compiled JS files to be downloaded before rendering the page. File download takes a certain amount of time, so rendering on the first screen takes a certain amount of time. SSR directly returns the page rendered by the server directly, without waiting to download JS files and render again, so SSR has a faster content arrival time;

(2) Disadvantages of server-side rendering:

  • More development constraints: for example, server-side rendering only supports the beforCreate and Created hook functions, resulting in some external extension libraries requiring special handling to run in server-side rendering applications; And unlike fully static single-page application SPA, which can be deployed on any static file server, server-side rendering applications need to be in the Node.js server running environment;

  • More server load: Rendering a full application in Node.js is obviously more cpu-intensive than a server that just serves static files, so if you expect to use it in a high-traffic environment, prepare for the server load and use caching wisely.

If SEO and first screen rendering of your project are key metrics for evaluating your project, then your project will need server rendering to help you achieve the best initial load performance and SEO, specific Vue SSR. If your Vue project only needs to improve SEO for a few marketing pages (e.g. /, /about, /contact, etc.), then you may need to pre-render and simply generate static HTML files for specific routes at build time. The advantage is that it’s easier to set up pre-rendering and you can treat your front end as a completely static site, which you can easily add using the prerender-spa-plugin.

Second, optimization of Webpack level

2.1. Webpack compresses pictures

In the vue project, except the limit size can be set in the url-loader of webpack.base.conf.js to process images, and the images smaller than the limit can be converted to base64 format, the rest of the operation is not done. Therefore, for some large image resources, the loading will be very slow when the resource is requested. We can use image-webpack-loader to compress the image:

(1) First, install image-webpack-loader:

npm install image-webpack-loader --save-dev
Copy the code

(2) Then configure it in webpack.base.conf.js:

{ test: /\.(png|jpe? g|gif|svg)(\? . *)? $/, use:[ { loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { loader: 'image-webpack-loader', options: { bypassOnDebug: true, } } ]}Copy the code

2.2. Reduce redundant code from ES6 to ES5

The Babel plug-in will inject some helper functions when converting ES6 code to ES5 code, such as the following ES6 code:

class HelloWebpack extends Component{... }Copy the code

The following two helper functions are needed to convert this code into working ES5 code:

Babel - the runtime/helpers/createClass / / used to implement the class grammar Babel - the runtime/helpers/inherits / / used to implement the extends the syntaxCopy the code

By default, Babel will embed these dependent helper functions in each output file, and if multiple source files rely on these helper functions, the code for these helper functions will appear many times, causing code redundancy. In order not to let the auxiliary function code is repeated, can rely on them through the require (‘ Babel – the runtime/helpers/createClass) way to import, so you can do to make them appear only once. The babel-plugin-transform-Runtime plugin does this by replacing the relevant helper functions with import statements to reduce the file size of the code compiled by Babel.

(1) install babel-plugin-transform-runtime:

npm install babel-plugin-transform-runtime --save-dev
Copy the code

(2) Then modify the.babelrc configuration file to:

"plugins": [    "transform-runtime"]
Copy the code

For more details on the plug-in, see the babel-plugin-transform-Runtime description.

2.3. Extract common code

If the third party libraries and common modules for each page are not extracted from the project, the project will have the following problems:

  • The same resources are loaded repeatedly, wasting user traffic and server costs.

  • Too many resources need to be loaded on each page. As a result, the first screen of a web page loads slowly, affecting user experience.

So we need to separate common code from multiple pages into separate files to optimize the above problem. Webpack has built-in plugin CommonsChunkPlugin which is specially used to extract the common parts of multiple chunks. The configuration of CommonsChunkPlugin in our project is as follows:

// All packages that depend on package.json are packaged into vendor.js. new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function(module, count) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '.. /node_modules') ) === 0 ); }}), / / extract code module mapping new webpack.optimize.Com monsChunkPlugin ({name: 'the manifest, chunks: [' vendor']})Copy the code

For more details about the plug-in, see the CommonsChunkPlugin for more details.

2.4. Template precompilation

When using a template in the DOM or a string template in JavaScript, the template is compiled into a rendering function at run time. This is usually fast enough, but it is best avoided in performance-sensitive applications.

The easiest way to precompile a template is to use a single file component — the relevant build Settings take care of the precompilation automatically, so the built code already contains the compiled renderers instead of the original template strings.

If you use Webpack and prefer to separate JavaScript and template files, you can use vue-template-loader, which also converts template files into JavaScript rendering functions during build.

2.5. Extract the CSS of the component

When using a single-file component, the CSS within the component is dynamically injected through JavaScript in the form of a style tag. This has some small runtime overhead, and if you use server-side rendering, this will result in a “style-free content flicker” (FOUC). Extracting the CSS for all components into the same file avoids this problem and also allows CSS to be better compressed and cached.

Consult the build tool’s documentation to learn more:

  • Webpack + Vue-loader (vue-CLI webpack template has been pre-configured)

  • Browserify + vueify

  • Rollup + rollup-plugin-vue

2.6. Optimize SourceMap

After the project is packaged, we will package multiple files and codes under development into one file. After compression, removing redundant Spaces and Babel compilation, the compiled code will be used in the online environment. Then the code after such processing will be very different from the source code. We can only locate the compressed code, not the code in the development environment. It is bad for development to tune the problem, hence sourceMap, which is designed to solve the problem.

SourceMap has the following optional values (more + signs for faster speed, more – signs for slower speed, o for medium speed)

Cheap -module-eval-source-map

Recommended production environment: cheap-module-source-map

Here’s why:

  • Cheap: The column information in the source code is of no use, so we do not want the packaged file to contain column-related information, only the row information to establish the dependencies before and after the package. Therefore, in both development and production environments, we want to add the base type cheap to ignore column information before and after packaging;

  • Module: In both development and formal environments, we want to locate the source code of the bug. For example, a Vue file reported an error. We want to locate the Vue file, so we also need the Module configuration.

  • Soure-map: Source-map generates a separate Soucemap file for each packaged module, so we need to add the source-map attribute;

  • Eval-source-map: Eval is very fast to package code because it does not generate a map file, but you can use eval-source-map on an EVAL combination to store the map file as a DataURL in a packaged JS file. Do not use eval-source-map in a formal environment because it increases the file size, but in a development environment, try it out because they pack quickly.

2.7. Output analysis of construction results

The code output from Webpack was very unreadable and the files were very large, which gave us a headache. In order to analyze the output more easily and intuitively, a number of visual analysis tools have emerged in the community. These tools graphically present the results more visually, allowing us to quickly understand the problem. Let’s move on to the analysis tool we used in the Vue project: Webpack-bundle-Analyzer.

We configure webpack.prod.conf.js in the project

if (config.build.bundleAnalyzerReport) { var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; webpackConfig.plugins.push(new BundleAnalyzerPlugin()); }Copy the code

Generate an analysis report after executing $NPM run build \–report

2.8 compilation and optimization of Vue project

If your Vue project uses Webpack compilation and it takes you a cup of coffee, you may need to optimize your project’s Webpack configuration to make Webpack builds more efficient.

Third, basic Web technology optimization

3.1. Enable Gzip Compression

Gzip is the abbreviation of GNUzip. It was first used for file compression in UNIX systems. Gzip encoding over THE HTTP protocol is a technique used to improve the performance of Web applications, and both web servers and clients (browsers) must support GZIP. Chrome, Firefox and Internet Explorer all support this protocol. Common servers such as Apache, Nginx, IIS also support gzip compression efficiency is very high, usually can reach 70% compression rate, that is, if your web page has 30K, after compression becomes about 9K

The following uses the familiar Express server as an example to enable Gzip. The steps are as follows:

  • Installation:

    npm install compression –save

  • Add code logic:

    var compression = require(‘compression’); var app = express(); app.use(compression())

  • Restart the service and observe the Response header in the network panel. If you see the following fields in the red circle, it indicates that GZIP is enabled successfully:

3.2. Browser cache

In order to improve the user load page speed, it is very necessary to cache static resources, according to whether to re-initiate a request to the server to classify, the HTTP cache rules are divided into two categories (mandatory cache, comparison cache), if you do not understand the cache mechanism is very clear, You can refer to the author’s article on HTTP caching, “In-depth understanding of HTTP caching mechanisms and principles,” which will not be covered here.

3.3. Use of CDN

When a browser downloads CSS, JS and images from a server, it has to connect to the server. Most servers have limited bandwidth. CDN can load files through different domain names, so that the number of concurrent connections to download files is greatly increased, and CDN has better availability, lower network delay and packet loss rate.

3.4 use Chrome Performance to find Performance bottlenecks

Chrome’s Performance panel records js execution details and times over a period of time. To analyze page performance using Chrome Developer Tools, perform the following steps.

  1. Open Chrome Developer Tools and switch to the Performance panel

  2. Click Record to start recording

  3. Refresh the page or expand a node

  4. Click Stop to Stop recording

This paper consists of the following three parts: optimization of Vue code level, optimization of Webpack configuration level, optimization of basic Web technology level; To show you how to optimize the performance of Vue projects. (This article quotes from the front-end development of the public number, do learning record).