编程知识 cdmana.com

Performance optimization of Vue project

Made quite a few vue project , There are also many problems in the development process , To sum up ,

Vue The code level

1、v-for Traversal should be item add to key, And avoid simultaneous use v-if

(1) The official recommendation v-for Traversal should be item add to key attribute

When the list data is traversed and rendered , Need for each item item Set up the only key value , convenient Vue.js Internal mechanism accurately finds the list data . When state update , Compare the new state value with the old one , Quickly navigate to diff .

(2) Official statement v-for Traversal avoid using at the same time v-if

v-for Than v-if High priority , If you have to traverse the entire array every time , Because of the intermediate calculation, the contrast will affect the rendering speed , Especially when it needs to render a small part of it , If necessary, it can be replaced with computed attribute .

recommend :

<ul>
  <li
     v-for="book in books"
     :key="book.id">
     {{ book.name }}
 </li>
</ul>
computed: {
  activeBooks: function () {
    return this.books.filter(function (book) {
        return book.isActive
    })
  }
}

Not recommended :

<ul>
  <li
     v-for="book in books"
     v-if="book.isActive"
     :key="book.id">
     {{ book.name }}
  </li>
</ul>

Be careful : If you have to use it, you can use template Wrap it up

<ul>
  <template v-for="book in books" :key="book.id">
      <li v-if="book.isActive">
         {{ book.name }}
      </li>
  </template>
</ul>

2、computed and watch

computed: It's computational properties , Depend on other property values , also computed The value of has cache , Only the property value it depends on changes , Next acquisition computed Will be recalculated computed Value
  • When we need to do numerical calculations , And depend on other data , You should use computed, Because it can be used computed Cache properties for , Avoid every time you get a value , All have to be recalculated . For example, in the form operation , When the input or selection value changes , Other values are changed in linkage .
watch: Is more of a 「 Observe 」 The role of , Similar to some data monitoring callbacks , Whenever the monitored data changes, a callback will be executed for subsequent operations
  • When we need to perform asynchronous or expensive operations when data changes , You should use watch, Use watch Option allows us to perform asynchronous operations ( Visit one API ), Limit how often we do this , And before we get the final result , Set intermediate state . These are all things that computational properties can't do .

3、v-if and v-show

v-if  yes   real   Conditional rendering , Because it ensures that the event listeners and child components within the condition block are properly destroyed and rebuilt during the switch ; It's also The inertia of the : If the condition is false at the initial render , And do nothing —— Until the condition is true for the first time , Before the condition block is rendered .

v-show  It's much simpler , Whatever the initial conditions are , Elements are always rendered , And simply based on CSS Of display Property to switch .

therefore ,v-if It is applicable to conditions that are rarely changed during operation , Scenes that do not need to switch conditions frequently ;v-show It is suitable for scenarios that require very frequent switching conditions , such as tabs Component switching .

4、 Long list performance optimization

Vue Will pass Object.defineProperty Hijack data , To implement the view response to data changes , However, sometimes our components are pure data presentation , There will be no change , We don't need it Vue To hijack our data , In the case of a large amount of data , This can significantly reduce the time of component initialization , Then how to prohibit Vue Hijacking our data ? Can pass Object.freeze Method to freeze an object , Once frozen objects can no longer be modified .

export default {
  data: () => ({
    books: []
  }),
  async created() {
    const books = await axios.get("/api/books");
    this.books = Object.freeze(books);
  }
};

5、 Optimize infinite list performance

If your app has a very long or infinite scrolling list , So we need to adopt “ Windowing ” Technology to optimize performance , Only a few areas need to be rendered , Reduce re rendering of components and creation dom Node time .window.requestAnimationFrame Method to set the function of delayed loading Click to see an example
Or you can refer to vue-virtual-scroll-list and vue-virtual-scroller Project approach ,
Or, for example ElementUI, In this way UI The frame has a separate infinite scrolling list component

6、 Global events are manually destroyed , Avoid memory leaks

