Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a base path to vite.config.js host module in vue3-demo-esm-expose-store pinia store sharing doesn't work #542

Open
fbrillante opened this issue Nov 14, 2023 · 6 comments

Comments

@fbrillante
Copy link

Versions

  • vite-plugin-federation: 1.3.2
  • vite: 4.1.4

Reproduction

Adding a base path to vite.config.js, the pinia store sharing doesnt' work.
To reproduce the issue you can start from "vue3-demo-esm-expose-store" demo and add the following property:

base: "/test",
in config object defined here (e.g. line 28):
https://github.com/originjs/vite-plugin-federation/blob/main/packages/examples/vue3-demo-esm-expose-store/host/vite.config.ts

The host app will run with the specified base path but the store initialization will fail with the following error:

image

Uncaught Error: [🍍]: "getActivePinia()" was called but there was no active Pinia. Are you trying to use a store before calling "app.use(pinia)"?

@fbrillante
Copy link
Author

fbrillante commented Nov 14, 2023

Found a workaround I'll put here for future reference, if someone gets the same error, but however is not suitable for production environment
You can get rid of it adding the following configuration in server section:

**server: {
    origin: "http://localhost:5173/test",
},**

Can the usage of window.location.href in the "wrapShareScope" function be a fix on the library?

image

@TimGundmann
Copy link

I have the same problem, any fixes for the problem?

@amidnikmal
Copy link

Hello, I'm encountering a problem when specifying a relative path inside base: "/test". Is there an official solution?

@amidnikmal
Copy link

Found a workaround I'll put here for future reference, if someone gets the same error, but however is not suitable for production environment You can get rid of it adding the following configuration in server section:

**server: {
    origin: "http://localhost:5173/test",
},**

Can the usage of window.location.href in the "wrapShareScope" function be a fix on the library?

image

It appears that the issue lies in the order of module loading. As seen in the screenshot, the defineStore of the Pinia store module from the host app (the app from which the Pinia module is exposed) is loaded before the createPinia call of the local app (the app that uses the exposed Pinia module).

Therefore, there should be a way to specify the exact order of loading modules while in development mode.

This error only occurs in development mode.

image

@amidnikmal
Copy link

It seems like the order doesn't matter. In the production build, the order is the same. However, when the local app is in development mode (but the host is in production), the getCurrentInstance call on the side of the local app returns nothing inside of the useStore function of Pinia's internal code. But in production mode, everything works fine. By the way, the error occurred when the host app was running in production mode (using Vite preview), but the local app was running in development mode. However, when both sides are in production mode, there are no errors.

@amidnikmal
Copy link

amidnikmal commented Apr 2, 2024

I figure it out. The Pinia module loads twice and rewrites some of its own internal state.

You can investigate in the following steps: You need mainApp and remoteApp. MainApp exposes some stores with a default store - you run it through npm run build && vite preview.

But remoteApp, you run through the dev way - just vite --host.

In that case, inside main.ts of remoteApp, it will be something like this.


import { createPinia }  from  'pinia'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)

That code will trigger first loading of local dependency . It can be seen inside the Nework tab - the name of file will something like this :
http://172.25.64.96:5173/dictionary/node_modules/.vite/deps/pinia.js?v=253339aa

Secondly, App.vue will be mounted, and the code inside of which will be something like this

<script setup lang="ts">
import { getCurrentInstance } from 'vue'

import { useAuthStore } from 'mainApp/auth-store'

const instance = getCurrentInstance()
console.log("INSTANCE", instance)


const authStore = useAuthStore()
console.log("AUTH STORE", authStore)

</script>

<template>
  APP
</template>

As you can see there are import { useAuthStore } from 'mainApp/auth-store'

That module will be imported second time through vite-module-federation plugin , because the generated code of useAuthStore will something like this :

import { importShared } from './__federation_fn_import-1d150bd9.js';

const {defineStore} = await importShared('pinia');

console.log("DEFINE STORE", defineStore);
const token = localStorage.getItem("token");
const useAuthStore = defineStore({
  id: "auth",
  state: () => ({
    token,
    login: "",
    data: null,
    loading: false,

importShared will do some magic , but it totally ignores already imported dependency http://172.25.64.96:5173/dictionary/node_modules/.vite/deps/pinia.js?v=253339aa

importShared will import pinia again from file __federation_fn_import-1d150bd9.js using moduleMap from __federation_fn_import-1d150bd9.js

// eslint-disable-next-line no-undef
const moduleMap = {
  'vue':{get:()=>()=>__federation_import(new URL('__federation_shared_vue-fee7d8a8.js', import.meta.url).href),import:true},
  'vue-router':{get:()=>()=>__federation_import(new URL('__federation_shared_vue-router-28720dca.js', import.meta.url).href),import:true},
  'pinia':{get:()=>()=>__federation_import(new URL('__federation_shared_pinia-04447d99.js', import.meta.url).href),import:true},
  '@vueuse/core':{get:()=>()=>__federation_import(new URL('__federation_shared_@vueuse/core-57dd04b9.js', import.meta.url).href),import:true},
  'element-plus':{get:()=>()=>__federation_import(new URL('__federation_shared_element-plus-4836b0d5.js', import.meta.url).href),import:true},
  'vue-i18n':{get:()=>()=>__federation_import(new URL('__federation_shared_vue-i18n-b86e26b4.js', import.meta.url).href),import:true}};

and secondly rewrites pinia module internals .

To prove that, you can go to remoteApp/node_modules/pinia/dist/pinia.mjs and at the top of the file, write code like this

const tag =Math.random()
console.log(tag)

And print it also in defineStore and useStore functions- you will see , that the tag will be different in some cases.

So, to solve that ( at least temporary ) you can explicitly export the entire pinia module from mainApp

// mainApp : pinia.ts
import * as piniaModule from 'pinia'
export { piniaModule }

// mainApp : vite.config.ts

  federation({
      name: 'mainApp',
      filename: 'remoteEntry.js',
      exposes: {
        "./auth-store": "./src/store/auth.ts",
        "./pinia": "./src/store/pinia.ts",
      },

And at remoteApp import it like this:


//main.ts

import { piniaModule } from 'mainApp/pinia'
const { createPinia }  = piniaModule;
....

const pinia = createPinia()
app.use(pinia)
app.mount('#app')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants