single-spa / single-spa-vue

a single-spa plugin for vue.js applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

(Vue 3) Cannot load Vue app with error "Promise rejection: Cannot convert object to primitive value"

smilyanp opened this issue · comments

In our teams we have been using single SPA for a while and love it. The different teams use Angular, React and Vue applications. They all work really well together. However, recently we tried to convert one of the Vue applications from version 2 to version 3 with Typescript and that's when we encountered problems.

To Replicate

I have setup an example repository with instructions to replicate here: https://github.com/smilyanp/mf-setup

The error

The error we see is this:

image

In more detail

I don't claim that we're doing everything correctly, but this is what has worked previously and now it doesn't, thus me raising the issue.

The setup is simple, in the host application we load:

{
    "imports": {
        "@mf-setup/react-app": "/node_modules/@mf-setup/react-app/dist/react-app.umd.js",
        "@mf-setup/vue-app": "/node_modules/@mf-setup/vue-app/dist/index.umd.js"
    }
}

And we register the application as:

singleSpa.registerApplication(
    'react-app',
    () => load('@mf-setup/react-app'),
    showWhenPrefix(['/user-management', '/user/profile']),
    { environment, eventBus, features },
  );

  singleSpa.registerApplication(
    'vue-app',
    () => load('@mf-setup/vue-app'),
    showWhenPrefix(['/user/profile']),
    { environment, eventBus, features },
  );

That all works ok and there is no issue loading the source for each application under the respective route.

This is where things become a bit more difficult and potentially we are doing it incorrectly, but again, it has worked previously.

The React application loads the contents of the Vue application for a given route

In our case, the React application has a lot of different functionality and we want it to load the contents of the Vue application which should be independent. To do so, the React application provides a placeholder element on it's route, a <div id="vue-app"></div> with an ID that the Vue application can bind to:

<Router>
        <Switch>
          <Route path="/user-management" component={() => {
            return (
              <div>
                <h2>React App Content:</h2>
                <div>Some content provided by the react app</div>
              </div>
            )
          }} />
          <Route exact path="/user/profile" component={() => {
          return (
            <div>
              <h2>Vue App Content:</h2>
              <div id="vue-app"></div>
            </div>)
          }} />
        </Switch>
      </Router>

When the user goes to /user/profile route the @mf-setup/vue-app source code correctly loads on the page (the console.logs show that and also the network tab).

Inside of the Vue application we abstract the mount to wait until the HTML element is available in the DOM thus:

vueLifecycles = singleSpaVue({
    createApp,
    appOptions: {
        render () {
            return h(App, {
                name: this.name,
                // @ts-expect-error single-spa docs claim these properties exist...
                mountParcel: this.mountParcel,
                // @ts-expect-error single-spa docs claim these properties exist...
                singleSpa: this.singleSpa,
            });
        },
        el: `#vue-app`,
    },
    replaceMode: true,
});

mount = async (props) => {
    waitForElement('vue-app', () => vueLifecycles.mount(props));
};

export { mount, unmount, bootstrap };

This has worked previously without issues, and also we can see that the <App /> component is mounted as well, because in the created() lifecycle hook there is a console.log that appears in the console.

However, the contents of that component are never rendered on the page and instead we see the error shown above.

Any help on this would greatly be appreciated.

Hi,
I wanted to install your example to try to help you. But your package-lock in the react folder points to presumably your companies internal npm registries. If other maintainers/contributors want to help you it would make their lives easier if you find and replace the package-locks with a public npm registry.

I tried setting up your project but following the readme and trying around a bit myself, I can't get it to run properly. During the link:host an error occurs:

npm ERR! Could not resolve dependency:
npm ERR! peer webpack@"^5" from string-replace-loader@3.1.0

Maybe you can update it so people can take a closer look?

not recognized props will be treated as attr,which will be set to dom node. if the attr value is a object, this error shows

Thank you @Lalaluka and @shiye515. I will look into this again. @Lalaluka you are right, I need to update the package-lock file, sorry about that.