How to Boost Vue.js Performance

March 18, 2019

Avoid Unnecessary Network Payloads

Reducing the total size of network requests speeds up page load time and saves your users money that they would have spent on cellular data. — Google

When we first start SPA projects in Vue, usually we quickly prepare the project skeleton and the development environment with CLI 3.0 (https://cli.vuejs.org/) and start creating pages and components.

With some of the tasks done, we continue to develop the pages. Consequently, they increase in size. The components we put on those pages rise gradually. But in the background, there is one more thing that has an increase that we don’t usually think about. That’s our bundle file.

Have you thought of the possibility that your users will not even access that page? Or the possibility of not fulfilling the requirements of the components you render under a particular condition. Most of the modal you’ve created is perhaps never to be seen.

We send all these redundant codes to our users. Whereas, the user wanted to view only a single page.

Ok.. Well what can we do?

First of all.. Code splitting and lazy loading

By applying both route-based and component-based code splitting and lazy loading, we can split our bundle file into small chunks.

To achieve this with vue-router (https://router.vuejs.org/guide/advanced/lazy-loading.html), we can import our pages with this special syntax instead of importing them directly.


const router = new VueRouter({
routes: [
{
path: '/foo',
component: () =>
import(/* webpackChunkName: "foo" */ '@/views/foo'),
}
]
});

webpackChunkName is a special keyword. Sometimes we want to combine a few pages or components under the same chunk. The webpack will recognize this keyword and combine pages and components with the same name under the same chunk.

In the components we render conditionally:




We can use it like this. This component is included as soon as the condition has been met. It will not be included until then. The user will thus have downloaded the code of this component only when the condition met.

The example above explains a lot, but my point is that you can develop a multi-role application. If you are developing an application that has multiple roles, the importance of splitting your code becomes even more important.

Let’s say you have a 3-roll system, Client, Admin, and Guest.

If we hadn’t split our code, the user would have downloaded the code belonging to all roles regardless of his/her role. Besides the issue of generating a large-sized file with excessive, unnecessary code, it is also a security breach.


import Vue from 'vue';
import BootstrapVue from 'bootstrap-vue';

Vue.use(BootstrapVue);

You can use it in this way:


import {
Modal,
Table,
Pagination,
Button,
Layout,
} from 'bootstrap-vue/es/components';

import bTooltipD from 'bootstrapvue/es/directives/tooltip/tooltip';

[Modal, Table, Pagination, Button, Layout].forEach(comp => {
Vue.use(comp);
});

Vue.directive('b-tooltip', bTooltipD);

Or using lodash-es (https://www.npmjs.com/package/lodash-es) instead of lodash (https://www.npmjs.com/package/lodash).

You can search the support of other libraries you use. This also means that many code that will not be used will not be sent to the user.

After doing this, both our JavaScript and CSS code will be separated in a similar way as in the following structure:

You can use the “vue-cli-service build - report” to get this report.

Yeah, I used lodash instead of lodash-es. I haven’t touched it yet. Because I’m the guy I mentioned at the beginning of the article 🙂 I’m thinking of changing it soon.

If you have noticed here, our ‘chunk-vendors’ file also has a large size. If you want to do something about this, you can go to this setting in our vue.config.js file based on this article (https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758) by David Gilbertson (https://hackernoon.com/@david.gilbertson).


module.exports = {
...
configureWebpack: {
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
return `npm.${packageName.replace('@', '')}`;
},
},
},
},
},
},
...
};

This will create separate chunks for our npm (https://www.npmjs.com/) packages:


After splitting vendor file.

However, it is useful to consider the interpretation (https://medium.com/@TheLarkInn/hey-david-b6649337d331) of Sean T. Larkin (https://medium.com/@TheLarkInn) from the Webpack team.

Finally.. Bundle

If we compile our code with legacy browser support, why should we want to send those compiled code with redundant legacy support functionality to modern browsers that support native ES2015?

Fortunately, with Vue’s ‘Modern Mode (https://cli.vuejs.org/guide/browser-compatibility.html#modern-mode)’ option, we can easily solve this problem without the need for any special development.

Just pass the ‘modern’ flag vue-cli-service build –modern to the build script . That’s all. What about the results?

For a Hello World app, the modern bundle is already 16% smaller. In production, the modern bundle will typically result in significantly faster parsing and evaluation, improving your app’s loading performance.