foxbenjaminfox/vue-async-computed

"Auto install in dist mode" code

oscar-gardiazabal opened this issue · 4 comments

This is so bad if you want to import vue from cdn and use this plugin options.

if (typeof window !== 'undefined' && window.Vue) {
  // Auto install in dist mode
  window.Vue.use(AsyncComputed)
}

I had to copy and manually remove this part to use it in my environtment.

I think this should change in future versions.

Good point. The reason vue-async-computed does this is because plugins like vue-router and vue-resource do, and it seems useful. But you're right that it gets in the way of passing options to Vue.use.

I guess one argument would be that the reactively "advanced" who would want to pass options would be using the package through npm, not the CDN build, and so it doesn't matter that much. That said, it seems that at the very least you are someone who wants to use it through a CDN and still pass it options.

I don't really want to completely remove this block, because I do believe it is helpful to beginners to not have to call Vue.use manually. But there is a thing or two that could be done to help:

  1. What if the window.Vue.use like can be something like this: window.Vue.use(AsyncComputed, window.Vue.asyncComputedOptions || {}). This would allow you to define Vue.asyncComputedOptions before the script tag that loads vue-async-computed from the CDN, and then you can configure vue-async-computed with whatever options you wish. A similar proposal would be to instead check the value of Vue.autoInstallAsyncComputed and if it's false, then to not automatically do the Vue.use, and instead let you do it manually.

  2. You could include the script tag that loads vue-async-computed from the CDN before the script tag that loads vue itself. That means that as the vue-async-computed code runs, window.Vue is undefined, and so it won't enter that if block and call window.Vue.use. After you do load vue, you can then do Vue.use with precisely the options you want.

Does either of these sound good to you?

Yeah, I saw that other plugins work like this.

I'm using "dynamic-cdn-webpack-plugin" that auto-imports all the CDN's at the same time. In that scenario I can't decide when or in wich order include CDN's so none of the solutions fits to me.

The second option could work if "asyncComputedOptions" were a global in window and not inside Vue.
Another solution could be to add a conditional to that block to prevent it from firing like:

if (typeof window !== 'undefined' && window.Vue && !window.preventThisToFire) {
  // Auto install in dist mode
  window.Vue.use(AsyncComputed)
}

But I think both solutions are ugly :(

I see. To be fair, that's really an edge use case, and I'm not entirely sure I want to contort things in order to support it. Perhaps it would be best if you indeed keep on using a modified version without those lines.

The reason I would want to put the option on the Vue object (or actually, on further reflection, on Vue.config) is to avoid having the global window namespace be polluted.

Here is a potential workaround, if you'd like to avoid using a manually modified version. Before loading the all the files from CDNs, run something like this:

let finishedLoading = false
;(function () {
  let Vue
  Object.defineProperty(window, 'Vue', {
    get () {
      if (finishedLoading) {
        return Vue
      } else {
        return undefined
      }
    },
    set (value) {
      Vue = value
    }
  })
})()

Then, after loading all the files from the CDNs, set finishedLoading to be true, then you can call Vue.use on all your plugins. This will cause all the scripts at load time to see Vue as undefined, but as soon as you set finishedLoading the Vue object will be set as normal.

While this is a bit of a workaround, it is a way to solve your problem without needing to change things for the 99%+ of users who load this and other plugins in one of the typical ways (as an npm package, or by dropping into the page a script tag pointing to it.)

Thank you @foxbenjaminfox for the code!
I had never worked with defineProperty getters and I didn't ve much time to spend on this.

But your solution didn't work to me because some vueautify plugin broken when not finds "new Vue()" constructor, so I made some ugly modifications to intercept only the use() method, although I'm sure there's a better way to do it.

Anyway, maybe somebody needs this.

    var cdnLoad = false;

    (function () {

      var Vue;
      Object.defineProperty(window, 'Vue', {
        get() {
          if (!Vue) {
            return Vue;
          }

          if (!Vue.use_intercept) {
            Vue.use_intercept = Vue.use;
          }

          Object.defineProperty(Vue, 'use', {
            get() {
              if (!cdnLoad) {
                return function () { };
              }
              return Vue.use_intercept;
            },
            set(value) {
              Vue.use = value
            }
          });

          return Vue;
        },
        set(value) {
          Vue = value
        }
      })

    })()

Also, to return to cdnLoad = false; it has to come as an import to load before the other imports in index.js