Subscribe on changes!

Impossible to create a getter on app.config.globalProperties

avatar
Dec 30th 2020

What problem does this feature solve?

In Vue 2 I had a getter defined as Vue.prototype.$app – this wasn’t a static value but rather computed for each component (walking up the parents chain until the right component was located). Doing the same with Vue 3 turned out impossible: getters on app.config.globalProperties aren’t transferred to the instance. Instead, they are resolved with app.config.globalProperties as this.

What does the proposed API look like?

Maybe the code behind processing app.config.globalProperties should recognize getters and setters, calling them appropriately when proxy handler’s get() and set() methods are called.

avatar
Dec 31st 2020

I think you can use global mixins as an alternative?

avatar
Dec 31st 2020

In what way? Define a created() method and set a property there? Sounds like a rather wasteful and non-straightforward approach.

Note that personally I’m not looking for a work-around, I solved this in another way already. That’s a capability which was present in Vue 2 however and makes migration harder.

avatar
Dec 31st 2020

Vue components don't have a prototype anymore.

We could kind of replicate the behavior with something like this inserted here:

https://github.com/vuejs/vue-next/blob/a2e65ef85352d6233db0839befbe2eec7bae397c/packages/runtime-core/src/componentPublicInstance.ts#L328-L333

else if (hasOwnProperty(globalProperties, key)) {
  const descriptor = Object.getOwnPropertyDescriptor(globalProperties, key)
  if (descriptor.get) {
    return descriptor.get.call(instance.proxy)
  } else {
    return globalProperties[key]
  }
}

and likewise we would likely adjust the behavior when trying to set a property that exists in globalProperties, but has a setter?

I'm personally torn - does this overcomplicates the behavior of globalProperties that is right now just a simple object, or is the use case mentioned by @palant worth it?

Because extending a prototype with a getter makes it clear that you will have access to the in instance created from that prototype through this in the getter - that's just plain JS. The hack that I fleshed out above would have to be documented and explained as it's not apparent why a getter on that plain would give you access to the component instance through this.

Such a getter would definitely be cheaper than a global mixin that adds a property to each instance, but would it actually have a measurable impact?

avatar
Jan 3rd 2021

I did something similar in some of my Vue 2 applications. I needed access to this and didn't want to add any extra overhead to components that didn't use the property. A getter on Vue.prototype worked perfectly.

So far I've only migrated one, very small application to Vue 3. I switched it to use a global mixin with a computed property instead. That did work in that case but the application was far too small to assess the performance impact.

I've worked on large applications (a long time ago, pre-Vue) where performance became a major problem because of several, very small inefficiencies. That experience has always made me very wary of features like global mixins.

If it were possible to use a getter with globalProperties I would definitely have used that instead.

avatar
Mar 10th 2022

Hi there,

Any news on this issue ? I'm in the same situation, I need to use a getter for a globalPropertie but it seems there's no way to do that ?

avatar
Jan 14th 2023

If you need to define a dynamic global property, for example, a $store per Storybook story, try this.

app.mixin({
  beforeCreate() {
    this.$store = $store
  }
})

It works because Vue3 allows defining $xxx properties in VM. However, an attempt to define $store as a computed property would fail.

https://github.com/vuejs/core/blob/f73925d76a76ee259749b8b48cb68895f539a00f/packages/runtime-core/src/componentPublicInstance.ts#L344-L347