feat: on-route component registry resolution
This commit is contained in:
parent
058b112747
commit
7b1fc863ef
9 changed files with 54 additions and 66 deletions
|
@ -1,6 +1,5 @@
|
|||
import defineConfig from "./packages/define-config";
|
||||
// import registerComponents from "./packages/register-components";
|
||||
|
||||
export default defineConfig({
|
||||
// onBuild: [registerComponents()],
|
||||
components: "js",
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ import { NitroApp } from "nitropack";
|
|||
|
||||
export type McFlyConfig = {
|
||||
onBuild?: Array<(event: NitroApp) => void>;
|
||||
components: "js" | "ts";
|
||||
};
|
||||
export default function defineConfig(config: McFlyConfig) {
|
||||
return () => config;
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
import { existsSync, promises as fsp } from "node:fs";
|
||||
|
||||
export default function registerComponents() {
|
||||
return () => {
|
||||
copyComponents();
|
||||
buildRegistry();
|
||||
};
|
||||
}
|
||||
|
||||
const copyComponents = async () => {
|
||||
const rawKeys = await useStorage().getKeys("assets:components");
|
||||
rawKeys.forEach(async (key) => {
|
||||
const cleanKey = key.replace("assets:components:", "");
|
||||
const content = await useStorage().getItem(key);
|
||||
if (!existsSync("./public/.output")) await fsp.mkdir("./public/.output");
|
||||
await fsp.writeFile(`./public/.output/${cleanKey}`, content.toString());
|
||||
});
|
||||
};
|
||||
|
||||
const buildRegistry = async () => {
|
||||
console.log("Building registry of custom elements...");
|
||||
const rawKeys = await useStorage().getKeys("/assets/components");
|
||||
const keys = rawKeys.map((key) => key.replace("assets:components:", ""));
|
||||
console.log("Found components:", keys);
|
||||
const imports = keys.map((key, index) => {
|
||||
return `import C${index} from "./${key}"`;
|
||||
});
|
||||
|
||||
const registryObject = `const registry = {
|
||||
${keys
|
||||
.map((key, index) => {
|
||||
const name = key.replace(".js", "").replace(".ts", "");
|
||||
return `"${name}": C${index}`;
|
||||
})
|
||||
.join(",")}}`;
|
||||
|
||||
const customElementsDefine = `Object.keys(registry).forEach((key) => {if(window?.hasOwnProperty("customElements"))customElements.define(key, registry[key]);})`;
|
||||
|
||||
if (!existsSync("./public")) await fsp.mkdir("./public");
|
||||
if (!existsSync("./public/.output")) await fsp.mkdir("./public/.output");
|
||||
|
||||
await fsp.writeFile(
|
||||
"./public/.output/registry.js",
|
||||
[...imports, registryObject, customElementsDefine].join(";")
|
||||
);
|
||||
};
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
|
@ -2,21 +2,28 @@
|
|||
* McFly SSR logic
|
||||
*/
|
||||
|
||||
import { ELEMENT_NODE, parse, renderSync, walkSync } from "ultrahtml";
|
||||
import { ELEMENT_NODE, parse, render, renderSync, walkSync } from "ultrahtml";
|
||||
import { parseScript } from "esprima";
|
||||
import config from "../mcfly.config";
|
||||
|
||||
export default eventHandler(async (event) => {
|
||||
const { path } = event;
|
||||
let html = await getHtml(path);
|
||||
|
||||
const { components: componentType } = config();
|
||||
|
||||
// transforms
|
||||
const transforms = [doSetUp, deleteServerScripts, insertRegistry];
|
||||
const transforms = [doSetUp, deleteServerScripts];
|
||||
if (html) {
|
||||
for (const transform of transforms) {
|
||||
html = transform(html.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (!!componentType) {
|
||||
html = await insertRegistry(html.toString(), componentType);
|
||||
}
|
||||
|
||||
return html ?? new Response("Not found", { status: 404 });
|
||||
});
|
||||
|
||||
|
@ -36,30 +43,60 @@ function getPath(filename: string) {
|
|||
return `assets/pages${filename}`;
|
||||
}
|
||||
|
||||
function insertRegistry(html: string): string {
|
||||
// temporary; use ultrahtml later
|
||||
const registryScript =
|
||||
'<script type="module" src="./.output/registry.js"></script>';
|
||||
|
||||
async function insertRegistry(
|
||||
html: string,
|
||||
type: "js" | "ts"
|
||||
): Promise<string> {
|
||||
const ast = parse(html);
|
||||
const componentFiles = (await useStorage().getKeys("assets:components"))
|
||||
.map((key) => key.replace("assets:components:", ""))
|
||||
.filter((key) => key.includes(type));
|
||||
const availableComponents = componentFiles.map((key) =>
|
||||
key.replace(`.${type}`, "")
|
||||
);
|
||||
|
||||
let hasCustomElements = false;
|
||||
const usedCustomElements = [];
|
||||
|
||||
walkSync(ast, (node) => {
|
||||
if (node.type === ELEMENT_NODE && node.name.includes("-")) {
|
||||
hasCustomElements = true;
|
||||
const usedElement = availableComponents.find((name) => name === node.name);
|
||||
|
||||
if (node.type === ELEMENT_NODE && !!usedElement) {
|
||||
usedCustomElements.push(usedElement);
|
||||
}
|
||||
});
|
||||
|
||||
// insert registry script to head
|
||||
if (hasCustomElements)
|
||||
if (usedCustomElements.length > 0) {
|
||||
const registryScript = await buildRegistry(usedCustomElements, type);
|
||||
walkSync(ast, (node) => {
|
||||
if (node.type === ELEMENT_NODE && node.name === "head") {
|
||||
node.children.push(parse(registryScript));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return renderSync(ast);
|
||||
return render(ast);
|
||||
}
|
||||
|
||||
async function buildRegistry(usedCustomElements: string[], type: "js" | "ts") {
|
||||
let registryScript = `<script type='module'>
|
||||
import { WebComponent } from "https://unpkg.com/web-component-base@1.6.15/WebComponent.js";
|
||||
`;
|
||||
|
||||
for (const name of usedCustomElements) {
|
||||
const content = await useStorage().getItem(
|
||||
`assets:components:${name}.${type}`
|
||||
);
|
||||
registryScript += content;
|
||||
const evalStore = eval(`class WebComponent {};(${content.toString()})`);
|
||||
const className = new evalStore().constructor.name;
|
||||
|
||||
registryScript += `customElements.define("${name}", ${className});`;
|
||||
}
|
||||
|
||||
registryScript += "</script>";
|
||||
|
||||
return registryScript;
|
||||
}
|
||||
|
||||
function doSetUp(html: string) {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { WebComponent } from "https://unpkg.com/web-component-base@1.6.15/WebComponent.js";
|
||||
|
||||
export default class ClickableText extends WebComponent {
|
||||
class ClickableText extends WebComponent {
|
||||
onInit() {
|
||||
this.onclick = () => alert("Thank you for clicking the text!");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { WebComponent } from "https://unpkg.com/web-component-base@1.6.15/WebComponent.js";
|
||||
|
||||
export default class HelloWorld extends WebComponent {
|
||||
class HelloWorld extends WebComponent {
|
||||
name = "";
|
||||
static properties = ["name"];
|
||||
|
||||
|
|
1
src/components/something-else.ts
Normal file
1
src/components/something-else.ts
Normal file
|
@ -0,0 +1 @@
|
|||
const hey = "AYO";
|
Loading…
Reference in a new issue