Organize Code with Vue.js

Organize Code with Vue.js
Vue encourages using Mixin and Store instead of isolated stateful object to organize shared logic.

If you have played with Angular before, you must be familiar with services in the Angular ecosystem. They are isolated singleton objects that you can use to organize your shared functions. For example, you may have an AuthenticationService which handle all the login, logout, token refresh, etc.

This concept doesn’t exist in Vue. Vue encourages using Mixin and Store instead of isolated stateful object to organize shared logic. Yet, if you love Angular (like me :D) and you want to stick with the Angular methodology even in Vue (and you don’t care about best practices), here is what you can do to create an Angular-like service in Vue.

Vue

Creating importable singleton objects in JS

It is actually quite simple to create a singleton object. Simply define your class and export an instance instead of the class definition, then it will be singleton.

In my.service.js:

class MyService {
  myVar = 1;
  
  constructor() {
    
  }
 
  myMethod() {
    return this.myVar;
  }
}
export default new MyService();

In your component:

<template>
  <div>{{test}}</div>
</template>
<script>
  import myService from '@/services/my.service.js';
  export default {
    data() {
      return {
        test: myService.myMethod()
      }
    }
  }
</script>

(Vue) Accessing Vue instance inside services

Services with only simple methods are not practical. You will usually need to access the Vue instance, such as calling router.go() in the AuthenticationService.logout(). In order to do that, you need to first define a base class:

In service.js:

export class Service {}

In index.js

...
import { Service } from './service';
...
let vue = new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
Service.prototype.$vue = vue;

Or

Service.prototype.$router = vue.router;

Finally, edit your my.service.js:

import { Service } from './service';
class MyService extends Service {
  myVar = 1;
  
  constructor() {
    super();
  }
 
  myMethod() {
    return this.myVar;
  }
  test() {
    console.log(this.$vue);
    console.log(this.$vue.router);
    console.log(this.$router);
  }
}
export default new MyService();

(Nuxt) Accessing Vue instance inside services

The approach is quite similar if you are using Nuxt. Simply create a custom plugin and assign the instance to the service prototype.

In service-init.js:

import { Service } from '@/services/service';
export default ({ app: {router} }) => {
  Service.prototype.$router = router;
}

In nuxt.config.js:

export default {
  ...
  plugins: [
    ...
    '@/plugins/service-init'
  ]
}

Reactivity of services

Your services are stateful, but they are not reactive, like Angular. It means updating you service variables will not trigger change detection (thus, no UI update). Here are two approaches that you may use to handle this:

Angular approach — event bus: If you want to stick with the Angular way, you may define an event bus in your Vue instance. You can fire an event manually when there is change in the state. After that, you subscribe the event in the component to track the change and handle the update.

Vue approach — Vuex store: A more organized approach is to add Vuex store to your application. If you have played with React, store is nothing special. Yet, if you don’t have any experience about using store, you can imagine it as a global reactive variable. For anything you would like to be shown in the UI, such as AuthenticationService.isAuthenticated, put it in the store instead of the service. Whenever you update the store, Vuex will handle the UI update.

In the last company I worked for, most projects are implemented with Angular, while some new projects are with Vue. These kind of services are probably not the best practice to do Vue programming, but we find it quite helpful for our Angular programmers during the transition before they get used to Vue. Especially when we do revamp from Angular to Vue, we can reuse the code in services. Hope our idea is also helpful for you!

Suggest:

Nuxt.js - Practical NuxtJS

Learn Vue.js from scratch 2018

Is Vue.js 3.0 Breaking Vue? Vue 3.0 Preview!

18 Nuxt JS beginner tutorial - Start weather app project

Vue.js Tutorial: Zero to Sixty

Learn Vue.js from Scratch - Full Course for Beginners