Add global variable in Vue.js 3
Asked Answered
O

8

84

How to add a global variable in Vue.js 3?

In Vue.js 2 we use this in the main.js file:

Vue.prototype.$myGlobalVariable = globalVariable
Othilie answered 26/7, 2020 at 13:16 Comment(3)
https://mcmap.net/q/194802/-apply-global-variable-to-vuejsKick
You can use Vuex to handle all global dataBehavior
Yes of course, i can use the store or use a global mixin but I'm asking to use a prototypeOthilie
R
128

The most direct replacement is app.config.globalProperties. See:

https://vuejs.org/api/application.html#app-config-globalproperties

So:

Vue.prototype.$myGlobalVariable = globalVariable

becomes:

const app = createApp(RootComponent)
app.config.globalProperties.$myGlobalVariable = globalVariable

This is scoped to a particular application rather than being global as it was with Vue.prototype. This is by design, all 'global' configuration options are now scoped to an application.

The relevant RFC is here:

https://github.com/vuejs/rfcs/blob/master/active-rfcs/0009-global-api-change.md

Properties added to globalProperties will be available via the component instance for all components within the application. So if you're using the Options API you'll be able to access them using this.$myGlobalVariable, just like you could with Vue.prototype. They'll also be available in the template without the this., e.g. {{ $myGlobalVariable }}.

If you're using the Composition API then you'll still be able to use these properties within the template, but you won't have access to the component instance within setup, so these properties won't be accessible there.

While hacks involving getCurrentInstance() can be used to access globalProperties within setup, those hacks involve using undocumented APIs and are not the recommended approach.

Instead, application-level provide/inject (also discussed in that RFC) can be used as an alternative to Vue.prototype:

const app = createApp(RootComponent)
app.provide('myGlobalVariable', globalVariable)

In the descendant component this can then be accessed using inject. e.g. With <script setup>:

<script setup>
import { inject } from 'vue'
const myGlobalVariable = inject('myGlobalVariable')
</script>

Or with an explicit setup function:

import { inject } from 'vue'

export default {
  setup() {
    const myGlobalVariable = inject('myGlobalVariable')

    // Expose it to the template, if required
    return {
      myGlobalVariable
    }
  }
}

Or with the Options API:

export default {
  inject: ['myGlobalVariable']
}

Docs: https://vuejs.org/api/application.html#app-provide

The idea here is that the component can explicitly declare the property rather than inheriting it by magic. That avoids problems like name collisions, so there's no need to use a $ prefix. It can also help to make it clearer where exactly a property is coming from.

It is common for the inject function to be wrapped in a composable. For example, the useRoute composable exposed by Vue Router is just a wrapper around inject.

In addition to globalProperties and provide/inject, there are various other techniques that might be used to solve the same problems as Vue.prototype. For example, ES modules, stores, or even global mixins. These aren't necessarily direct answers to the specific question posted here, but I've gone into more detail describing the various approaches at:

https://skirtles-code.github.io/vue-examples/patterns/global-properties.html

Which approach you prefer will depend on your circumstances.

Recusant answered 26/7, 2020 at 14:5 Comment(7)
does this work with classes? doesn't seem to work for meZoezoeller
And how are the global variables accessed from the child components (In both cases)? Is it directly by calling this.myGlobalVariable?Nascent
Is there a way to declare global variables from outside the main app creation file? In Vue 2 I used to import Vue and then declare new global variables. I am struggling now since I need the app created by createApp.Nascent
M3HD1 - You can create a function that takes the application (app in the code above) as a parameter and does the provide (i.e. doProv = function(app) { app.provide(...); } and then just import it and call it in main.js or wherever you do your app creation/setup.Bawd
Your argumentation is solid, but you are notably not emphasizing the huge downside of the new approach. You need an extra line, i.e. inject, in every component where you want to access a global variable in CAPI!Sosthena
that is a wonderful answer, thank you!Grafton
The problem I'm facing with inject/provide is that functions that rely on this execute in a different (caller's) scope. I want the provided functions to execute within the scope that they are defined inAngarsk
I
48

How to add a global variable using Vue 3 and vue-cli (or Vite)

Note: You can drop the dollar sign from your $globalVariable and just use globalVariable, just like in the documentation.

Initially your main.js file looks something like this (adding router for common use case):

import { createApp } from 'vue'
import { App } from './App.vue'
import { router } from './router'

createApp(App).use(router).mount('#app')

To use add the global variable using Vue 3 and the vue-cli or Vite:

import { createApp } from 'vue'
import { App } from './App.vue'
import { router } from './router'

// 1. Assign app to a variable
let app = createApp(App)

// 2. Assign the global variable before mounting
app.config.globalProperties.globalVar = 'globalVar'

// 3. Use router and mount app
app.use(router).mount('#app')

Then to access the variables in components like this:

<script>
export default {
    data() {
        return {
            myVar: this.globalVar
        }
    }
}
</script>

like in the template like this:

<template>
  <h1>{{ globalVar }}</h1>
</template>

And that's it. Happy coding!

About Global Variables and Composition API

According to the very bottom of samayo's answer on this post, global variables are only available on the Options API.

Quoting the bottom of his answer:

Note: This is only for the Options API. Evan You (Vue creator) says: "config.globalProperties are meant as an escape hatch for replicating the behavior of Vue.prototype. In setup functions, simply import what you need or explicitly use provide/inject to expose properties to app.

