I have started using the new defineCustomElement feature in Vue version 3.2.
Here is an example code snippet from 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],
})
)
In the implementation file defineCustomElementWithStyles.js
:
import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'
const getNearestElementParent = (el) => {
while (el?.nodeType !== 1 /* ELEMENT */) {
el = el.parentElement
}
return el
}
export const defineCustomElement = (component, { plugins = [] }) =>
VueDefineCustomElement({
render: () => h(component),
setup() {
const app = createApp()
// install plugins
plugins.forEach(app.use)
app.mixin({
mounted() {
const insertStyles = (styles) => {
if (styles?.length) {
this.__style = document.createElement('style')
this.__style.innerText = styles.join().replace(/\n/g, '')
getNearestElementParent(this.$el).prepend(this.__style)
}
}
// load own styles
insertStyles(this.$?.type.styles)
// load styles of child components
if (this.$options.components) {
for (const comp of Object.values(this.$options.components)) {
insertStyles(comp.styles)
}
}
},
unmounted() {
this.__style?.remove()
},
})
const inst = getCurrentInstance()
Object.assign(inst.appContext, app._context)
Object.assign(inst.provides, app._context.provides)
},
})
In the component file App.ce.vue
, I register and use a prop
:
<template>
<div id="app">
<p>{{ title }}</p>
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<main>
<router-view />
</main>
</div>
</template>
<script>
export default {
name: 'App',
props: {
title: String,
},
}
</script>
In the index.html
where I set the value for the prop title
:
<app-root title="hello"></app-root>
When running, I encountered an error message:
Uncaught TypeError: Cannot read properties of undefined (reading 'title')
You can find the full demo project here