We are .vue The event of file registration will be in vue Components are automatically removed when they are destroyed ,. But if <script> The global event definition method is used in the tag window.addEventListener To register Events , Consider possible memory leaks , So it is recommended that .vue Manually delete files when they are logged out

beforeDestroy() {
  removeEventListener('click', this.handleClick, false)
}

7、 Lazy loading of picture resources

For pages with too many pictures , To speed up page loading , So a lot of times we need to not load the pictures that do not appear in the visual area in the page first , Wait until you scroll to the visible area before loading . This will greatly improve the page loading performance , It also improves the user experience . Used in projects Vue Of vue-lazyload plug-in unit :

(1) Installing a plug-in

npm install vue-lazyload --save-dev;

(2) At the entrance file man.js To introduce and use

import VueLazyload from 'vue-lazyload';

stay vue Use in

Vue.use(VueLazyload);
//  Or add custom options 
Vue.use(VueLazyload, {
    preLoad: 1.3,
    error: 'dist/error.png',
    loading: 'dist/loading.gif',
    attempt: 1
});

(3) stay vue file img Labeled src Property is changed to v-lazy , In this way, the image display mode is changed to lazy loading display :

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

8、 Road load by lazy , Components are introduced on demand

Vue It's a single page app , There may be many routing entries , Use this way webpcak The packed file is big , When entering the home page , Too many resources loaded , There will be a white screen on the page , Bad for user experience . If we can divide the components corresponding to different routes into different code blocks , Then load the corresponding components when the route is accessed , It's more efficient . This will greatly improve the speed of the first screen , But maybe other pages will slow down .

Road load by lazy :

const Foo = () => import('./Foo.vue');
const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
});

A kind of aided design , More flexible control of routing ( Black and white list mode ), Unified processing of files within the folder ,concat All routing information

const files = require.context('.', true, /\.js$/);

var subRouters = [];

files.keys().map((key) => {
    if (key === './index.js') return;
    // console.log(files(key).default);
    subRouters = subRouters.concat(files(key).default);
});
export default subRouters;

9、 On demand introduction of third-party plug-ins

Very common configuration , For example, we think there are UI The component does not satisfy , To quote something else UI A single component of a library , Introduction on demand is a must for project creation
(1) install  babel-plugin-component :

npm install babel-plugin-component -D

(2) With elementUI For example , take .babelrc It is amended as follows :

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

(3) stay main.js Introduce some components as needed :

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

10、 Server rendering SSR or pre-render

Server side rendering refers to Vue Render the whole tag on the client side html The work of the segment is completed on the server , Formed by the server html This process is called server rendering .

Server rendering :

(1) Advantages of server-side rendering :

  • better SEO: because SPA The content of the page is through Ajax obtain , And search engine crawling tools don't wait Ajax After asynchronous completion, the content of the page can be retrieved , So in SPA Is not able to grab the page through Ajax What you get ; and SSR It is to return the rendered page directly from the server ( Data is already included in the page ), So search engine crawler can grab the rendered page ;
  • Faster content arrival time ( Faster first screen loading ):SPA Will wait for all Vue The compiled js After all files are downloaded , To start rendering the page , File download and so on need a certain time and so on , So the first screen rendering takes a certain amount of time ;SSR Render the page directly from the server and return to the display directly , No need to wait for download js File and re rendering, etc , therefore SSR Faster content arrival time ;

(2) Disadvantages of server-side rendering :

  • More development constraints : For example, server-side rendering only supports beforCreate and created Two hook functions , This will cause some external extension libraries to need special handling , In order to run in the server rendering application ; And with a fully static single page application that can be deployed on any static file server SPA Different , Server rendering application , Need to be in Node.js server Running environment ;
  • More server load : stay Node.js Render the complete application , Obviously it's better than just providing static files server More occupation CPU resources , So if you expect to use it in a high traffic environment , Please prepare the corresponding server load , And adopt the caching strategy wisely .

pre-render :