Inconsistent answered 24/8, 2021 at 9:42 Comment(7)
hey that's amazing!! thank you very much!! =)Fiddlefaddle
Prefixing variables with some kind of "special character" makes it easier to signify in code that this variable is indeed special and probably comes from somewhere else. This makes coders more aware and development less error-prone.Sena
@Sena is there specific documentation that talks about this?Variolous
No, but it's a common practice for things that pollute the global scope. Think i.e jQuery for instance and their $. The approach was also commonly used in Vue 2 docs. As always, you're free to use whatever you want, in the same way you're free to drive off the side of the road instead of following it. You should probably look up the Rosetta Stone. Experience tells us that making them stand out (in some way) makes their significance easier to see.Sena
Why provide an example with the options API in Vue 3? One of the biggest reasons to move to Vue 3 is the composition API with the script setup sugar.Nitride
@Nitride Just updated. Apparently this isn't a feature for the composition api.Variolous
What if I want to call the fetch request first and then set the globalProperties? It always returns undefined because the app is mounting before setting globalProperties. I tried the mounting process after api call but still looking for an elegant solution.Bristling
T
35

I recommend to use provide/inject approach as follows :

in main.js :

import {createApp} from 'vue'

const app=createApp({
  provide:{
    globalVariable:123
  }

}).$mount('#app')

in some child or grand-child component do :

export default{
 name:'some-compo',
 inject:['globalVariable'],
 //then access this.globalVariable as property in you component
...
}

for composition api and script setup :

 import { inject } from 'vue'
 
 const globalVar=inject('globalVariable')
Taipan answered 26/7, 2020 at 13:37 Comment(6)
createApp in my example is being passed a component, which has <script setup>. So how to pass provide in this case?Zoezoeller
how can i achieve something similar to this inside a class ( not a component ) i mean how can i use inject inside a class ?Pentacle
Is it possible to inject multiple variables in one line?Lowpitched
@Lowpitched yes you could with options api, but in composition one you should assign each injected item in a specific variableTaipan
I have done it like this, const global = {"$axios": axios,'$moment': moment,'$third': third,}; app.provide('$global ', global ); in main.js, and then inject the whole object when needed.Lowpitched
You're currently only linking to the options API provide/inject page, you should also link to the composition API provide/inject page: vuejs.org/api/composition-api-dependency-injection.htmlBiodynamics
F
17

If possible you should use imports or provide/inject. Another way to define global variables/functions and use them would be using globalProperties (although this seems to be considered more of an anti-pattern). But if a library you use uses globalProperties then you can use it like this. This also works with global functions.

const app = Vue.createApp({})
app.config.globalProperties.$http = () => {} // global function
app.config.globalProperties.$globalVariable = 'Jimmy' // global variable

1. Using options API

mounted() {
  console.log(this.$globalVariable)
}

2. Using setup method

<script setup>
    import { getCurrentInstance } from 'vue'

    const app = getCurrentInstance()
    const progressBar = app.appContext.config.globalProperties.$globalVariable

    console.log(this.$globalVariable)
</script>
Freddiefreddy answered 12/12, 2020 at 8:34 Comment(1)
What if I want to access this global variable outside of components, i.e. in router?Echelon
A
8

For those of you who are confused about how to access globalProperties in the setup() method, you can use getCurrentInstance() as in the following documentation.

https://v3.vuejs.org/api/composition-api.html#getcurrentinstance

Agonized answered 23/11, 2020 at 14:23 Comment(1)
From the documentation: "getCurrentInstance is only exposed for advanced use cases, typically in libraries. Usage of getCurrentInstance is strongly discouraged in application code. Do NOT use it as an escape hatch to get the equivalent of this in Composition API."Sena
P
6

Vue 3:

import { getCurrentInstance } from "vue";

const { proxy } = getCurrentInstance();

"proxy" will be contain the value from globalProperties. For example:

app.config.globalProperties.$toast = {...}

and then:

proxy.$toast.success()
Playwriting answered 11/7, 2023 at 13:25 Comment(1)
My got I was looking for this everywhere. You my heroBarocchio
D
1

In my case I had to create a global var and get the data from a script.
Used provide and inject:

In main.js:

    import { createApp } from 'vue'
    import App from './App.vue'
    const app = createApp(App);
    app.provide('message',document.querySelector('script[name="nameSCRIPT"]').innerHTML.split('=').slice(1).join('=').slice(1,-1));
    app.mount('#app')

In index.html:

 <script name="nameSCRIPT">nameSCRIPT="HELLO"</script>

In child component:

    inject:['message'],
    mounted(){
    console.log(this.message)
  },
Deron answered 9/5, 2022 at 8:12 Comment(1)
It is very likely that your solution will sometimes break with an error: TypeError: Cannot read properties of null (reading 'innerHTML'). Generally, DOM is about DISPLAY, but not about data storage. It's easier then to write a variable to self and read from there, although this is bad for a number of reasonsSalvadorsalvadore
S
-5

window.myGlobal = "hey this is easy";

Seraphic answered 16/3, 2023 at 22:8 Comment(5)
window is not guaranteed to be available. especially in the tool chain for Vue. It's only guaranteed in the browser.Quintus
global.myGlobal = "hey, im running in node"Seraphic
const globalObject = typeof window == 'undefined' ? global : window; globalObject.someval = "works if I am unsure what context my code is run in. "Seraphic
being that everything runs through a bundler like webpack, how do you know some other dependency doesn't include the code window.myGlobal = 'something'? If the final bundle requires the existence of the global window variable to make use of the window global in a browser, the bundler can't alter the name of the variable window without also breaking the program. I would just ditch this strategy from your repertoire. I've ended up doing very difficult debugs before because of this.Quintus
That is a risk of using any global variable in any programming language. If its a likely issue, it can be mitigated by appropriate naming.Seraphic

© 2022 - 2024 — McMap. All rights reserved.