Author: enhancement of night The original address: segmentfault.com/a/119000001…

preface

I did a blog with Vuecli earlier. It was a single page project with about 10 routes packaged directly into NPM Run build and a huge JS file of 1M

Let’s just mount it to the server and try it boy it’s been loading for like half a century

It took 8s to load that big file. This has to be optimized. No user can tolerate 9s of blank screen without closing the page

In the process, I also migrated the project from Vuecli 2.x to Vuecli 3, so I’ll cover some of the similarities and differences in optimization

Analysis of the

Vuecli 2.x comes with an analysis tool just run NPM Run build –report

For Vuecli 3, install the plug-in first

NPM intall webpack – bundle – analyzer – save – dev

Then configure webPack in vue.config.js

chainWebpack: (config) => {/* Add analysis tools */ if (process.env.node_env === 'production') {if (process.env.npM_config_report) {config .plugin('webpack-bundle-analyzer') .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin) .end(); config.plugins.delete('prefetch') } } }Copy the code

Then run NPM run build –report

! Note: For very old projects may not run successfully, please refer to Baidu for specific methods.

A project packaging diagram opens in the browser to visually compare the size of individual bundles

You can see that all the dependencies in the project, all the routes, are packaged into the same file

Alternatively, in the browser, converge to see how the code is being used

The red ones are the ones that are downloaded but not used

Route lazy loading

JavaScript packages can become very large when packaged to build applications, affecting page loads. 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.

It is obviously not appropriate to download all the component files corresponding to the route in the first place. It is like downloading an app, so we need to use lazy route loading

In the router.js file, the original static reference

import ShowBlogs from '@/components/ShowBlogs'

routes:[ path: 'Blogs', name: 'ShowBlogs', component: ShowBlogs ]
Copy the code

Instead of

routes:[ path: ‘Blogs’,name: ‘ShowBlogs’,component: () => import(‘./components/ShowBlogs.vue’)

Dynamically imported as a function so that the respective routing files can be packaged separately and the routing components are downloaded only when a given route is parsed

The file that needs to be loaded on the first screen turns into the orange part, which is shunted out by the boys for 300K

If it is in vuecli 3, we need to do more work step Because vuecli 3 default open prefetch (preloaded module), early get the user may access the contents of the future This a dozen routing file on the first screen will, are downloaded at a stretch So we have to close the function, Set in vue.config.js

Refer to the official website:

Once set up, the first screen will load only the components of the current page route

Element-ui loads on demand

The first screen needs to be loaded with dependencies, of which element-UI takes up 568K of the entire package.

import ElementUI from ‘element-ui’

Vue.use(ElementUI)

But the only components I’m really using are buttons, pagination, tables, input and warnings so we’ll reference them as needed:

import { Button, Input, Pagination, Table, TableColumn, MessageBox } from ‘element-ui’;

Vue.use(Button)

Vue.use(Input)

Vue.use(Pagination)

Vue.prototype.$alert = MessageBox.alert

Notice the difference in MessageBox registration methods, and we use alert, but we don’t need to introduce an alert component

Add to the. Babelrc file (vue-cli 3 requires babel-plugin-component) :

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

The element-UI is much smaller, but when we see the table.js, we realize that the table component is only used by the admin page and does not need global registration, so we remove the references to the table and TablColumn in main.js and register them locally in the background component

 import { Table, TableColumn } from "element-ui";

components: {
    "el-table": Table,
    "el-table-column": TableColumn },
    
Copy the code

The table is split into a routing file

Component repackaging

As you can see in the figure above, there are two routing files that reference codemiror.js and cause repeated downloads. We can modify the CommonsChunkPlugin configuration in the webpack config file

minChunks: 3

Changing 3 to 2 will pull out packages that have been used twice or more and put them into a public dependency file, but since the home page also has reusable components, it will also download this public dependency file

Home page download yellow and gray part of the tear down along while, back to the origin

Of course, we could keep fidgeting with the CommonsChunkPlugin configuration to solve this problem, but in the new webPack, the CommonsChunkPlugin is replaced by SplitChunksPlugin, which is more flexible and advanced

This is why I migrated the project to vuecli 3 (using webpack4) which is optimized by default and only downloads the gray section on the home page (235K)

gzip

After unpacking, we will use gzip to install compression-webpack-plugin

nmp i compression-webpack-plugin -D

Introduce and modify the WebPack configuration in vue.config.js

const CompressionPlugin = require('compression-webpack-plugin') configureWebpack: (config) => {if (process.env.node_env === 'production') {// Modify configuration for production environment... Config. Mode = 'production' return {plugins: [new CompressionPlugin ({test: / \. Js $| \. HTML $| \. CSS /, / / matching filename threshold: DeleteOriginalAssets: false})]}}Copy the code

You can see that files over 200K are compressed down to 100K

On the server we’re going to have to configure that if the browser that’s sending the request supports GZIP, we’re going to send it a GZIP file and my server is built with the Express framework and you can use Compression if you install compression

const compression = require(‘compression’)

app.use(compression())

Note that this last sentence precedes all other middleware registrations

The final result

The first screen loads 198K resources, taking 1s to load, which is 90% faster than the original speed

Postscript: Whether to split the CSS

Another difference between Vuecli 3 and Vuecli2. x is that vuecli 3 will enable a CSS ExtractTextPlugin by default. The CSS files of each module will be separated, a total of 13 CSS files, and our home page requested four. We can turn it off in vue.config.js

CSS: {extract: false, // enable CSS source maps? SourceMap: false, // CSS preset configuration item loaderOptions: {}, // enable CSS modules for all CSS/pre-processor files.modules: false},Copy the code

Pack out file, directly without the CSS folder Instead, integrate a js file, is responsible for all injection style from the start First screen load file number decreases, but the volume is larger, eventually down speed not too big difference So, split on whether to CSS, specific project specific analysis

conclusion

Performance tuning is a very enjoyable process, but it’s also a pit, and there’s so much going on here that I hope this article will help you out