single-spa / single-spa-vue

a single-spa plugin for vue.js applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issue sharing external vue dependency with common plugin

jualoppaz opened this issue · comments

Hi @joeldenning !

We are developing a single-spa ecosystem with legacy backbone apps and new vue ones. We have already the single-spa app with dynamic modules load working. The last feature we added is the externals option for shared dependencies like vue, vue-router, single-spa-vue, etc. combined with its related import map.

However we have noticed some issues related with vue.

We defined some custom common plugins like this:

export default {
  install: (Vue, {
    endpoint, proxy,
  }) => {
    const client = Client({
      endpoint, proxy,
    });
    Vue.client = client;
    Vue.prototype.$client = client;
  },
};

This plugin is loaded in every microfrontend with Vue.use(plugin), but only at first load. However, if one microfrontend is unmounted and another is mounted, the new client plugin will overwrite the previous one. This fact will cause errors if we return to the initial microfrontend, as the related plugin was installed only in the first mount.

By the moment we have decided adding a suffix to every client for avoid crashes between apps like:

Vue.client_app1 = client;
Vue.prototype.$client_app1 = client;
Vue.client_app2 = client;
Vue.prototype.$client_app2 = client;

This strategy works fine but get it working with the same name would be great. Another way is undo the external dependency for vue and keep one vue instance for every app with the vue-cli --inline-vue param, but it is not the desired scenario.

Is there any way of fix the error I am reporting without using a custom name for one plugin in every micro frontend?

Thank you so much.

I'm not Joel, but I'd like to help if possible.

What you've done is what is recommended in the Vue documentation of "The Importance of Scoping Instance Properties". This problem would exist even if you were not using single-spa since each of those components is overriding the previous one's. That's just the nature of modifying a global (in this case, the Vue instance). They also include this alternative:

When you have access to a module system, you can easily organize shared code into modules, then require/import those modules wherever they’re needed. This is the epitome of explicitness, because in each file you gain a list of dependencies. You know exactly where each one came from.

While certainly more verbose, this approach is definitely the most maintainable, especially when working with other developers and/or building a large app.

It would seem to me that in this case, you should extract that client/plugin into a local module that you import in every file that needs it, and never ever attaching it to the Vue instance.

Hi @filoxo !

Thank you so much for your answer and sharing this content. We will follow the guidelines of this cookbook for avoid this crash and let webpack to manage every load.