I want to compile sfc string as a component like this:
<script setup>
import { parseToComponent } from './';
const sfcString = `
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
<template>
<div class="label">{{ count }}</div>
<button @click="count++">increase</button>
</template>
<style scoped>
.label {
color: red;
}
</style>
`;
const parsedComponent = parseToComponent(sfcString);
</script>
<template>
<div>
<parsedComponent />
</div>
</template>
<style scoped>
</style>
How can I do this?
I tried to use vue/compiler-sfc
to parse and compile sfcString
, but I don't know how to convert it to component:
import { parse, compileTemplate, compileScript, compileStyle } from 'vue/compiler-sfc';
export function parseToComponent(sfcString) {
const { descriptor } = parse(sfcString);
const scriptOptions = ...;
const templateOptions = ...;
const styleOptions = ...;
// succeed, but how to use them to take a component?
const script = compileScript(descriptor, scriptOptions);
const template = compileTemplate(templateOptions);
const style = compileStyle(styleOptions);
}
I used vue3-sfc-loader to implemented it:
import * as Vue from 'vue';
import { loadModule } from 'vue3-sfc-loader';
export function parseToComponent(sfcString) {
const id = genRandomId(id);
const options = {
moduleCache: { vue: Vue },
async getFile(url) {
return Promise.resolve(sfcString);
},
addStyle(styleString) {
let style = document.getElementById(id);
if (!style) {
style = document.createElement('style');
style.setAttribute('id', id);
const ref = document.head.getElementsByTagName('style')[0] || null;
document.head.insertBefore(style, ref);
}
style.textContent = styleString;
}
};
const component = loadModule(`${id}.vue`, options);
return Vue.defineAsyncComponent(() => component);
}
Use in code(need markRaw()
):
<script setup>
import { markRaw } from 'vue';
import { parseToComponent } from './';
const sfcString = `...`;
const parsedComponent = markRaw(parseToComponent(sfcString));
</script>
<template>
<div>
<parsedComponent />
</div>
</template>