single-spa set Vue as an external: defineComponent is not a function

1.2k Views Asked by At

I am using Vue with single-spa and I decided to try to reduce the bundle size. To do this, first I started by trying to set Vue as an external dependency by setting it in webpack.config.js of each Micro Front-end

 externals: ['single-spa', 'vue'],

and setting in the root config the following:

   <script type="systemjs-importmap">
{
  "imports": {
    "single-spa": "https://cdn.jsdelivr.net/npm/[email protected]/lib/system/single-spa.min.js",
    "vue": "https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.34/vue.global.min.js"
  }
}

</script>
<link rel="preload" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/system/single-spa.min.js" as="script"
      crossOrigin="anonymous">

<link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.34/vue.global.min.js" as="script"
      crossOrigin="anonymous">

but when I try to load, it crashes with the following:

Uncaught TypeError: application '@workspace/foo' died in status LOADING_SOURCE_CODE: (0 , t.defineComponent) is not a function
    at vue-router.esm-bundler.js:2123:38
    at main.ts:32:38
    at Object.execute (main.ts:32:38)
    at doExec (system.js:469:34)
    at postOrderExec (system.js:465:12)
    at system.js:422:14

and also for another

Uncaught TypeError: application '@workspace/bar' died in status LOADING_SOURCE_CODE: (0 , o.ref) is not a function
    at Object.9828 (quasar.esm.prod.jss:6:510)
    at s (bootstrapp:19:32)
    at 1.jss:3:16
    at main.tss:54:28
    at Object.execute (main.tss:54:28)
    at doExec (system.js:469:34)
    at postOrderExec (system.js:465:12)
    at system.js:422:14
2

There are 2 best solutions below

0
Eduardo Sousa On BEST ANSWER

I really don't know why, but using exactly this made it work

 <script type="systemjs-importmap">
    {
      "imports": {
        "single-spa": "https://cdn.jsdelivr.net/npm/[email protected]/lib/system/single-spa.min.js",
        "vue": "https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.29/vue.global.prod.min.js",
        "vue-router": "https://cdnjs.cloudflare.com/ajax/libs/vue-router/4.0.12/vue-router.global.prod.min.js",
        "vue-i18n": "https://cdnjs.cloudflare.com/ajax/libs/vue-i18n/9.2.0-beta.35/vue-i18n.global.prod.min.js"
      }
    }

    </script>
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/system/single-spa.min.js" as="script"
          crossOrigin="anonymous">
    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.29/vue.global.prod.min.js" as="script"
          crossOrigin="anonymous">
1
Lalaluka On

You are using a vue3 Version in your externals and Vue3's API is different from vue2.

I guess you are using quasar and vue-router in a version built for vue2, or your full Application might be built on vue2, so the different APIs will clash.

If you have Vue2 and Vue3 Microfrontends you can define two externals:

"vue": "https://vue2location.example",
"vue3": "https://vue3location.example"

And in your vue.config.js you can use named externals like this to rename from vue3 to vue:

config.externals({
  vue: 'vue3'
})

(in theory you could use any naming you want)