If your project's SEO and The first screen rendering is the key index to evaluate the project , Then your project needs server-side rendering to help you achieve the best initial loading performance and SEO. If your Vue The project only needs to improve a few marketing pages ( for example /about, /contact etc. ) Of SEO, Then you may need pre-render , At build time (build time) Simply generate static for a specific route HTML file . The advantage is that setting up pre rendering is simpler , And you can use your front end as a completely static site .

Use prerender-spa-plugin You can easily add settings to pre render .

Webpack Level optimization

1、Webpack Compress the picture

2.1、Webpack Compress the picture

stay vue In addition to the project can be in  vue.config.js  in url-loader Set in limit Size to handle the picture , For less than limit The picture of is transformed into base64 Format , The rest do not operate . So for some larger image resources , When requesting resources , Loading will be slow , We can use  image-webpack-loader To compress pictures :

(1) Install first image-webpack-loader :

npm install image-webpack-loader --save-dev

(2) stay vue.config.js To configure :

{
  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,
      }
    }
  ]
}

2、 Reduce ES6 To ES5 Redundant code for

Babel The plug-in will ES6 Code to ES5 Code will inject some auxiliary functions , For example, the following ES6 Code :

class HelloWebpack extends Component{...}

This code is then converted into something that works ES5 The code needs the following two auxiliary functions :

babel-runtime/helpers/createClass  //  Used to implement  class  grammar 
babel-runtime/helpers/inherits  //  Used to implement  extends  grammar 

By default , Babel These dependent auxiliary function codes are embedded in each output file , If multiple source files depend on these helper functions , Then the code of these auxiliary functions will appear many times , Causes code redundancy . In order not to let the code of these auxiliary functions repeat , You can rely on them through  require('babel-runtime/helpers/createClass')  How to import , So you can make them appear only once .babel-plugin-transform-runtime  Plugins are used to do this , Replace relevant auxiliary functions with import statements , Thereby reducing babel The file size of the compiled code .

(1) Install first  babel-plugin-transform-runtime :

npm install babel-plugin-transform-runtime --save-dev

(2) modify .babelrc The configuration file is :

"plugins": [
    "transform-runtime"
]

3、tree-sharking

webpack5 Yes tree-shaking The friendliness of the support is exciting , about webpack4 It's basically enough , Don't talk too much nonsense , It's necessary for the production environment , Add it up !!!

4、 Extract public code

If the third-party library and common modules of each page are not extracted in the project , Then the project will have the following problems :

  • The same resources are loaded repeatedly , Waste user traffic and server costs .
  • Each page needs to load too many resources , The first screen load of the web page is slow , Impact on user experience .

So we need to separate the common code of multiple pages into separate files , To optimize the above .Webpack Built in for extracting multiple Chunk Plugins for the public part of CommonsChunkPlugin, We are in the project CommonsChunkPlugin The configuration is as follows :

//  All in  package.json  It depends on the package , Will be packed into  vendor.js  In this file .
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 the mapping relationship of code modules 
new webpack.optimize.CommonsChunkPlugin({
  name: 'manifest',
  chunks: ['vendor']
})

5、 Template precompile

When using DOM Internal formwork or JavaScript When the string template inside , The template is compiled at run time as a rendering function . Usually the process is fast enough , But performance sensitive applications are best avoided .

The easiest way to precompile a template is to use a single file component —— The relevant build settings will automatically pre compile , So the built code already contains the compiled rendering function instead of the original template string .

If you use webpack, And like to separate JavaScript And template files , You can use vue-template-loader, It can also convert template files into JavaScript Rendering function .

6、 Extract component's CSS

When using a single file component , Components within the CSS Will style Label the way through JavaScript Dynamic Injection . There's a little runtime overhead , If you use server-side rendering , This will lead to a period of “ No style content flicker (fouc) ” . Put all components of CSS Extracting to the same file can avoid this problem , Will also let CSS Better compression and caching .

vue-cli Of webpack The template has been pre configured

