Recently, I have been in contact with the management system at the b-end of my work, which basically uses Vue Cli to generate scaffolding and then directly starts to write business logic, so I generally ignore some ideas and work related to performance optimization. Although the front-end requirements of this system are generally relatively simple, most of which are some data verification and visual display, the workload may focus on business logic, but as a front-end project, the basic optimization still needs to be done, you can refer to this article.

This article will introduce some performance optimizations based on Vue Cli projects that have been overlooked, especially the first screen optimizations. If they are helpful, please like them.

The UI library is loaded on demand

For most B-side systems, there are some UI component libraries, such as Ant Design or Element UI. These components can be imported on demand. When using these components, if only part of them are used, we can configure loading on demand and modify the code in main.js:

import {
    Pagination,
    Icon,
    Tabs,
} from 'ant-design-vue'
// import 'ant-design-vue/dist/antd. CSS 'is already introduced via Babel, but not globally

Vue.use(Pagination)
    .use(Icon)
    .use(Tabs)
Copy the code

Then modify babel.config.js as follows:

  "plugins": [["import", { "libraryName": "ant-design-vue"."libraryDirectory": "es"."style": "css"}].// 'style: true' will load less files

  ]
Copy the code

In this way, the component’s corresponding JS and CSS files can be loaded on demand. For configuration of babel.config.js, refer to the previous article.

Analyze packaged resource bundles using Webpack-bundle-Analyzer

Webpack-bundle-analyzer is a Webpack plug-in, which can intuitively analyze the contents of packed files, the proportion of size, the relationship between modules, dependencies, whether files are repeated, and the size after compression. Based on these, we can perform file segmentation. Is the basis for our analysis of resource pack size later.

// Analyze the package contents
npm install webpack-bundle-analyzer --save-dev
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 
module.exports = { 
plugins: [ 
/ / open BundleAnalyzerPlugin
      new BundleAnalyzerPlugin(), 
    ], 
};   

Copy the code

After the configuration is complete, only NPM run build is required. http://127.0.0.1:8888/ is automatically opened

Route lazy loading

For large b-end management system projects, Vue Router is generally used to manage routes. These projects involve a large number of pages. Therefore, in order to prevent the first screen resources from being too large, we need to adopt route slouch loading resources, namely Code Splitting, to separate resources on each page. This can only be configured in router.js:

// Use arrow functions and import for lazy loading
component: () = > import('./index.vue')
Copy the code

Use prefetch and preload selectively

prefetch

<link rel="prefetch" ></link>
Copy the code

This code tells the browser that the resource will be used in some future navigation or function, but that the download order weight of the resource is low. That is, Prefetch is usually used to speed up the next navigation, not this one.

preload

<link rel="preload" ></link>
Copy the code

Preload is usually used for key resources used in the page, including key JS, fonts, and CSS files. Preload will increase the load order weight of resources, so that key data can be downloaded in advance, optimize the speed of page opening.

In the project generated using the Vue Cli, when we configure the route lazy load, by default WebPack builds for all lazy load resourcesprefetchandpreload, so when you open up the home page, you’ll see plenty ofprefetchandpreloadRequest, as shown below:Though prefetch will in your leisure time in a browser, download the corresponding file, but this is a very general definition, these large preload resources will take up the resources of the browser, can lead to some key API request or picture, so in this case, you can choose to specify some resources for preload or prohibit the preload, The code is as follows:

// Disable prefetch and preload
chainWebpack: (config) = > {
  config.plugins.delete('prefetch')
  config.plugins.delete('preload')}// Select prefetch and preload
config.plugin('prefetch').tap(options= > {
    options[0].fileBlacklist = options[0].fileBlacklist || []
    options[0].fileBlacklist.push(/myasyncRoute(.) +? \.js$/)
    return options
})
Copy the code

The code above modifies the chainWebpack of vue.config.js to add configuration.

Split node_modules

For large b-side management system projects, it is common to use some UI component libraries, chart libraries and other third-party libraries. These third-party libraries are generally installed under node_modules through NPM, and most of the pages will use these libraries, so it will be introduced in main.js:

Vue.use(Antd)
Vue.use(Echarts)

Copy the code

When you pack, WebPack pulls these common modules out and puts them into a common module. No matter how many entries the module is referenced by, it will only show up once in the final package result to eliminate code redundancy.

This has been done automatically for us in projects using the Vue Cli, mainly using the optimization.splitchunks configuration, but when we heap these common modules together in a single module, the file can be very large (usually app.js, which is loaded on the front screen, The larger the file, the more common third-party libraries are referenced), is also detrimental to network requests and page loads.

