Description
What problem does this feature solve?
When testing Vue components on Node with @vue/test-utils, it is important that you mock a browser environment with jsdom-global before vue is loaded. If you fail to do this, you get a TypeError: Cannot read property 'child' of undefined
(see vuejs/vue-test-utils#1192) when trying to mount your component.
The reason is that when Vue is loaded, it checks the environment as
const inBrowser = typeof window !== 'undefined';
It would be useful - at least for the mounting of components - if this check is performed just in time so that the order of loading is not important here.
While one could argue that this is not a problem if you simply get the loading order correct, there is actually a problem when trying to load .vue
files natively in Node. I've written an experimental library for this, call vue-esm-loader. The problem I had when trying to get this to work with @vue/test-utils is that there's a cyclic problem: vue-esm-loader needs vue-template-compiler, which in turn loads Vue first to check for a version mismatch. However, as the loader is loaded as the very first file, this means it's impossible to mock the browser environment before vue is loaded the first time.
I was able to bypass this by directly requiring the build of vue-template-compiler which does not provide the version check, but this is not a good solution (see sebamarynissen/vue-esm-loader@252f1df#diff-5dfe38baf287dcf756a17c2dd63483781b53bf4b669e10efdd01e74bcd8e780aR7). Therefore it would be useful if the environment check in Vue is done on the fly.
What does the proposed API look like?
I propose to replace the inBrowser
constant by an env
object, which can look like
const env = {
get inBrowser() {
return typeof window === 'undefined';
}
};
Subsequently the $mount
method can use this as
Vue.prototype.$mount = function (
el,
hydrating
) {
el = el && env.inBrowser ? query(el) : undefined;
return mountComponent(this, el, hydrating)
};