Skip to content

Instantly share code, notes, and snippets.

@nestarz
Last active May 16, 2023 12:22
Show Gist options
  • Save nestarz/43ebf0df13be127914b91bb25b679872 to your computer and use it in GitHub Desktop.
Save nestarz/43ebf0df13be127914b91bb25b679872 to your computer and use it in GitHub Desktop.

Revisions

  1. nestarz revised this gist May 16, 2023. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions routes.ts
    Original file line number Diff line number Diff line change
    @@ -114,3 +114,5 @@ export const buildRoutes =
    (defaults) =>
    (arr = []) =>
    arr.reduce(createRoutes(defaults), {});

    export * from "./middleware.ts";
  2. nestarz renamed this gist May 16, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. nestarz revised this gist May 16, 2023. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions pipe.ts
    Original file line number Diff line number Diff line change
    @@ -31,11 +31,11 @@ export const pipe =
    );


    type MiddlewareFunction = (
    export type MiddlewareFunction = (
    req: Request
    ) => Promise<Response | undefined> | Response | undefined;

    const middleware =
    export const middleware =
    (...fns: MiddlewareFunction[]) =>
    async (req: Request): Promise<Response> => {
    for (const fn of fns) {
    @@ -45,10 +45,10 @@ const middleware =
    return new Response(null, { status: 404 });
    };

    type DeepObject = {
    export type DeepObject = {
    [key: string]: unknown;
    };
    const deepApplyFunction = (
    export const deepApplyFunction = (
    fn: (func: Function) => Function,
    obj: DeepObject
    ): DeepObject => {
  4. nestarz revised this gist May 16, 2023. 1 changed file with 34 additions and 1 deletion.
    35 changes: 34 additions & 1 deletion pipe.ts
    Original file line number Diff line number Diff line change
    @@ -28,4 +28,37 @@ export const pipe =
    (fns as AnyFunc[]).reduce(
    (acc, fn) => (acc instanceof Promise ? acc.then(fn) : fn(acc)),
    firstFn(...args)
    );
    );


    type MiddlewareFunction = (
    req: Request
    ) => Promise<Response | undefined> | Response | undefined;

    const middleware =
    (...fns: MiddlewareFunction[]) =>
    async (req: Request): Promise<Response> => {
    for (const fn of fns) {
    const result = await fn(req);
    if (result !== undefined) return result;
    }
    return new Response(null, { status: 404 });
    };

    type DeepObject = {
    [key: string]: unknown;
    };
    const deepApplyFunction = (
    fn: (func: Function) => Function,
    obj: DeepObject
    ): DeepObject => {
    const applyFn = (value: unknown): unknown => {
    if (typeof value === "function") return fn(value);
    if (typeof value === "object" && value !== null && !Array.isArray(value))
    return deepApplyFunction(fn, value as DeepObject);
    return value;
    };
    const newObj: DeepObject = {};
    for (const key in obj) newObj[key] = applyFn(obj[key]);
    return newObj;
    };
  5. nestarz revised this gist May 5, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion islands.ts
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    import { join, fromFileUrl } from "https://deno.land/[email protected]/path/mod.ts";
    import * as esbuild from "https://deno.land/x/[email protected]/wasm.js";
    import { denoPlugins } from "https://raw.githubusercontent.com/nestarz/esbuild_deno_loader/patch-1/mod.ts";
    import { denoPlugins } from "https://deno.land/x/esbuild_deno_loader@0.7.0/mod.ts";
    import { getHashSync, scripted, scriptedGetClean } from "https://deno.land/x/[email protected]/mod.ts";
    export { scripted } from "https://deno.land/x/[email protected]/mod.ts";

  6. nestarz revised this gist May 4, 2023. 1 changed file with 34 additions and 29 deletions.
    63 changes: 34 additions & 29 deletions islands.ts
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,8 @@
    import * as esbuild from "esbuild";
    import { denoPlugins } from "esbuild_deno_loader";
    import { getHashSync, scripted, scriptedGetClean } from "scripted";
    export { scripted } from "scripted";

    const isProd = !!Deno.env.get("DENO_DEPLOYMENT_ID");
    import { join, fromFileUrl } from "https://deno.land/[email protected]/path/mod.ts";
    import * as esbuild from "https://deno.land/x/[email protected]/wasm.js";
    import { denoPlugins } from "https://raw.githubusercontent.com/nestarz/esbuild_deno_loader/patch-1/mod.ts";
    import { getHashSync, scripted, scriptedGetClean } from "https://deno.land/x/[email protected]/mod.ts";
    export { scripted } from "https://deno.land/x/[email protected]/mod.ts";

    const readPlugin = () => ({
    name: "deno_read",
    @@ -13,9 +12,9 @@ const readPlugin = () => ({
    async (args) => {
    const path = await Deno.realPath(
    args.path.startsWith("file")
    ? import.meta.resolve(args.path).slice(7)
    ? fromFileUrl(args.path)
    : args.path.startsWith(".")
    ? `${args.resolveDir}/${args.path}`
    ? join(args.resolveDir, args.path)
    : args.path
    );
    return { path, namespace: "file" };
    @@ -34,9 +33,9 @@ const readPlugin = () => ({
    const readOnly = !!Deno.env.get("DENO_DEPLOYMENT_ID");

    console.time("init");
    console.log(esbuild.version);
    await esbuild.initialize({
    wasmURL:
    "https://raw.githubusercontent.com/esbuild/deno-esbuild/v0.17.18/esbuild.wasm",
    wasmURL: `https://raw.githubusercontent.com/esbuild/deno-esbuild/v${esbuild.version}/esbuild.wasm`,
    worker: false,
    });
    console.timeEnd("init");
    @@ -58,7 +57,7 @@ const esBuild = async (manifest, config = {}) => {
    splitting: true,
    treeShaking: true,
    write: false,
    outdir: "/islands/",
    outdir: manifest.prefix,
    sourcemap: "linked",
    minify: true,
    ...config,
    @@ -124,12 +123,10 @@ const getIsland = (islands: Record<string, string>[], url: string | URL) => {
    return islands.find((v) => v.reqpath === new URL(url).pathname);
    };

    const buildIsland = async (entrypath: string) => {
    const id = `_${getHashSync(
    await Deno.readTextFile(entrypath.replaceAll("file://", "/"))
    )}`;
    const reqpath = `/islands/${id}.js`;
    return { id, entrypath, reqpath, outpath: `./dist${reqpath}` };
    const buildIsland = async (prefix: string, entrypath: string) => {
    const id = `_${getHashSync(await Deno.readTextFile(fromFileUrl(entrypath)))}`;
    const reqpath = join(prefix, `${id}.js`);
    return { id, entrypath, reqpath, outpath: join("dist", reqpath) };
    };

    const buildOutputFiles = async (
    @@ -140,19 +137,18 @@ const buildOutputFiles = async (
    const entryPoints = islands.map((i) => ({ in: i.entrypath, out: i.id }));
    const result = await esBuild(manifest, { entryPoints });
    if (save) {
    await Deno.remove("./dist/islands/", { recursive: true }).catch(() => null);
    await Deno.mkdir("./dist/islands/", { recursive: true });
    const folder = join("dist", manifest.prefix);
    await Deno.remove(folder, { recursive: true }).catch(() => null);
    await Deno.mkdir(folder, { recursive: true });
    await Promise.all(
    result.outputFiles.map(({ path, contents }) =>
    Deno.writeFile("./dist" + path, contents)
    Deno.writeFile(join("dist", path), contents)
    )
    );
    }
    return result;
    };

    let islands: Record<string, string>[] = [];

    class SuffixTransformStream extends TransformStream<Uint8Array, Uint8Array> {
    constructor(suffix: string) {
    super({
    @@ -164,12 +160,24 @@ class SuffixTransformStream extends TransformStream<Uint8Array, Uint8Array> {
    }
    }

    export const register = (
    islands: any[],
    vpath: string,
    props?: any,
    name?: string
    ) => {
    const specifier = islands.find((v) => v.entrypath?.includes(vpath))?.reqpath;
    return scripted(hydrate, specifier, name ?? "default", props ?? {});
    };

    export const setup = async (manifest, save = true) => {
    islands = await Promise.all(
    const islands = await Promise.all(
    await asynGlob(
    manifest.islands,
    new URLPattern("*.(t|j)s(x|)", "file://")
    ).then((files) => files.map(async ({ path }) => await buildIsland(path)))
    ).then((files) =>
    files.map(async ({ path }) => await buildIsland(manifest.prefix, path))
    )
    );
    const isSync = await Promise.all(
    islands.map(async (v) => !!(await Deno.stat(v.outpath)))
    @@ -179,6 +187,8 @@ export const setup = async (manifest, save = true) => {
    throw Error("Islands not synced with source.\n" + JSON.stringify(islands));

    return {
    islands,
    register: (...props) => register(islands, ...props),
    inject: async (html: string | ReadableStream) => {
    const scripts = await dump(manifest);
    const script = `<script data-scripted>${scripts}</script>`;
    @@ -212,8 +222,3 @@ export const setup = async (manifest, save = true) => {
    }))),
    };
    };

    export const register = (vpath: string, props?: any, name?: string) => {
    const specifier = islands.find((v) => v.entrypath?.includes(vpath))?.reqpath;
    return scripted(hydrate, specifier, name ?? "default", props ?? {});
    };
  7. nestarz revised this gist May 4, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion routes.ts
    Original file line number Diff line number Diff line change
    @@ -99,7 +99,7 @@ class SuffixTransformStream extends TransformStream<Uint8Array, Uint8Array> {
    }
    }

    export const injectStream = (stream: ReadableStream) =>
    export const injectStream = (stream: ReadableStream, suffix: string) =>
    stream.pipeThrough(new SuffixTransformStream(suffix));

    export const docType =
  8. nestarz revised this gist May 4, 2023. 1 changed file with 31 additions and 0 deletions.
    31 changes: 31 additions & 0 deletions pipe.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    type AnyFunc = (...arg: any[]) => Promise<any> | any;

    type LastFnReturnType<F extends Array<AnyFunc>, Else = never> = F extends [
    ...any[],
    (...arg: any) => infer R
    ]
    ? R
    : Else;

    type PipeArgs<F extends AnyFunc[], Acc extends AnyFunc[] = []> = F extends [
    (...args: infer A) => infer B
    ]
    ? [...Acc, (...args: A) => B | Promise<B>]
    : F extends [(...args: infer A) => any, ...infer Tail]
    ? Tail extends [(arg: infer B) => any, ...any[]]
    ? PipeArgs<Tail, [...Acc, (...args: A) => B | Promise<B>]>
    : Acc
    : Acc;

    export const pipe =
    <FirstFn extends AnyFunc, F extends AnyFunc[]>(
    firstFn: FirstFn,
    ...fns: PipeArgs<F> extends F ? F : PipeArgs<F>
    ) =>
    (
    ...args: Parameters<FirstFn>
    ): Promise<LastFnReturnType<F, ReturnType<FirstFn>>> =>
    (fns as AnyFunc[]).reduce(
    (acc, fn) => (acc instanceof Promise ? acc.then(fn) : fn(acc)),
    firstFn(...args)
    );
  9. nestarz revised this gist May 4, 2023. 1 changed file with 31 additions and 3 deletions.
    34 changes: 31 additions & 3 deletions routes.ts
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,12 @@ export const createRoutes = (defaults) => (acc, _route) => {
    acc[route.path] = auth(async (req, _, params) => {
    const render = pipe(
    (data) =>
    route.default({ data, url: new URL(req.url), route: route.path, params }),
    route.default({
    data,
    url: new URL(req.url),
    route: route.path,
    params,
    }),
    route.render,
    route.inject,
    (content: string) =>
    @@ -83,6 +88,29 @@ export const createRoutes = (defaults) => (acc, _route) => {
    return acc;
    };

    export const docType = (attrs: string[]) => (html) => `<!DOCTYPE ${attrs.join(" ")}>${html}`;
    class SuffixTransformStream extends TransformStream<Uint8Array, Uint8Array> {
    constructor(suffix: string) {
    super({
    flush(controller) {
    controller.enqueue(new TextEncoder().encode(suffix));
    controller.terminate();
    },
    });
    }
    }

    export const buildRoutes = (defaults) => (arr = []) => arr.reduce(createRoutes(defaults), {});
    export const injectStream = (stream: ReadableStream) =>
    stream.pipeThrough(new SuffixTransformStream(suffix));

    export const docType =
    (attrs: string[]) => (htmlOrStream: string | ReadableStream) => {
    const suffix = `<!DOCTYPE ${attrs.join(" ")}>`;
    return htmlOrStream instanceof ReadableStream
    ? injectStream(htmlOrStream, suffix)
    : `${suffix}${htmlOrStream}`;
    };

    export const buildRoutes =
    (defaults) =>
    (arr = []) =>
    arr.reduce(createRoutes(defaults), {});
  10. nestarz revised this gist May 4, 2023. 1 changed file with 20 additions and 5 deletions.
    25 changes: 20 additions & 5 deletions islands.ts
    Original file line number Diff line number Diff line change
    @@ -153,11 +153,23 @@ const buildOutputFiles = async (

    let islands: Record<string, string>[] = [];

    class SuffixTransformStream extends TransformStream<Uint8Array, Uint8Array> {
    constructor(suffix: string) {
    super({
    flush(controller) {
    controller.enqueue(new TextEncoder().encode(suffix));
    controller.terminate();
    },
    });
    }
    }

    export const setup = async (manifest, save = true) => {
    islands = await Promise.all(
    await asynGlob(manifest.islands, new URLPattern("*.(t|j)s(x|)", "file://")).then(
    (files) => files.map(async ({ path }) => await buildIsland(path))
    )
    await asynGlob(
    manifest.islands,
    new URLPattern("*.(t|j)s(x|)", "file://")
    ).then((files) => files.map(async ({ path }) => await buildIsland(path)))
    );
    const isSync = await Promise.all(
    islands.map(async (v) => !!(await Deno.stat(v.outpath)))
    @@ -167,11 +179,14 @@ export const setup = async (manifest, save = true) => {
    throw Error("Islands not synced with source.\n" + JSON.stringify(islands));

    return {
    inject: async (html: string) => {
    inject: async (html: string | ReadableStream) => {
    const scripts = await dump(manifest);
    const script = `<script data-scripted>${scripts}</script>`;
    if (html instanceof ReadableStream)
    return html.pipeThrough(new SuffixTransformStream(script));
    return `${html.replace(
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
    (_, $1) => `<script data-scripted>${scripts}</script>${$1}`
    (_, $1) => `${script}${$1}`
    )}`;
    },
    ...(isSync
  11. nestarz revised this gist Apr 24, 2023. No changes.
  12. nestarz revised this gist Apr 24, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion islands.ts
    Original file line number Diff line number Diff line change
    @@ -183,7 +183,7 @@ export const setup = async (manifest, save = true) => {
    return dist ? await Deno.readFile(dist) : null;
    },
    }
    : buildOutputFiles(manifest, islands, save).then((result) => ({
    : await buildOutputFiles(manifest, islands, save).then((result) => ({
    get: (url: string) => {
    const island = getIsland(islands, url);
    return (
  13. nestarz revised this gist Apr 24, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions islands.ts
    Original file line number Diff line number Diff line change
    @@ -153,9 +153,9 @@ const buildOutputFiles = async (

    let islands: Record<string, string>[] = [];

    export const setup = async (manifest, directory: URL, save = true) => {
    export const setup = async (manifest, save = true) => {
    islands = await Promise.all(
    await asynGlob(directory, new URLPattern("*.(t|j)s(x|)", "file://")).then(
    await asynGlob(manifest.islands, new URLPattern("*.(t|j)s(x|)", "file://")).then(
    (files) => files.map(async ({ path }) => await buildIsland(path))
    )
    );
  14. nestarz revised this gist Apr 24, 2023. No changes.
  15. nestarz revised this gist Apr 24, 2023. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion islands.ts
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,6 @@ import * as esbuild from "esbuild";
    import { denoPlugins } from "esbuild_deno_loader";
    import { getHashSync, scripted, scriptedGetClean } from "scripted";
    export { scripted } from "scripted";
    import { toFileUrl } from "https://deno.land/[email protected]/path/mod.ts";

    const isProd = !!Deno.env.get("DENO_DEPLOYMENT_ID");

  16. nestarz revised this gist Apr 24, 2023. 1 changed file with 39 additions and 45 deletions.
    84 changes: 39 additions & 45 deletions islands.ts
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,7 @@ import * as esbuild from "esbuild";
    import { denoPlugins } from "esbuild_deno_loader";
    import { getHashSync, scripted, scriptedGetClean } from "scripted";
    export { scripted } from "scripted";
    import { toFileUrl } from "https://deno.land/[email protected]/path/mod.ts";

    const isProd = !!Deno.env.get("DENO_DEPLOYMENT_ID");

    @@ -36,18 +37,18 @@ const readOnly = !!Deno.env.get("DENO_DEPLOYMENT_ID");
    console.time("init");
    await esbuild.initialize({
    wasmURL:
    "https://raw.githubusercontent.com/esbuild/deno-esbuild/v0.17.14/esbuild.wasm",
    "https://raw.githubusercontent.com/esbuild/deno-esbuild/v0.17.18/esbuild.wasm",
    worker: false,
    });
    console.timeEnd("init");

    const esBuild = async (config = {}) => {
    const esBuild = async (manifest, config = {}) => {
    console.time("build");
    const res = await esbuild.build({
    plugins: [
    readPlugin(),
    ...denoPlugins({
    importMapURL: new URL("import_map.json", import.meta.url).href,
    importMapURL: new URL("import_map.json", manifest.baseUrl).href,
    }),
    ],
    format: "esm",
    @@ -67,9 +68,9 @@ const esBuild = async (config = {}) => {
    return res;
    };

    export const dump = async () => {
    export const dump = async (manifest) => {
    const contents = scriptedGetClean();
    const { outputFiles } = await esBuild({
    const { outputFiles } = await esBuild(manifest, {
    splitting: false,
    stdin: { contents },
    sourcemap: false,
    @@ -133,11 +134,12 @@ const buildIsland = async (entrypath: string) => {
    };

    const buildOutputFiles = async (
    manifest,
    islands: Record<string, string>[],
    save: boolean
    ) => {
    const entryPoints = islands.map((i) => ({ in: i.entrypath, out: i.id }));
    const result = await esBuild({ entryPoints });
    const result = await esBuild(manifest, { entryPoints });
    if (save) {
    await Deno.remove("./dist/islands/", { recursive: true }).catch(() => null);
    await Deno.mkdir("./dist/islands/", { recursive: true });
    @@ -152,7 +154,7 @@ const buildOutputFiles = async (

    let islands: Record<string, string>[] = [];

    export const setup = async (directory: URL, save = true) => {
    export const setup = async (manifest, directory: URL, save = true) => {
    islands = await Promise.all(
    await asynGlob(directory, new URLPattern("*.(t|j)s(x|)", "file://")).then(
    (files) => files.map(async ({ path }) => await buildIsland(path))
    @@ -165,47 +167,39 @@ export const setup = async (directory: URL, save = true) => {
    if (!isSync && readOnly)
    throw Error("Islands not synced with source.\n" + JSON.stringify(islands));

    return isSync
    ? {
    get: async (url: string) => {
    const island = getIsland(islands, url);
    const dist =
    island?.outpath ?? Deno.cwd() + "/dist" + new URL(url).pathname;
    return dist ? await Deno.readFile(dist) : null;
    },
    }
    : buildOutputFiles(islands, save).then((result) => ({
    get: (url: string) => {
    const island = getIsland(islands, url);
    return (
    result.outputFiles.find(
    (file) =>
    file.path === island?.reqpath ||
    file.path === new URL(url).pathname
    )?.contents ?? null
    );
    },
    }));
    return {
    inject: async (html: string) => {
    const scripts = await dump(manifest);
    return `${html.replace(
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
    (_, $1) => `<script data-scripted>${scripts}</script>${$1}`
    )}`;
    },
    ...(isSync
    ? {
    get: async (url: string) => {
    const island = getIsland(islands, url);
    const dist =
    island?.outpath ?? Deno.cwd() + "/dist" + new URL(url).pathname;
    return dist ? await Deno.readFile(dist) : null;
    },
    }
    : buildOutputFiles(manifest, islands, save).then((result) => ({
    get: (url: string) => {
    const island = getIsland(islands, url);
    return (
    result.outputFiles.find(
    (file) =>
    file.path === island?.reqpath ||
    file.path === new URL(url).pathname
    )?.contents ?? null
    );
    },
    }))),
    };
    };

    export const register = (vpath: string, props?: any, name?: string) => {
    const specifier = islands.find((v) => v.entrypath?.includes(vpath))?.reqpath;
    return scripted(hydrate, specifier, name ?? "default", props ?? {});
    };

    export const inject = async (html: string) => {
    const scripts = await dump();
    return `<!DOCTYPE html>${html.replace(
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
    (_, $1) => `<script data-scripted>${scripts}</script>${$1}`
    )}`;
    };

    export const injectScripts = async (html: string) => {
    const scripts = await dump();
    return `${html.replace(
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
    (_, $1) =>
    `<script data-scripted>${scripts}</script>${$1}`
    )}`;
    };
  17. nestarz revised this gist Apr 24, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion islands.ts
    Original file line number Diff line number Diff line change
    @@ -36,7 +36,7 @@ const readOnly = !!Deno.env.get("DENO_DEPLOYMENT_ID");
    console.time("init");
    await esbuild.initialize({
    wasmURL:
    "https://raw.githubusercontent.com/esbuild/deno-esbuild/v0.17.17/esbuild.wasm",
    "https://raw.githubusercontent.com/esbuild/deno-esbuild/v0.17.14/esbuild.wasm",
    worker: false,
    });
    console.timeEnd("init");
  18. nestarz renamed this gist Apr 24, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  19. nestarz revised this gist Apr 24, 2023. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    import { register } from "./islands.ts";

    export default ({ proxy: C, specifier, name, children, ...props }) => (
    <C
    {...props}
    className={[register(specifier, props, name), props.className].filter((v) => v).join(" ")}
    >
    {children}
    </C>
    );
  20. nestarz revised this gist Apr 24, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion routes.ts
    Original file line number Diff line number Diff line change
    @@ -83,6 +83,6 @@ export const createRoutes = (defaults) => (acc, _route) => {
    return acc;
    };

    export const docType = (attrs: string[]) => `<!DOCTYPE ${attrs.join(" ")}>`;
    export const docType = (attrs: string[]) => (html) => `<!DOCTYPE ${attrs.join(" ")}>${html}`;

    export const buildRoutes = (defaults) => (arr = []) => arr.reduce(createRoutes(defaults), {});
  21. nestarz revised this gist Apr 23, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion islands.ts
    Original file line number Diff line number Diff line change
    @@ -201,7 +201,7 @@ export const inject = async (html: string) => {
    )}`;
    };

    const injectScripts = async (html: string) => {
    export const injectScripts = async (html: string) => {
    const scripts = await dump();
    return `${html.replace(
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
  22. nestarz revised this gist Apr 23, 2023. No changes.
  23. nestarz revised this gist Apr 23, 2023. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions islands.ts
    Original file line number Diff line number Diff line change
    @@ -199,4 +199,13 @@ export const inject = async (html: string) => {
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
    (_, $1) => `<script data-scripted>${scripts}</script>${$1}`
    )}`;
    };

    const injectScripts = async (html: string) => {
    const scripts = await dump();
    return `${html.replace(
    html.includes("</body>") ? /(<\/body>)/ : /(.*)/,
    (_, $1) =>
    `<script data-scripted>${scripts}</script>${$1}`
    )}`;
    };
  24. nestarz revised this gist Apr 23, 2023. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions twind.ts
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,11 @@
    import { extract } from "@twind/core";

    export const inject = (string) => {
    export const inject = (string, cssApply) => {
    const { html, css } = extract(string);
    const cssRaw = css.replaceAll("gt;", ">");
    const finalCss = cssApply?.(cssRaw) ?? cssRaw;
    return html.replace(
    html.includes("</head>") ? /(<\/head>)/ : /(.*)/,
    (_, $1) => `<style data-twind>${css.replaceAll("gt;", ">")}</style>${$1}`
    (_, $1) => `<style data-twind>${finalCss}</style>${$1}`
    );
    };
  25. nestarz revised this gist Apr 23, 2023. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions createVNode.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    import { DOMParser } from "https://esm.sh/linkedom";

    let actions; // current actions to apply when walking the tree

    const convert = (h, hook) => (node) => {
    if (node.nodeType === 3) return node.data;
    let attrs = {};
    for (let i = 0; i < node.attributes.length; i++) {
    const { name, value } = node.attributes[i];
    const m = name.match(/^(?:on:|data-on-?)(.+)$/); // <a on:click="go" data-on-mouseover="blink">
    if (m && actions[value]) attrs["on" + m[1]] = actions[value];
    else attrs[name] = value;
    }
    return (hook ?? h)?.(
    node.localName,
    attrs,
    [].map.call(node.childNodes, convert(h, hook))
    );
    };

    export default ({ h, html, mimeType = "text/html", hook }) => {
    const dom = new DOMParser().parseFromString(html ?? "", mimeType);
    actions = {};
    return [].map.call(dom.childNodes, convert(h, hook));
    };
  26. nestarz revised this gist Apr 23, 2023. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions routes.ts
    Original file line number Diff line number Diff line change
    @@ -84,3 +84,5 @@ export const createRoutes = (defaults) => (acc, _route) => {
    };

    export const docType = (attrs: string[]) => `<!DOCTYPE ${attrs.join(" ")}>`;

    export const buildRoutes = (defaults) => (arr = []) => arr.reduce(createRoutes(defaults), {});
  27. nestarz revised this gist Apr 23, 2023. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions routes.ts
    Original file line number Diff line number Diff line change
    @@ -82,3 +82,5 @@ export const createRoutes = (defaults) => (acc, _route) => {
    });
    return acc;
    };

    export const docType = (attrs: string[]) => `<!DOCTYPE ${attrs.join(" ")}>`;
  28. nestarz revised this gist Apr 23, 2023. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions twind.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    import { extract } from "@twind/core";

    export const inject = (string) => {
    const { html, css } = extract(string);
    return html.replace(
    html.includes("</head>") ? /(<\/head>)/ : /(.*)/,
    (_, $1) => `<style data-twind>${css.replaceAll("gt;", ">")}</style>${$1}`
    );
    };
  29. nestarz revised this gist Apr 23, 2023. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions routes.ts
    Original file line number Diff line number Diff line change
    @@ -75,10 +75,10 @@ export const createRoutes = (defaults) => (acc, _route) => {
    );
    const ctx = { render, params };
    const key = JSON.stringify({ url: req.url, path: route.path });
    const handler = route.handler ?? (() => ctx.render({}));
    const handler = route.handler ?? ((_, ctx) => ctx.render?.({}));
    return req.method === "GET"
    ? await staleWhileRevalidate(key, route.handler, req, ctx)
    : route.handler?.(req, ctx);
    ? await staleWhileRevalidate(key, handler, req, ctx)
    : handler?.(req, ctx);
    });
    return acc;
    };
  30. nestarz revised this gist Apr 23, 2023. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion routes.ts
    Original file line number Diff line number Diff line change
    @@ -75,9 +75,10 @@ export const createRoutes = (defaults) => (acc, _route) => {
    );
    const ctx = { render, params };
    const key = JSON.stringify({ url: req.url, path: route.path });
    const handler = route.handler ?? (() => ctx.render({}));
    return req.method === "GET"
    ? await staleWhileRevalidate(key, route.handler, req, ctx)
    : route.handler(req, ctx);
    : route.handler?.(req, ctx);
    });
    return acc;
    };