Skip to content

Consider detecting browser environment just-in-time #11772

Open
@sebamarynissen

Description

@sebamarynissen

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)
};

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions