From fb8192f367a9ab189067b088225b3d26b76c459e Mon Sep 17 00:00:00 2001 From: Ayo Date: Sat, 21 Oct 2023 15:56:36 +0200 Subject: [PATCH] fix(core): use mcfly config in eventHandler --- app/routes/[...index].ts | 2 +- package-lock.json | 7 +- package.json | 3 +- packages/core/index.ts | 42 +++-- packages/core/package.json | 5 +- templates/basic/package.json | 4 +- templates/basic/routes/[...index].ts | 260 +-------------------------- 7 files changed, 34 insertions(+), 289 deletions(-) diff --git a/app/routes/[...index].ts b/app/routes/[...index].ts index f5e0c55..64393bf 100644 --- a/app/routes/[...index].ts +++ b/app/routes/[...index].ts @@ -3,4 +3,4 @@ */ import McFly from "@mcflyjs/core"; import config from "../mcfly.config"; -export default McFly(config, useStorage); +export default McFly(config, useStorage()); diff --git a/package-lock.json b/package-lock.json index 3ac5445..0f26997 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3979,13 +3979,14 @@ }, "packages/core": { "name": "@mcflyjs/core", - "version": "0.0.1", + "version": "0.1.0", "license": "MIT", "dependencies": { "esprima": "^4.0.1", "h3": "^1.8.2", "nitropack": "^2.7.0", - "ultrahtml": "^1.5.2" + "ultrahtml": "^1.5.2", + "unstorage": "^1.9.0" } }, "packages/create-mcfly": { @@ -4002,7 +4003,7 @@ "license": "MIT", "dependencies": { "@mcflyjs/config": "^0.0.1", - "@mcflyjs/core": "^0.0.1", + "@mcflyjs/core": "^0.1.0", "esprima": "^4.0.1", "nitropack": "latest", "ultrahtml": "^1.5.2" diff --git a/package.json b/package.json index e00fb71..0439a97 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "scripts": { "start": "npm start -w @mcflyjs/landing-page", "build": "npm run build -w @mcflyjs/landing-page", - "build:preview": "npm run build:preview -w @mcflyjs/landing-page" + "build:preview": "npm run build:preview -w @mcflyjs/landing-page", + "template:basic": "npm run dev -w @templates/basic" }, "workspaces": [ "packages/config", diff --git a/packages/core/index.ts b/packages/core/index.ts index def1327..618e00b 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -1,14 +1,14 @@ import { eventHandler } from "h3"; +import { Storage as NitroStorage } from "unstorage"; import { ELEMENT_NODE, parse, render, renderSync, walkSync } from "ultrahtml"; import { parseScript } from "esprima"; -export default (config: Function, useStorage) => { - const { componentType } = config(); +export default (config: Function, storage: NitroStorage) => { return eventHandler(async (event) => { const { path } = event; - let html = await getHtml(path, useStorage); + const { components: componentType } = config(); + let html = await getHtml(path, storage); - // transforms const transforms = [doSetUp, deleteServerScripts]; if (html) { for (const transform of transforms) { @@ -16,24 +16,24 @@ export default (config: Function, useStorage) => { } } - html = await useFragments(html.toString(), useStorage); + html = await useFragments(html.toString(), storage); if (!!componentType && !!html) { - html = await insertRegistry(html.toString(), componentType, useStorage); + html = await insertRegistry(html.toString(), componentType, storage); } return html ?? new Response("Not found", { status: 404 }); }); }; -const getHtml = async (path: string, useStorage) => { +const getHtml = async (path: string, storage) => { const rawPath = path[path.length - 1] === "/" ? path.slice(0, -1) : path; const filename = rawPath === "" ? "/index.html" : `${rawPath}.html`; const fallback = getPath(rawPath + "/index.html"); const filePath = getPath(filename); - let html = await useStorage().getItem(filePath); - if (!html) html = await useStorage().getItem(fallback); - if (!html) html = await useStorage().getItem(getPath("/404.html")); + let html = await storage.getItem(filePath); + if (!html) html = await storage.getItem(fallback); + if (!html) html = await storage.getItem(getPath("/404.html")); return html; }; @@ -45,10 +45,10 @@ function getPath(filename: string) { async function insertRegistry( html: string, type: "js" | "ts", - useStorage + storage: NitroStorage ): Promise { const ast = parse(html); - const componentFiles = await getFiles(type, useStorage); + const componentFiles = await getFiles(type, storage); const availableComponents = componentFiles.map((key) => key.replace(`.${type}`, "") ); @@ -68,7 +68,7 @@ async function insertRegistry( const registryScript = await buildRegistry( usedCustomElements, type, - useStorage + storage ); walkSync(ast, (node) => { if (node.type === ELEMENT_NODE && node.name === "head") { @@ -83,16 +83,14 @@ async function insertRegistry( async function buildRegistry( usedCustomElements: string[], type: "js" | "ts", - useStorage + storage: NitroStorage ) { let registryScript = `"; - - return registryScript; -} - -function doSetUp(html: string) { - const ast = parse(html); - const serverScripts = []; - walkSync(ast, (node) => { - const { attributes } = node; - const attributeKeys = Object.keys(attributes ?? {}); - const isServerScript = attributeKeys.some((key) => key.includes("server:")); - if ( - node.type === ELEMENT_NODE && - node.name === "script" && - isServerScript - ) { - const scripts = node.children.map((child) => child.value); - const script = cleanScript(scripts); - serverScripts.push(script); - } - }); - - const setupMap = {}; - serverScripts.forEach((script: string) => { - const { body } = parseScript(script); - const keys = body - .filter((node) => node.type === "VariableDeclaration") - .map((node) => node.declarations[0].id.name); - const constructor = `(function(){}.constructor)(\`${script}; return {${keys.join( - "," - )}}\`);`; - const evalStore = eval(constructor); - Object.assign(setupMap, new evalStore()); - }); - - const regex = /{{(.*?)}}/g; - var match; - - while ((match = regex.exec(html))) { - let [key, value] = match; - value = value.replace(/\s/g, ""); - html = html.replace(key, setupMap[value]); - } - - return html; -} - -function deleteServerScripts(html: string): string { - const ast = parse(html); - walkSync(ast, (node) => { - const { attributes } = node; - const attributeKeys = Object.keys(attributes ?? {}); - const isServerScript = attributeKeys.some((key) => key.includes("server:")); - if (isServerScript) { - node.parent.children.splice(node.parent.children.indexOf(node), 1); - } - }); - - return renderSync(ast); -} - -function cleanScript(scripts: string[]): string { - let script = scripts.map((s) => s.trim()).join(" "); - - script = removeComments(script); - - return script.replace(/\n/g, "").replace(/\s+/g, " "); -} - -function isComment(node) { - return ( - node.type === "Line" || - node.type === "Block" || - node.type === "BlockComment" || - node.type === "LineComment" - ); -} - -function removeComments(script: string) { - const entries = []; - parseScript(script, { comment: true }, function (node, meta) { - if (isComment(node)) { - entries.push({ - start: meta.start.offset, - end: meta.end.offset, - }); - } - }); - - entries - .sort((a, b) => { - return b.end - a.end; - }) - .forEach((n) => { - script = script.slice(0, n.start) + script.slice(n.end); - }); - return script; -} - -async function useFragments(html: string) { - const fragmentFiles = await getFiles("html"); - - const availableFragments = fragmentFiles.reduce((acc, key) => { - return { - ...acc, - [key.replace(".html", "")]: "", - }; - }, {}); - const ast = parse(html); - - for (const key in availableFragments) { - let text: string = await useStorage().getItem( - "assets:components:" + key + ".html" - ); - availableFragments[key] = text.replace(/\n/g, "").replace(/\s+/g, " "); - } - - walkSync(ast, (node) => { - const selector = Object.keys(availableFragments).find( - (name) => name === node.name - ); - - if (node.type === ELEMENT_NODE && !!selector) { - const index = node.parent.children.indexOf(node); - const fragmentNode = parse(availableFragments[selector]); - - replaceSlots(fragmentNode, node); - - node.parent.children[index] = fragmentNode; - } - }); - - return render(ast); -} - -function replaceSlots(fragmentNode, node) { - walkSync(fragmentNode, (n) => { - if (n.type === ELEMENT_NODE && n.name === "slot") { - const index = n.parent.children.indexOf(n); - n.parent.children.splice(index, 1, ...node.children); - } - }); -} - -async function getFiles(type: string) { - return (await useStorage().getKeys("assets:components")) - .map((key) => key.replace("assets:components:", "")) - .filter((key) => key.includes(type)); -} +export default McFly(config, useStorage());