I have a page rendered from the back-end and I was hoping to be able to load Vue3 and mount the app and components without an ID. I was informed that this isn't difficult, but clearly my Vue kung fu is weak. I thought this would be a fairly common flow, or maybe I'm looking in the wrong places. I did stumble on petite-vue, but the use at your own risk warning is sketchy for a production build.
This is where I'm at so far, any help is greatly appreciated:
Pre-rendeded markup:
<body>
<hello-world :msg="prop passed from BE"></hello-world>
</body>
vue.config.js:
module.exports = {
filenameHashing: false,
runtimeCompiler: true,
transpileDependencies: true,
configureWebpack: {
devtool: "eval-source-map",
entry: {
main: "../exec.js",
},
},
productionSourceMap: true
};
Exec.js (entry point):
import HelloWorld from "./src/components/HelloWorld.vue"
import { createApp } from "vue";
import compile from "vue"
const app = createApp({})
app.mount()
app.component("HelloWorld", HelloWorld)
HelloWorld.vue:
<template>
<div>
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: null,
},
},
name: "HelloWorld",
};
</script>
</script>
<style lang="scss">
.root {
text-align: center;
color: red;
}
</style>
I did notice something while writing this question. If I load https://unpkg.com/[email protected]/dist/vue.global.js and then mount #app it's non-destructive and I weirdly can even see the styles from helloworld.vue being applied, but no template rendering.
app.vue:
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
components: {
HelloWorld
},
};
</script>
exec.js:
import { createApp } from "vue";
import App from "./src/App.vue"
const app = createApp(App)
app.mount("app")
HTML:
<body id="app">
<hello-world :msg="prop passed from BE"></hello-world>
</body>
You can create and mount a component to any DOM element you want:
import { createVNode, render } from 'vue';
export function mountComponent(app, elem, component, props) {
let vNode = createVNode(component, props);
vNode.appContext = app._context;
render(vNode, elem);
return vNode.component;
}
To match your prerendered HTML:
<body>
<hello-world data-msg="prop passed from BE"></hello-world>
</body>
import {app} from './exec';
import HelloWorld from "./components/HelloWorld.vue";
import {mountComponent} from './utils';
document.querySelectorAll('hello-word').forEach(elem => {
mountComponent(app, elem, HelloWorld, elem.dataset);
// we try to remove <hello-world>, not sure about to work ok
// move the component's DOM before the <hello-word>
elem.children.forEach(child => elem.parent.insertBefore(child, elem));
// remove <hello-world> not to clutter the page
elem.remove();
});
You could also try to use Web Components: https://vuejs.org/guide/extras/web-components.html
Overall it's an interesting topic, tomorrow I'll try to bring some live examples on my github.
Moreover it's more interesting with Vite's globbing your components and putting them into the DOM automatically... Will try to make an example tomorrow. Time to sleep.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments