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 defineConfig from "./packages/define-config";
|
||||||
// import registerComponents from "./packages/register-components";
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// onBuild: [registerComponents()],
|
components: "js",
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { NitroApp } from "nitropack";
|
||||||
|
|
||||||
export type McFlyConfig = {
|
export type McFlyConfig = {
|
||||||
onBuild?: Array<(event: NitroApp) => void>;
|
onBuild?: Array<(event: NitroApp) => void>;
|
||||||
|
components: "js" | "ts";
|
||||||
};
|
};
|
||||||
export default function defineConfig(config: McFlyConfig) {
|
export default function defineConfig(config: McFlyConfig) {
|
||||||
return () => config;
|
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
|
* 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 { parseScript } from "esprima";
|
||||||
|
import config from "../mcfly.config";
|
||||||
|
|
||||||
export default eventHandler(async (event) => {
|
export default eventHandler(async (event) => {
|
||||||
const { path } = event;
|
const { path } = event;
|
||||||
let html = await getHtml(path);
|
let html = await getHtml(path);
|
||||||
|
|
||||||
|
const { components: componentType } = config();
|
||||||
|
|
||||||
// transforms
|
// transforms
|
||||||
const transforms = [doSetUp, deleteServerScripts, insertRegistry];
|
const transforms = [doSetUp, deleteServerScripts];
|
||||||
if (html) {
|
if (html) {
|
||||||
for (const transform of transforms) {
|
for (const transform of transforms) {
|
||||||
html = transform(html.toString());
|
html = transform(html.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!!componentType) {
|
||||||
|
html = await insertRegistry(html.toString(), componentType);
|
||||||
|
}
|
||||||
|
|
||||||
return html ?? new Response("Not found", { status: 404 });
|
return html ?? new Response("Not found", { status: 404 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,30 +43,60 @@ function getPath(filename: string) {
|
||||||
return `assets/pages${filename}`;
|
return `assets/pages${filename}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertRegistry(html: string): string {
|
async function insertRegistry(
|
||||||
// temporary; use ultrahtml later
|
html: string,
|
||||||
const registryScript =
|
type: "js" | "ts"
|
||||||
'<script type="module" src="./.output/registry.js"></script>';
|
): Promise<string> {
|
||||||
|
|
||||||
const ast = parse(html);
|
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) => {
|
walkSync(ast, (node) => {
|
||||||
if (node.type === ELEMENT_NODE && node.name.includes("-")) {
|
const usedElement = availableComponents.find((name) => name === node.name);
|
||||||
hasCustomElements = true;
|
|
||||||
|
if (node.type === ELEMENT_NODE && !!usedElement) {
|
||||||
|
usedCustomElements.push(usedElement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// insert registry script to head
|
// insert registry script to head
|
||||||
if (hasCustomElements)
|
if (usedCustomElements.length > 0) {
|
||||||
|
const registryScript = await buildRegistry(usedCustomElements, type);
|
||||||
walkSync(ast, (node) => {
|
walkSync(ast, (node) => {
|
||||||
if (node.type === ELEMENT_NODE && node.name === "head") {
|
if (node.type === ELEMENT_NODE && node.name === "head") {
|
||||||
node.children.push(parse(registryScript));
|
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) {
|
function doSetUp(html: string) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@1.6.15/WebComponent.js";
|
class ClickableText extends WebComponent {
|
||||||
|
|
||||||
export default class ClickableText extends WebComponent {
|
|
||||||
onInit() {
|
onInit() {
|
||||||
this.onclick = () => alert("Thank you for clicking the text!");
|
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";
|
class HelloWorld extends WebComponent {
|
||||||
|
|
||||||
export default class HelloWorld extends WebComponent {
|
|
||||||
name = "";
|
name = "";
|
||||||
static properties = ["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