So we need to split this public module into several module files according to certain rules, reduce the size of the file, but also can take advantage of HTTP2 multiplexing features, these need to configure our own code as follows:

  config.optimization.splitChunks.cacheGroups.antdv = {
      name:'chunk-antdv'.// The name of the module to be removed
      priority: 20./ / priority
      test: /ant-design-vue/,
      chunks: 'initial'.reuseExistingChunk: true.enforce: true // Force the module to be removed
  }
  config.optimization.splitChunks.cacheGroups.antdv = {
    name:'chunk-echarts'.// The name of the module to be removed
    priority: 20./ / priority
    test: /echarts/,
    chunks: 'initial'.reuseExistingChunk: true.enforce: true // Force the module to be removed
}
Copy the code

In vue.config.js, modify the configureWebpack TAB to add configuration, and separate the ant-Design-Vue and Echarts library files from app.js into a separate package.

For the configuration of optimization.splitchunks, please refer to this document. Here is a brief explanation of the configuration:

  1. eachcacheGroupsRepresents the third party libraries that need to be pulled out, two of which are Ant-Design-Vue and Echarts.
  2. testItem indicates what to scannode_modulesFile path, here the simple use of re to match.
  3. chunksItem has three options:all.async.initial.initialRepresents the common pull-out responsible for loading asynchronous and non-asynchronous modules,asyncRepresents a public pull-out that is only responsible for loading asynchronous modules,allCombine the first two characteristics.

Customize the resource file loading location

For projects created using the Vue Cli, CSS is not deliberately modified. The loading order of JavaScript files, for example, by default WebPack puts CSS inside the tag and JavaScript files at the bottom of the tag, so, Sometimes we introduce some third-party JavaScript files at the bottom of the tag, such as jquery or amap API files, as follows:

  <body>
    <div id="app"></div>
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=c65f481aebaed72935e11654238ab5a6"></script>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <! -- built files will be auto injected -->
  </body>
Copy the code

We know that when a browser parses HTML, it will download and parse non-asynchronous resources, especially JavaScript files, so the first it loads, the first it parses. By default, after the project is built, The core JavaScript files of the business will be loaded behind these third-party JavaScript files, which will have a certain impact on the display of the first screen.

To solve this problem, you need to modify the html-webpack-plugin configuration and manually customize the loading location of the file in index.html as follows:

  config.plugin('html')
  .tap(args= > {
    args[0].inject = false
    return args
  })
Copy the code
<% for (var css in htmlWebpackPlugin.files.css) { %>
  <link href="<%=htmlWebpackPlugin.files.css[css] %>" rel="stylesheet">The < %} % >... <% for (var chunk in htmlWebpackPlugin.files.chunks) { %><script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>The < %} % >Copy the code

In this way, the loading priority of some important first-screen resources can be increased, and the loading speed of the first screen can be optimized in certain cases.

PrerenderSpaPlugin First screen pre-render

For most B-side systems, most of them are a one-page application SPA developed by Vue, so the content of the first screen basically relies on JavaScript for rendering, which not only depends on the loading of JavaScript file resources, but also is not conducive to SEO (probably most B-side systems do not need SEO, But do not rule out some welcome page or brand homepage similar pages have SEO needs).

PrerenderSpaPlugin is a Webpack plug-in that prepackages pages as static resource pages and uses vue-Router to configure specific pages based on routing. The PrerenderSpaPlugin works as follows:

Based on this, we can modify vue.config.js to add PrerenderSpaPlugin support as follows:

npm install prerender-spa-plugin --save-dev
const PrerenderSpaPlugin = require('prerender-spa-plugin')...new PrerenderSpaPlugin({

  staticDir: resolve('dist'),
  // Corresponding to its own routing file. For example, if a has parameters, write it as /a/param1.
  routes: ['/login'.'/about'],}).Copy the code

In the above code, the /login and /about routes are preloaded. After project dist, you can see two independent HTML files. After some nginx configuration, you can directly forward the corresponding path to the corresponding static page. More information about PrerenderSpaPlugin can be found in configuration.

Image compression

By default, the project created by Vue Cli will not carry out secondary compression of some image resources introduced in the project. If some large images are introduced and there are too many images, the package after Dist will become very large. At this time, image-webpack-loader can be used to enable image compression configuration. Add image-webpack-loader as follows:

npm install image-webpack-loader --save-dev
...
config.module
    .rule('images')
    .use('image-webpack-loader')
    .loader('image-webpack-loader')
    .options({ bypassOnDebug: true })
    .end()
Copy the code

Js chainWebpack is modified to add configuration. Image-webpack-loader starts with webpack loader developed by Imagemin and can support lossless and lossy compression.

conclusion

For most B-side systems, they may pay more attention to the implementation of complex business logic, but they may also neglect some basic performance optimization. For the whole system, good user experience makes the system more robust, which is also the achievement of a front-end engineer.