Closed paulpflug closed 8 years ago
How about var Vue = require('vue');
?
I thought I might end up with different versions of Vue.
I think I can go with peerDependencies
, thank you :smile:
If you use webpack, it should just refer to 1 version of script, instead of creating new on each require, no?
I think one cannot necessarily assume this. When you add a component as a dependency and it has another vue as dependency then I think it should load that instead.
Ok, now it is a real problem.
When Vue is statically linked, for example from a cdn, I can't get it with require('vue')
Atop of this, when I have Vue additionally installed as a dep I won't even notice that require('vue')
points to another instance and produce wired behavior (e.g Vue.util.defineReactive
isn't working)
Furthermore it would allow component developers to get rid of the peerDependecy
.
When Vue is statically linked, for example from a cdn, I can't get it with require('vue')
Obviously.. It's already on window.Vue
in that case.
so what would be the reliable way?
if (window.Vue != null)
Vue = window.Vue
else
Vue = require("vue")
would still add vue to the webpack bundle without necessity or error when no vue is installed
You have to use different packaging strategies targeting different usage.
When distributing it for npm-based bundler usage (e.g. Webpack, browserify), there's no need to pre-compile it, just let the user import the *.vue
file directly.
When distributing for use without build tools (e.g. global Vue from CDN), you need to wrap the whole thing as a plugin so that Vue can be passed via Vue.use()
or just assume Vue will be available globally.
In that case I would target statical linking for my component, I would have to distribute 4 versions
I will use this now:
if @$root.construtor? # is Vue instance
@Vue = @$root.construtor
else # is Vue-Component instance
@Vue = Object.getPrototypeOf(Object.getPrototypeOf(@$root)).constructor
But I really would appreciate a cleaner solution
Actually, the next version of vue-router will probably use a different api which uses a plain Vue instance as root. Together with Vuex it will look more like:
const root = new Vue({
el: '#app',
store: vuexStoreInstance,
router: vueRouterInstance,
components: { App }
})
+1 for that api change.
I'm looking at this issue again and am wondering what is the reason that you need reference to the global Vue
inside a distributed component - can you explain the use case a bit more?
In vue-clusterize I need to access Vue.FragmentFactory
, Vue.util.createAnchor
and Vue.util.defineReactive
to workaround the nested slot
problem by basically building an own v-for
, this can be avoided with the changes I proposed in #2507.
Actually I can't think of another use case.
Cool, seems like a very specific use case then. Since you already have a working (although hacky) solution, and the need can be eliminated by adding API elsewhere, I'm closing this for now.
I found another use case: singleton component. For example an overlay which is used behind dialogs or modals. A singleton pattern allows a way better handling of z-index / click events than dealing with multiple instances.
This is my current implementation:
overlay = null
module.exports = (Vue) ->
overlay ?= new Vue(require('./overlay-component')) # the overlay attaches itself to the body..
return overlay
So to activate the overlay the calling component needs a ref. to Vue
.
I would prefer a cleaner solution, but I see no easy way of adding singleton components to Vue..
I have another convincing use-case for a singleton component: toast
I made a mixin as a workaround getVue
so the usage will look something like this:
mixins: [require("vue-mixins/getVue")]
method:
makeAToast: ->
toaster = require("vue-toaster")(@getVue())
toaster.toast({})
I would love to get around the getVue
stuff for the user..
I think this should be reconsidered for 2.0 because of
vm.$set -> Vue.set
and vm.$delete -> Vue.delete
The check you mentioned here actually should work, you just need to treat vue
as an external when bundling your component: https://webpack.github.io/docs/library-and-externals.html#applications-and-externals
nonono - I will stick with my mixin solution. All others are unreliable and error prone.
My point is, with that API change, others will also have the need for the Vue
instance and this will create some issues in the future.. (because all other solutions are unreliable and error prone :smile:)
Why is what I suggested unreliable?
imagine this dependency tree:
require("vue")
will give different versions of Vue
in myProject and in myComponent - this could be very difficult to debug, especially as a maintainer of myComponent
when you have no idea of myProject
.
Such tree happens regularly when using npm link
..
(But I also stumbled upon components which list Vue
as a direct dependency)
this can be avoided by adding
resolve:
alias:
"vue": path.resolve("./node_modules/vue")
in the webpack config of the project, but I clearly prefer the mixin to that..
@paulpflug I believe if component specifies vue
as a peerDependency
, then npm (at least 3.x+) will never install Vue under the component, even when there's a version conflict.
sure thing, emphasis is on if I have seen components with vue as direct dependency already..
This is very easy to fix - yes - but very difficult to debug, because there is no error / no warning if you accidentally use the wrong vue instance, it just won't work (I speak for Vue.util.defineReactive
).
Regarding peerDependency
- I often use npm link
on my own repositories which have all devDependencies
installed, so peerDependency
is ignored and require("vue")
will always deliver different instances - so I avoid it completely..
This Issue is not severe, not like I can't live without fixing this. It might be a source for annoying mistakes in the future - we will see.
If I could close it again I would :smile:
Currently I'm using
this.$root.constructor
within my component to get toVue
But when using
vue-router
,this.$root
is aVueComponent
, so this doesn't work.Object.getPrototypeOf(Object.getPrototypeOf(this))
would work, but I don't really want to do that, for obvious reasons :smile:maybe I can have
$Vue
refering to the main Vue object?