1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { loadModule as loadModuleRaw } from "https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.9.5/dist/vue3-sfc-loader.esm.js";
import * as Vue from "https://cdn.jsdelivr.net/npm/vue@3.4.20/dist/vue.esm-browser.prod.js";
import { html, htmlResponse, RawHTML, rawHtml } from "https://esm.town/v/postpostscript/html";
export { Vue };
export function vueSfc(name: string, template: string) {
window.moduleCache ??= {
vue: Vue,
};
return Vue.defineAsyncComponent(() =>
loadModuleRaw(`${name}.vue`, {
moduleCache: window.moduleCache,
async getFile(url) {
if (url === `${name}.vue`) {
return template;
}
if (url.slice(-4) !== ".vue") {
console.log("importing", url)
const mod = await import(url);
return {
type: "module",
getContentData() {
return mod;
},
};
}
const res = await fetch(url);
if (!res.ok)
throw Object.assign(new Error(res.statusText + " " + url), { res });
return {
getContentData: asBinary => asBinary ? res.arrayBuffer() : res.text(),
};
},
async handleModule(type, getContentData) {
if (type === "module") {
return getContentData();
}
},
addStyle(textContent) {
const style = Object.assign(document.createElement("style"), { textContent });
const ref = document.head.getElementsByTagName("style")[0] || null;
document.head.insertBefore(style, ref);
},
})
);
}
export function vueSfcInline(strings: TemplateStringsArray, ...replacements: any[]) {
const id = rawHtml`vueSfcInline-${Math.random().toString().slice(3)}`;
const template = strings.reduce((prev, next, i) => {
return `${prev}${replacements[i - 1] || ""}${next}`;
});
return html`
<span id="${id}">Loading component...</span>
<script type="module">
import { Vue, vueSfc } from "${new RawHTML(import.meta.url)}";
Vue.createApp({
components: {
InlineComponent: vueSfc("${id}", decodeURIComponent("${new RawHTML(encodeURIComponent(template))}")),
},
template: '<inline-component></inline-component>',
}).mount("#${id}");
</script>
`;
}