9

I'm trying to write a Vue plugin that's a simple abstraction to manage auth state across my app. This will need to access other Vue plugins, namely vuex, vue-router and vue-apollo (at the moment).

I tried extending Vue.prototype but when I try to access the plugin's properties how I would normally - eg. this.$apollo - I get the scope of the object, and therefore an undefined error. I also tried adding vm = this and using vm.$apollo, but this only moves the scope out further, but not to the Vue object - I guess this is because there is no instance of the Vue object yet?

export const VueAuth = {
  install (Vue, _opts) {
    Vue.prototype.$auth = {
      test () {
        console.log(this.$apollo)
      }
    }
  }
}

(The other plugins are imported and added via. Vue.use() in the main app.js)

Alternatively, I tried...

// ...
  install (Vue, { router, store, apollo })
// ...

but as a novice with js, I'm not sure how this works in terms of passing a copy of the passed objects, or if it will mutate the originals/pass by ref. And it's also very explicit and means more overhead if my plugin is to reach out to more plugins further down the line.

Can anyone advise on a clean, manageable way to do this? Do I have to instead alter an instance of Vue instead of the prototype?

0

3 Answers 3

6

In the plugin install function, you do not have access to the Vue instance (this), but you can access other plugins via the prototype. For example:

main.js:

Vue.use(Apollo)
Vue.use(VueAuth) // must be installed after vue-apollo

plugin.js:

export const VueAuth = {
  install (Vue) {
    Vue.prototype.$auth = {
      test () {
        console.log(Vue.prototype.$apollo)
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I found a simple solution for this issue:

In plugin installer you need to add value to not just prototype, but Vue itself to be able to use it globally.

There is a code example:

Installer:

import apiService from "../services/ApiService";
// Service contains 'post' method

export default {
  install(Vue) {
    Vue.prototype.$api = apiService;
    Vue.api = apiService;
  }
};

Usage in other plugin:

import Vue from "vue";

...

const response = await Vue.api.post({
  url: "/login",
  payload: { email, password }
});

Usage in component:

const response = await this.$api.post({
  url: "/login",
  payload: { email, password }
});

I'm not sure if that's a good solution, but that made my scenario work perfectly.

Comments

0

So, I got around this by converting my property from a plain ol' object into a closure that returns an object, and this seems to have resolved my this scoping issue.

Honestly, I've jumped into Vue with minimal JS-specific knowledge and I don't fully understand how functions and the likes are scoped (and I'm not sure I want to look under that rock just yet......).

export const VueAuth = {
  install (Vue, opts) {
    Vue.prototype.$auth = function () {
      let apollo = this.$apolloProvider.defaultClient
      let router = this.$router

      return {
        logIn: function (email, password) {
          apollo.mutate({
            mutation: LOGIN_MUTATION,
            variables: {
              username: email,
              password: password,
            },
          }).then((result) => {
            // Result
            console.log(result)
            localStorage.setItem('token', result.data.login.access_token)
            router.go(router.currentRoute.path)
          }).catch((error) => {
            // Error
            console.error('Error!')
            console.error(error)
          })
        },

        logOut: function () {
          localStorage.removeItem('token')
          localStorage.removeItem('refresh-token')
          router.go()
          console.log('Logged out')
        },
      }
    }

It's a rudimental implementation at the moment, but it'll do for testing.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.