initial jsx support
This commit is contained in:
parent
2301c5d631
commit
11be5e979c
7 changed files with 77 additions and 30 deletions
|
|
@ -2,6 +2,9 @@
|
|||
"tasks": {
|
||||
"dev": "deno run --allow-net src/main.ts"
|
||||
},
|
||||
"imports": {
|
||||
"interest/jsx-runtime": "./src/jsx.ts"
|
||||
},
|
||||
"lint": {
|
||||
"rules": {
|
||||
"tags": [
|
||||
|
|
@ -11,14 +14,13 @@
|
|||
}
|
||||
},
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "interest",
|
||||
"lib": [
|
||||
"deno.ns",
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable"
|
||||
]
|
||||
},
|
||||
"imports": {
|
||||
"@std/assert": "jsr:@std/assert@1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
deno.lock
generated
20
deno.lock
generated
|
|
@ -1,20 +1,5 @@
|
|||
{
|
||||
"version": "5",
|
||||
"specifiers": {
|
||||
"jsr:@std/assert@1": "1.0.15",
|
||||
"jsr:@std/internal@^1.0.12": "1.0.12"
|
||||
},
|
||||
"jsr": {
|
||||
"@std/assert@1.0.15": {
|
||||
"integrity": "d64018e951dbdfab9777335ecdb000c0b4e3df036984083be219ce5941e4703b",
|
||||
"dependencies": [
|
||||
"jsr:@std/internal"
|
||||
]
|
||||
},
|
||||
"@std/internal@1.0.12": {
|
||||
"integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027"
|
||||
}
|
||||
},
|
||||
"redirects": {
|
||||
"https://deno.land/std/fs/walk.ts": "https://deno.land/std@0.224.0/fs/walk.ts"
|
||||
},
|
||||
|
|
@ -46,10 +31,5 @@
|
|||
"https://deno.land/std@0.224.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01",
|
||||
"https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
|
||||
"https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780"
|
||||
},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
"jsr:@std/assert@1"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
src/app.tsx
Normal file
13
src/app.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Copyright (c) 2025 xwra
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<>
|
||||
<h1>JSX Page</h1>
|
||||
<p class="oh hey">meowing chunk by chunk</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
20
src/global.d.ts
vendored
Normal file
20
src/global.d.ts
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Copyright (c) 2025 xwra
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/// <reference types="interest/jsx-runtime" />
|
||||
|
||||
import type { ChunkedStream } from "./stream.ts";
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
type Element = (chunks: ChunkedStream<string>) => Promise<void>;
|
||||
interface IntrinsicElements {
|
||||
[key: string]: ElementProps;
|
||||
}
|
||||
interface ElementProps {
|
||||
[key: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -71,9 +71,9 @@ type TagFn = {
|
|||
(fn: () => any): TagRes;
|
||||
};
|
||||
|
||||
type HtmlProxy = { [K in keyof HTMLElementTagNameMap]: TagFn } & {
|
||||
export type HtmlProxy = { [K in keyof HTMLElementTagNameMap]: TagFn } & {
|
||||
[key: string]: TagFn;
|
||||
};
|
||||
} & { render(child: any): Promise<void> };
|
||||
|
||||
const isTemplateLiteral = (arg: any): arg is TemplateStringsArray =>
|
||||
Array.isArray(arg) && "raw" in arg;
|
||||
|
|
@ -125,5 +125,8 @@ export function html(
|
|||
},
|
||||
};
|
||||
|
||||
return new Proxy({}, handler) as HtmlProxy;
|
||||
const proxy = new Proxy({}, handler) as HtmlProxy;
|
||||
proxy.render = async (stuff: any) => void write(await render(stuff));
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
|
|
|||
29
src/jsx.ts
Normal file
29
src/jsx.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Copyright (c) 2025 xwra
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { html, type HtmlProxy } from "./html.ts";
|
||||
import { ChunkedStream } from "./stream.ts";
|
||||
|
||||
let context;
|
||||
|
||||
export function jsx(
|
||||
tag: string | typeof Fragment,
|
||||
{ children }: Record<string, any> = {},
|
||||
) {
|
||||
return async (chunks: ChunkedStream<string>) => {
|
||||
if (tag === Fragment) {
|
||||
context = html(chunks);
|
||||
for (const child of children) {
|
||||
await context.render?.(child);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await (context ||= html(chunks))[tag](...children);
|
||||
};
|
||||
}
|
||||
|
||||
export const Fragment = Symbol("Fragment");
|
||||
|
||||
export const jsxs = jsx;
|
||||
|
|
@ -5,18 +5,18 @@
|
|||
|
||||
import { html } from "./html.ts";
|
||||
import { createHtmlStream } from "./http.ts";
|
||||
import App from "./app.tsx";
|
||||
|
||||
Deno.serve({
|
||||
port: 8080,
|
||||
async handler() {
|
||||
const stream = await createHtmlStream({ lang: "en" });
|
||||
const { h1, ol, p, li } = html(stream.chunks);
|
||||
const { ol, li } = html(stream.chunks);
|
||||
|
||||
await h1`Normal Streaming Page`;
|
||||
await p({ class: "oh hey" }, "meowing chunk by chunk");
|
||||
await App()(stream.chunks);
|
||||
|
||||
ol(async () => {
|
||||
const fruits = ["Apple", "Banana", "Cherry"];
|
||||
const fruits = ["TSX support", "Apple", "Banana", "Cherry"];
|
||||
for (const fruit of fruits) {
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
await li(fruit);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue