How to Speed up performance with Vue.JS

Avoid Enormous 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+ and start creating pages and components.

Then we continue to develop with this acceleration. Our pages increase, the components we put on those pages multiply. But in the background, there is one more thing we forget about the increase in size. 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 certain condition. Most of the modal you’ve created is perhaps never to be seen.

We send all these redundant code 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, 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:

<template>
  <div> 
    <admin-panel v-if="userRole === 'admin'" />
  </div>
</template>
<script>
 const adminPanel = () => import('AdminPanel.vue')
 export default {
   components: { adminPanel }
 }
</script>

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.

I have given an example, especially as above. Because what I want to mention 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 role. Beside the issue of generating a large size file with excessive unnecessary code, it is also a security breach.

Cherry picking

If you are using a component library that uses ES modules like bootstrap-vue, you can cherry pick its components instead of just registering all of them globally.

Instead of doing this:

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 instead of 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:

This is image title

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 by 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 packages:

This is image title

However, it is useful to consider the interpretation of Sean T. Larkin from the Webpack team.

This is image title

This is image title

This is image title

This is image title

As you can see from the trace, you may not really need to split your ‘chunk-vendors’ file.

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’ 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?

I wanted to write an article that I combined what I have learned while developing and caring about performance. I hope it has been helpful. Thank you for reading.

#vuejs #javascript #vue

How to Speed up performance with Vue.JS
19.35 GEEK