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": {
|
"tasks": {
|
||||||
"dev": "deno run --allow-net src/main.ts"
|
"dev": "deno run --allow-net src/main.ts"
|
||||||
},
|
},
|
||||||
|
"imports": {
|
||||||
|
"interest/jsx-runtime": "./src/jsx.ts"
|
||||||
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"rules": {
|
"rules": {
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|
@ -11,14 +14,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "interest",
|
||||||
"lib": [
|
"lib": [
|
||||||
"deno.ns",
|
"deno.ns",
|
||||||
"esnext",
|
"esnext",
|
||||||
"dom",
|
"dom",
|
||||||
"dom.iterable"
|
"dom.iterable"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"imports": {
|
|
||||||
"@std/assert": "jsr:@std/assert@1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
deno.lock
generated
20
deno.lock
generated
|
|
@ -1,20 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "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": {
|
"redirects": {
|
||||||
"https://deno.land/std/fs/walk.ts": "https://deno.land/std@0.224.0/fs/walk.ts"
|
"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/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/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
|
||||||
"https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780"
|
"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;
|
(fn: () => any): TagRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
type HtmlProxy = { [K in keyof HTMLElementTagNameMap]: TagFn } & {
|
export type HtmlProxy = { [K in keyof HTMLElementTagNameMap]: TagFn } & {
|
||||||
[key: string]: TagFn;
|
[key: string]: TagFn;
|
||||||
};
|
} & { render(child: any): Promise<void> };
|
||||||
|
|
||||||
const isTemplateLiteral = (arg: any): arg is TemplateStringsArray =>
|
const isTemplateLiteral = (arg: any): arg is TemplateStringsArray =>
|
||||||
Array.isArray(arg) && "raw" in arg;
|
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 { html } from "./html.ts";
|
||||||
import { createHtmlStream } from "./http.ts";
|
import { createHtmlStream } from "./http.ts";
|
||||||
|
import App from "./app.tsx";
|
||||||
|
|
||||||
Deno.serve({
|
Deno.serve({
|
||||||
port: 8080,
|
port: 8080,
|
||||||
async handler() {
|
async handler() {
|
||||||
const stream = await createHtmlStream({ lang: "en" });
|
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 App()(stream.chunks);
|
||||||
await p({ class: "oh hey" }, "meowing chunk by chunk");
|
|
||||||
|
|
||||||
ol(async () => {
|
ol(async () => {
|
||||||
const fruits = ["Apple", "Banana", "Cherry"];
|
const fruits = ["TSX support", "Apple", "Banana", "Cherry"];
|
||||||
for (const fruit of fruits) {
|
for (const fruit of fruits) {
|
||||||
await new Promise((r) => setTimeout(r, 500));
|
await new Promise((r) => setTimeout(r, 500));
|
||||||
await li(fruit);
|
await li(fruit);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue