Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uncaught Error: [vue-composition-api] must call Vue.use(plugin) before using any function

Consider the following composition function:

import { computed, ref } from '@vue/composition-api'
import { isInternetExplorer } from 'src/services/utils/utilsService'
import { Screen } from 'quasar'
import { auth, getAllScopes } from 'src/services/auth/authService'

const isLoginPopup = Screen.lt.sm || isInternetExplorer ? false : true
const accountID = ref('')

export const setAccountID = () => {
  const account = auth.getAccount()

  if (account) { accountID.value = account.idTokenClaims.oid } 
  else { accountID.value = '' }
}

export const useAccount = () => {
  const loading = ref(false)
  const disabled = ref(false)

  const login = async () => {
    loading.value = true
    disabled.value = true

    const allScopes = getAllScopes()

    if (isLoginPopup) {
      try {
        await auth.loginPopup(allScopes)
      } finally {
        setAccountID()
        disabled.value = false
        loading.value = false
      }
    } else {
      auth.loginRedirect(allScopes)
    }
  }

  const logout = () => { auth.logout() }

  return {
    accountID: computed(() => accountID.value),
    isAuthenticated: computed(() => Boolean(accountID.value)),
    loading: computed(() => loading.value),
    disabled: computed(() => disabled.value),
    login, logout,
  }
}

Now when I want to use the isAuthenticated computed property within /router/index.js Vue throws the error "Uncaught Error: [vue-composition-api] must call Vue.use(plugin) before using any function.":

import { route } from 'quasar/wrappers'
import VueRouter from 'vue-router'
import routes from './routes'

import { useAccount } from 'src/comp-functions/useAccount'

export default route(function ({ Vue }) {
  Vue.use(VueRouter)

  const Router = new VueRouter({
    scrollBehavior: () => ({ x: 0, y: 0 }),
    routes,

    mode: process.env.VUE_ROUTER_MODE,
    base: process.env.VUE_ROUTER_BASE,
  })

  Router.beforeEach((to, from, next) => {
    const { isAuthenticated } = useAccount()

    if (isAuthenticated || to.path === '/' || to.path === '/login') {
      next()
    } else {
      next('/login')
    }
  })

  return Router
})

The component API is instantiated by a Quasar Framework boot file in the file '/boot/auth.js':

import VueCompositionApi from '@vue/composition-api'
import { boot } from 'quasar/wrappers'

export default boot(({ Vue }) => {
  Vue.use(VueCompositionApi)
})

Is there a way to use an exported computed property outside of a component?

According to this example, which is a library using the same composition API, it should work when isAuthenticated is instantiated within the Router object. There are more people struggling with this but I can't seem to get it right.

like image 280
DarkLite1 Avatar asked May 19 '20 07:05

DarkLite1


Video Answer


2 Answers

This problem was fixed by a friend on the Vue.js forum. For anyone else who is running into this issue I'll post his answer here. In short you need to create a separate file that will install the composition API plugin and call that file within the router/index.ts file to instantiate the plugin.

It’s because of the composition API not being inside Vue itself. With the release of Vue 3 this will be fixed.

You need to Vue.use(CompositionApi) before trying to use anything that belongs to @vue/composition-api.

In your main.js or index.js, the app entry point, install it first:

import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'

Vue.use(VueCompositionApi)

This works. But I assume your file doesn’t look like this and it looks more like the next one:

import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'
import { isAuthenticated } from '@/store/auth'

Vue.use(VueCompositionApi)

This will blow up everything again because the line that installs the composition API (Vue.use(VueCompositionApi)) is after a line that imports something that uses it (import { unauthenticated } from '@/store/auth')

In the meantime, until Vue 3.0 reaches its release, you can create a file that simply installs the plugin:

// installCompositionApi.js

import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'

Vue.use(VueCompositionApi)

And then in your entry point:

// main.js
import './installCompositionApi.js'
import Vue from 'vue'
import { isAuthenticated } from '@/store/auth'

if (isAuthenticated.value) {
// ...
} else {
// ...
}

This will work.

like image 108
DarkLite1 Avatar answered Oct 24 '22 16:10

DarkLite1


Did you install VueCompositionApito correctly?

You must install @vue/composition-api via Vue.use() before using other APIs:
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';

Vue.use(VueCompositionApi);
like image 33
Mohsen Avatar answered Oct 24 '22 15:10

Mohsen