7、 Optimize SourceMap

After the project is packaged , It will package multiple file codes in development into one file , And compressed 、 Remove the extra space 、babel After compiling , Finally, the compiled code will be used in the online environment , So there will be a big difference between the processed code and the source code , When there is bug When , We can only locate the code after compression , Unable to locate code in development environment , For development, it is not easy to locate the mode , therefore sourceMap There is , It is to solve the problem of bad modulation code .

SourceMap The optional values of are as follows (+ More numbers , Represents the faster ,- More numbers , The slower the speed , o For medium speed )
image

 Development environment recommendation :cheap-module-eval-source-map

 Recommended production environment :cheap-module-source-map

Here's why :

  • cheap: The column information in the source code has no effect , So we don't want the packed file to contain column related information , Only the row information can establish the dependency relationship before and after packing . So whether it's a development environment or a production environment , We all want to add cheap The basic type to ignore the column information before and after packing ;
  • module : Whether it's a development environment or a formal environment , We all want to be able to locate bug The specific location of the source code , For example, some Vue The document is wrong , We want to be specific Vue file , So we also need module To configure ;
  • soure-map :source-map It will generate independent modules for each packaged module soucemap file , So we need to increase source-map attribute ;
  • eval-source-map:eval Packing code is very fast , Because it doesn't make map file , But you can eval Use a combination of eval-source-map Use will map Document to DataURL The form exists in packaged js In file . Don't use... In a formal environment eval-source-map, Because it increases the size of the file , But in the development environment , You can try it out , Because they pack fast .

8、 Output analysis of construction results

Webpack The output code is very readable and the file is very large , It gives us a headache . For the sake of simplicity 、 Visually analyze the output , There are many visual analysis tools in the community . These tools graphically show the results more directly , Let's quickly understand the problem . Analysis tools :webpack-bundle-analyzer .

We are in the project  vue.config.js  To configure :

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

perform  $ npm run build --report  After the analysis report is generated

Unified optimization

1、 Browser cache

In order to improve the speed of loading pages , It is necessary to cache static resources , Classify according to whether the request needs to be reissued to the server , take HTTP There are two types of caching rules ( Mandatory cache , Compare cache )

2、CDN Use

Static external file is too large , Consider using stable CDN Services to load resources , Reduce the volume of the project

stay vue.config.js Add the following configuration to the configuration

configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      // config.plugins.push(new BundleAnalyzerPlugin())
      config.externals = {
        lodash: '_',
        vue: 'Vue',
        'vue-router': 'VueRouter',
        vuex: 'Vuex',
        'element-ui': 'ELEMENT',
        axios: 'axios',
        highcharts: 'Highcharts',
        echarts: 'echarts',
        'v-charts': 'VeIndex',
        sortablejs: 'Sortable'
      }
    } else {
      config.plugins.push(
        new HardSourceWebpackPlugin({
          cacheDirectory: '../.cache/hard-source/[confighash]'
        })
      )
    }
  }

First in index.html The file import CDN file ( Including supporting js and css file ), And then in main.js File to import the relevant components

<link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.8.2/theme-chalk/index.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/v-charts/lib/style.min.css">


<script src="https://cdn.bootcss.com/vue/2.6.10/vue.runtime.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.8.2/index.js"></script>
<script src="https://cdn.bootcss.com/highcharts/7.1.1/highcharts.js"></script>
<script src="https://cdn.bootcss.com/highcharts/7.1.1/highcharts-3d.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js"></script>

3、Chrome Performance Find performance bottlenecks

Chrome Of Performance The panel can record... For a period of time js Execution details and time . Use Chrome The steps for developer tools to analyze page performance are as follows .

  1. open Chrome Developer tools , Switch to Performance panel
  2. Click on Record Start recording
  3. Refresh the page or expand a node
  4. Click on Stop Stop recording

版权声明
本文为[Master of Wannian Da Ye Yi]所创,转载请带上原文链接,感谢

Scroll to Top