Search code examples
javascriptvue.jsvuexvue-routervuejs3

How to use vue router and vuex inside custom element from root?


I have project with nested custom elements. Now I need to vuex & vue router. How I can use this packages from root custom element and then use in all child custom elements?

Currently I tried only use vuex inside each component like this:

<script>
import store from './store';

export default {
  setup() {
    const state = store.state;

    return { state };
  },
};
</script>

Here is demo project with nested custom elements

Here is my main.js file code:

import { defineCustomElement } from "./defineCustomElementWithStyles";
import App from "./App.ce.vue";

customElements.define("app-root", defineCustomElement(App));

Solution

  • Vue plugins require the app instance, which is not defined for components created from defineCustomElement(). As a workaround, you can install the plugins on a temporary app instance, and then copy the resulting context over to the actual app, as seen in this utility (which we'll use later):

    // defineCustomElementWithStyles.js
    import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'
    
    export const defineCustomElement = (component, { plugins = [] } = {}) =>
      VueDefineCustomElement({
        render: () => h(component),
        setup() {
          const app = createApp()
    
          // install plugins
          plugins.forEach(app.use)
    
          const inst = getCurrentInstance()
          Object.assign(inst.appContext, app._context)
          Object.assign(inst.provides, app._context.provides)
        },
      })
    

    Use the defineCustomElement() above instead of the one from vue:

    // main.js
    import { defineCustomElement } from './defineCustomElementWithStyles'
    import App from './App.ce.vue'
    import store from './store'
    import router from './router'
    
    customElements.define(
      'app-root',
      defineCustomElement(App, {
        plugins: [store, router],
      })
    )
    

    demo