The best ways to optimize a Vue.js Application

vue.JS optimization
Share

There is a lot of controversy surrounding performance in software engineering. A developer can write code and ship it; it’s another thing altogether to make it faster and more enjoyable for the users and the next developer.

Before starting our examination, If you don’t know about Vue.js then please read our previous Vue.js full course from scratch which is totally free. Let’s examine how to speed up your Vue.js web applications, thereby improving both user and developer experiences.

1. Components of a lazy loading route

In software engineering, lazy loading refers to deferring the initialization of particular objects or parts of applications until they are needed.

Normally, we bundle our Vue.js app into one relatively large JavaScript file, but with this technique, each component is compiled into smaller chunks, each chunk for a route component. This results in our application loading faster in a browser, and each chunk is only requested when a user visits a new route.

In case you’re already familiar with lazy loading components in Vue, keep in mind that this method applies to only the components we register with Vue Router, not all the components in our codebase. The bundle would include all other components registered inside the router component.

So how is this done? Let’s have a look:

// in router.js file
import Vue from 'vue'
import Router from 'vue-router'
const Home = () => import('./routes/Home.vue');
const Profile = () => import('./routes/Profile.vue');
Vue.use(Router)
export default new Router({
routes: [
{ path: '/', component: Home },
{ path: '/profile', component: Profile }
]
})

As soon as we register our components this way, webpack automatically chunks our code into smaller pieces. You can also group these files into one chunk. A great scenario would be to group components related by route together.

// specifying the same chunk for components
const Profile = () => import(/* webpackChunkName: "profile" */'./routes/Profile.vue');
const ProfileSettings = () => import(/* webpackChunkName: "profile" */'./routes/ProfileSettings.vue');

By using the comment to explicitly specify the chunk name, webpack automatically bundles the compiled components into the same chunk.

2. Reduce the use of external libraries

In your web app, chances are there’s a package for anything you need due to the massive support behind JavaScript and the large number of packages published and updated daily on npm.That’s wonderful – but we shouldn’t bloat our app’s size with unnecessary code. A lighter package is almost always available.

Before looking for a package, check whether the feature you want is native to the browser. If the native feature is unreliable across browsers or is tough to implement, then a package is likely the best way to go.

Be sure to weigh your options when comparing various packages. The best package for your project is one that’s built in a modular pattern and supports tree-shaking.

3. Image compression and optimization

A bundle’s size is largely determined by its images. Heavy images can actually slow down some parts of the application during rendering.

The two methods of serving images are locally or through CDNs.In the case of an application displaying multiple images, a CDN might be a good option for delivering them.

Image optimization for local use

You can serve three to five images locally if your application only displays three to five images.  It is important to consider the sizes of these files, however, and the images may have to be compressed and scaled down to reduce their size.If you want to compress images, you can use a tool like Adobe Photoshop or online tools such as:

  1. Image compressor
  2. TinyPNG

Image optimization for CDNs

An application that relies heavily on images can benefit from optimizing images on a CDN. A CDN can reduce image file sizes by up to 70% while still maintaining the quality of the image.

A CDN is probably the best option if your application will use around ten or more images. The following are some popular media management platforms:

  1. Cloudinary
  2. Imagekit

4. Images that load slowly

When dealing with media-heavy sites, just compressing media files isn’t enough in some cases. In this case, lazy loading comes into play.  The users will only be able to request media files that are visible in the viewport during the initial load of the page; the rest will be requested as they navigate through the application.

For lazy loading images, we can use the vue-lazyload package. It is a lightweight, easy-to-use library with a lot of flexibility.

Installation:

npm i vue-lazyload

Setup:

// in main.js
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)

Working with v-for:

<ul>
  <li v-for="image in images">
    <img v-lazy="image.src" >
  </li>
</ul>

Working with raw HTML:

<section v-lazy-container="{ selector: 'img' }">
  <img data-src="//images.com/cart1.jpg">
  <img data-src="//images.com/cart2.jpg">
  <img data-src="//images.com/cart3.png">  
</section>

When an image enters the viewport, it will only be requested.  Create the file vue-lazyload.js with the content of the main.js (above) in the /plugins directory, If you’re working on a Nuxt project.

The plugin should be registered in nuxt.config.js as follows:

export default {
  plugins: [
    { src: '~/plugins/vue-lazyload.js', mode: 'client' }
  ]
}

5. Utilize the same functionalities across your apps

It’s quite easy to forget about reusability when working with external libraries. Using the Vue Notifications  library as an example, we’ll examine this section.

The Vue Notifications API connects your Vue app to various notification libraries. Switching between notification libraries is also easy. Based on the documentation, let’s take a look at how to use the library.

// in main.js
import Vue from 'vue'
import VueNotifications from 'vue-notifications'
import VueToasted from 'vue-toasted' 

function toast({ title, message, type, timeout, cb }) {
if (type === VueNotifications.types.warn) type = 'show'
return Vue.toasted[type](message, { duration: timeout })
}
Vue.use(VueToasted)
const options = {
success: toast,
error: toast,
info: toast,
warn: toast
}
Vue.use(VueNotifications, options)

In the script section of our components:

import VueNotifications from 'vue-notifications'
export default {
  name: 'Register',
  data () {
    return {
      email: '',
      password: ''
    }
  },
  notifications: {
    showSuccess: {
      type: VueNotifications.types.success,
      title: 'Success!',
      message: 'Account created successfully'
    },
    showError: {
      type: VueNotifications.types.error,
      title: 'Oops!',
      message: "Something's wrong, Please try again later"
    }
  }
  methods: {
    async login(){
      try {
        await sendUserData() // or any other way to send credentials
        this.showSuccess()
      } catch (error){
        // after checking error type
        this.showError({message: error.data.message})
      }
    }
  }
}

You may have noticed that we had to import the VueNotifications package and add a notification option as well? Using the package in just one component would be fine, but I doubt that would be the case for any large application.

Instead of manually importing VueNotifications into components and setting custom options in over 10 different components, how about creating a generic mixin that can be used to display any notification message?

First, we create the file /mixins/notifications.js:

import VueNotifications from 'vue-notifications'
export default {
  notifications: {
    showError: {
      title: 'Oops!',
      message:
        "Something's wrong with, please check your internet and try again.",
      type: VueNotifications.types.error
    },
    showSuccess: {
      type: VueNotifications.types.success,
      title: 'Success!',
      message: 'Action successful'
    }
  }
}

In our components, we can now import only the mixin:

import notifications from '@/mixins/notifications'
export default {
  name: 'Register',
  mixins: [notifications],
  data () {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    async login(){
      try {
        await sendUserData() // or any other way to send credentials
        this.showSuccess({ message: 'Account created successfully' })
      } catch (error){
        // after checking error type
        this.showError({ message: error.data.message })
      }
    }
  }
}

The component is now more readable and less cluttered. Using mixins, we import only the parts of the package we need.

Conclusion

In addition to the five techniques listed above, there are many other ways to optimize our Vue.js apps.

Following are the points highlighted above for those who skimmed the article:

  • Your route components should be loaded in a lazy manner
  • If external libraries are needed, weigh your options before using them
  • Prepare images for delivery on the web by compressing and optimizing them
  • Make your app’s user experience smooth by lazy loading images
  • Minimize duplication of code by reusing functionalities across your app
Share

Leave a Comment

Your email address will not be published.

Share