Vue3 use global variable in js files
Asked Answered
L

3

8

I have some global variables in Vue3 project defined like:

 app.config.globalproperties.$locale = locale

then composable is created to dynamically return global variable:

import { getCurrentInstance ) from 'vue'
export function useGlobals(type) {
  const app = getCurrentInstance()
  const global = app.appContext.config.globalProperties[`$${type}`]
  return { global }
}

then in vue components composable is imported and executed:

import { useGlobals } from '../path'
const { global } = useGlobals('locale')

now, global variable can be used.

But the problem arise when I import composable in js files, there the appContext is undefined.

My question is, is there a way we can get global variable or appContext in js files?

Lecialecithin answered 1/10, 2022 at 10:51 Comment(1)
Have you tried export const { appContext } = app in main.js? Should work.Publican
L
5

Thanks to great suggestion from @tao (btw it is impossible to get appContext from app but that gives me an idea :)) issue is solved.

I created another export in main.js, after app creation, with the all global properties:

const globals = app.config.globalProperties
export { globals }

or as a function (another @tao suggestion):

export const useGlobals = () => app.config.globalProperties

Now we can import globals in any js file and use it like:

import { globals } from '../path/to/main.js'
globals.$locale

or from function :

import { useGlobals } from '../path/to/main.js'
const { $locale } = useGlobals()
Lecialecithin answered 1/10, 2022 at 14:42 Comment(3)
You're right. There's no appContext on app. Personally I'd use a function: export const useAppConfig = () => app.config. And use it as const { globalProperties } = useAppConfig(). This way you can be sure you get the contents of globalProperties when you call the function, not when the config was exported. In most use cases, globalProperties doesn't change after the app is mounted but if a plugin is added dynamically, you won't get any global props added by it, because the config was exported early. Makes sense?Publican
@Publican Yes , yes it makes a lot of sense. Thanks again!! In my case global variables are created when app mounts, no additional ones. But exporting as function is way better. I will switch to it, cheers :)Lecialecithin
interesting solution, so I'm assuming here that ../path is the path to your main.js file? If so can you update your info here to reflect that and eliminate confusion for people who dont have the full context? @NikolaPavicevicDolabriform
P
2

I attempted the answer suggested by @nikola-pavicevic, but it had a negative side effect of causing infinite recursion. For example, every time you import globals, it has to run through the entirety of main.js, which means initializing and mounting the app again. In production, the app appears to work correctly most of the time, but in my Jest unit tests, the recursion causes lots of issues.

To get around this, I created a GlobalVariableHolder.js file that only contains the following:

const GlobalVariables = {};
export default GlobalVariables;

Then, in main.js, I can import it like so:

import GlobalVariables from "./GlobalVariableHolder";

Then assign the variables:

// This line expects that you first assigned the variables to app.config.globalProperties.
GlobalVariables.variables = app.config.globalProperties;

Then, in the JS file where you need them, your import looks the same as before:

import GlobalVariables from "./GlobalVariableHolder";

And you have access to everything that was in app.config.globalProperties like this:

GlobalVariables.variables.$thisIsAMethod(parameter);

This way, importing GlobalVariableHolder doesn't spin up a new Vue instance every time.

Piapiacenza answered 18/9, 2023 at 16:22 Comment(0)
P
0

instead of creating your composable to get global props, you can use the provide/inject mechanism.

check the documentation here: https://vuejs.org/api/composition-api-dependency-injection.html#provide

Pishogue answered 1/10, 2022 at 13:27 Comment(3)
hey mate, I'm aware of provide/inject functionality. But that only works in vue files not in js. Thanks any way for the help. cheers :)Lecialecithin
@NikolaPavicevic But your solution uses getCurrentInstance(), which also only works in the context of a Vue component instance (not any .js file).Amalle
@Amalle hey mate, you are right, but I said in question that doesn't work in js files :) But solution thanks to tao comment, is not using getCurrentInstance(). In js files I don't need composable just newly exported variable.Lecialecithin

© 2022 - 2024 — McMap. All rights reserved.