Home > OS >  Inject Vue component from diet js file
Inject Vue component from diet js file

Time:09-06

I have a very simple app vue3:

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

let currentApp = createApp(App);
(window as any).load(currentApp);
currentApp.mount('#app');

In the index.html file i import a dist lib:

<script src="http://localhost:5173/dist/assets/index.59eda240.js">

The content of dist JS is:

import HelloWorld from './components/HelloWorld.vue'

(window as any).load = (app: any) => {
    app.component('hello-world', HelloWorld);
}

If i use a very simple HelloWorld.vue with just one line of text "Hello", all works fine, but if i put some css classes or more complicated component i obtain:

[Vue warn]: Invalid VNode type: Symbol() (symbol) at <HelloWorld>
at <App>

How can i solve this? Or is there another way to load component at runtime?

Thanks in advance.

P.s. I have no problem doing the same thing with Vue

--------- UPDATE MORE INFO ----------

Vue version

3.2.38

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-744fbh?file=src/main.js

Steps to reproduce

The base idea is to have a main app the create a Vue app, and another external lib the load component at runtime.

Open the sample project and show console log to see "Invalid VNode type: Symbol() (symbol)"

What is expected?

I expect to see the components rendered correctly

What is actually happening?

I don't see the component UI, but looking at the console I see the logic code works correctly but we have a warning: Invalid VNode type: Symbol() (symbol) Invalid VNode type: Symbol() (symbol)

System Info

No response

Any additional comments?

This warning appears only in some components, for example, fur a very simple component, it works fine, see here: https://stackblitz.com/edit/vitejs-vite-nueucw?file=src/App.vue.

You can see the source of helloworld component at the top of lib.js file, inside a comment block

CodePudding user response:

The actual problem is that there are multiple Vue library copies per page that interact with each other. This should be avoided, preferably by bundling multiple parts of the application together, so multiple apps would reuse the same modules from vendors chunk. In case this isn't possible or practical, a simple workaround is to use Vue CDN for all applications, either by using window.Vue instead of vue import, or aliasing the import to global variable by means of a bundler.

The root cause is that Vue built-in element are specific to Vue copy in use - Fragment, Teleport, Comment, etc. They are defined with Symbol() to be distinguished from other elements and components and used in compiled component templates. Symbol is used in JavaScript to define unique tokens, Symbol('foo') !== Symbol('foo'). The symbols of built-in elements from one Vue copy mean nothing to another Vue copy, this is the meaning of this error message.

It can be seen in this analyzer that this component template:

<h1 style="background-color:Red; font-size: 44px;">{{ msg }}</h1>
<button @click="msg = 'click';">CLICK</button>

is compiled to this render function:

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(_Fragment, null, [
    _createElementVNode("h1", { style: {"background-color":"Red","font-size":"44px"} }, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createElementVNode("button", {
      onClick: $event => {_ctx.msg = 'click';}
    }, "CLICK", 8 /* PROPS */, ["onClick"])
  ], 64 /* STABLE_FRAGMENT */))
}

Notice that the use of multiple root elements results in wrapping them in Fragment, which won't be correctly processed by multiple Vue copies, etc.

CodePudding user response:

Change hello world with another component:

<template>
  <div >
    <div >


      <div  style="background-color: yellow;">
        <div  style="background-color: orange;">
          <div   style="background-color: brown;">
            <div >
              <h5 >test</h5>
              <p>
                test
              </p>
            </div>
          </div>
          <div>
            <div>
              test2
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

Only one root element, I have the same issue.

  • Related