htmx-router 1.0.0-alpha.6 → 1.0.0-pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/index.js +38 -0
- package/cookies.d.ts +7 -3
- package/cookies.js +30 -10
- package/css.d.ts +10 -2
- package/css.js +21 -16
- package/defer.d.ts +14 -0
- package/defer.js +80 -0
- package/endpoint.d.ts +12 -5
- package/endpoint.js +11 -5
- package/event-source.js +6 -13
- package/index.d.ts +7 -7
- package/internal/compile/manifest.js +6 -5
- package/internal/component/defer.js +19 -0
- package/internal/component/index.d.ts +4 -0
- package/internal/component/index.js +4 -0
- package/internal/mount.d.ts +9 -1
- package/internal/mount.js +13 -6
- package/internal/request/http.d.ts +1 -1
- package/internal/request/index.d.ts +2 -1
- package/internal/request/native.d.ts +1 -1
- package/internal/request/native.js +1 -1
- package/internal/router.d.ts +15 -0
- package/internal/router.js +24 -0
- package/package.json +6 -8
- package/readme.md +20 -3
- package/router.d.ts +18 -36
- package/router.js +33 -58
- package/shell.d.ts +1 -1
- package/shell.js +15 -7
- package/util/parameters.d.ts +7 -4
- package/util/parameters.js +1 -14
- package/dynamic.d.ts +0 -5
- package/dynamic.js +0 -42
- package/example/eventdim-react/package.json +0 -67
- package/example/eventdim-react/server.js +0 -90
- package/example/island-react/global.d.ts +0 -8
- package/example/island-react/package.json +0 -38
- package/example/island-react/server.js +0 -58
- package/internal/cli/index.js +0 -15
- package/internal/compile/router.d.ts +0 -1
- package/internal/compile/router.js +0 -51
- package/internal/component/dynamic.js +0 -18
- package/internal/hash.d.ts +0 -4
- package/internal/hash.js +0 -10
- package/request/http.d.ts +0 -10
- package/request/http.js +0 -59
- package/request/index.d.ts +0 -13
- package/request/index.js +0 -3
- package/request/native.d.ts +0 -9
- package/request/native.js +0 -46
- package/vite/code-splitting.d.ts +0 -4
- package/vite/code-splitting.js +0 -14
- /package/{internal/cli → cli}/config.d.ts +0 -0
- /package/{internal/cli → cli}/config.js +0 -0
- /package/{internal/cli → cli}/index.d.ts +0 -0
- /package/internal/component/{dynamic.d.ts → defer.d.ts} +0 -0
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { createRequestHandler } from 'htmx-router';
|
|
2
|
-
import { renderToString } from 'react-dom/server';
|
|
3
|
-
import express from 'express';
|
|
4
|
-
import morgan from "morgan";
|
|
5
|
-
|
|
6
|
-
const port = process.env.PORT || 5173;
|
|
7
|
-
const app = express();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const viteDevServer =
|
|
11
|
-
process.env.NODE_ENV === "production"
|
|
12
|
-
? null
|
|
13
|
-
: await import("vite").then((vite) =>
|
|
14
|
-
vite.createServer({
|
|
15
|
-
server: { middlewareMode: true },
|
|
16
|
-
appType: 'custom'
|
|
17
|
-
})
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
app.use(
|
|
21
|
-
viteDevServer
|
|
22
|
-
? viteDevServer.middlewares
|
|
23
|
-
: express.static("./dist/client")
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
// logging
|
|
27
|
-
app.use(morgan("tiny"));
|
|
28
|
-
|
|
29
|
-
const build = viteDevServer
|
|
30
|
-
? () => viteDevServer.ssrLoadModule('./app/entry.server.ts')
|
|
31
|
-
: await import('./dist/server/entry.server.js');
|
|
32
|
-
|
|
33
|
-
app.use('*', createRequestHandler.http({
|
|
34
|
-
build, viteDevServer,
|
|
35
|
-
render: (res) => {
|
|
36
|
-
const headers = new Headers();
|
|
37
|
-
headers.set("Content-Type", "text/html; charset=UTF-8");
|
|
38
|
-
|
|
39
|
-
const stream = renderToString(res);
|
|
40
|
-
return new Response(stream, { headers });
|
|
41
|
-
}
|
|
42
|
-
}));
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Start http server
|
|
46
|
-
app.listen(port, () => {
|
|
47
|
-
console.log(`Server started at http://localhost:${port}`)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Reload pages on file change
|
|
52
|
-
if (viteDevServer)
|
|
53
|
-
viteDevServer.watcher.on('change', (file) => {
|
|
54
|
-
console.log(`File changed: ${file}`);
|
|
55
|
-
|
|
56
|
-
console.log('Triggering full page reload');
|
|
57
|
-
viteDevServer.ws.send({ type: 'full-reload' });
|
|
58
|
-
});
|
package/internal/cli/index.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
import { readFile, writeFile } from "fs/promises";
|
|
4
|
-
import { CompileManifest } from "../compile/manifest.js";
|
|
5
|
-
import { ReadConfig } from "../cli/config.js";
|
|
6
|
-
const config = await ReadConfig();
|
|
7
|
-
if (config.client) {
|
|
8
|
-
console.info("Building client island manifest");
|
|
9
|
-
const source = await readFile(config.client.source, "utf8");
|
|
10
|
-
await writeFile(config.client.output.server, CompileManifest(config.framework, source, true));
|
|
11
|
-
await writeFile(config.client.output.client, CompileManifest(config.framework, source, false));
|
|
12
|
-
}
|
|
13
|
-
if (config.component) {
|
|
14
|
-
console.info("Building components");
|
|
15
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function CompileRouter(folder: string): string;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
export function CompileRouter(folder) {
|
|
2
|
-
return `import { GenericContext, RouteTree } from "htmx-router/bin/router";
|
|
3
|
-
import { GetClientEntryURL } from 'htmx-router/bin/client/entry';
|
|
4
|
-
import { DynamicReference } from "htmx-router/bin/util/dynamic";
|
|
5
|
-
import { GetMountUrl } from 'htmx-router/bin/client/mount';
|
|
6
|
-
import { GetSheetUrl } from 'htmx-router/bin/util/css';
|
|
7
|
-
import { resolve } from "path";
|
|
8
|
-
|
|
9
|
-
const modules = import.meta.glob('/${folder}/**/*.{ts,tsx}', { eager: true });
|
|
10
|
-
console.log("${folder}");
|
|
11
|
-
console.log(modules);
|
|
12
|
-
|
|
13
|
-
export const tree = new RouteTree();
|
|
14
|
-
for (const path in modules) {
|
|
15
|
-
const mod = modules[path];
|
|
16
|
-
const tail = path.lastIndexOf(".");
|
|
17
|
-
const url = path.slice(${folder.length + 1}, tail);
|
|
18
|
-
tree.ingest(url, mod);
|
|
19
|
-
}`;
|
|
20
|
-
}
|
|
21
|
-
/*
|
|
22
|
-
export function Dynamic<T extends Record<string, string>>(props: {
|
|
23
|
-
params?: T,
|
|
24
|
-
loader: (ctx: GenericContext, params?: T) => Promise<JSX.Element>
|
|
25
|
-
children?: JSX.Element
|
|
26
|
-
}): JSX.Element {
|
|
27
|
-
return <div
|
|
28
|
-
hx-get={DynamicReference(props.loader, props.params)}
|
|
29
|
-
hx-trigger="load"
|
|
30
|
-
hx-swap="outerHTML transition:true"
|
|
31
|
-
style={{ display: "contents" }}
|
|
32
|
-
>{props.children ? props.children : ""}</div>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
let headCache: JSX.Element | null = null;
|
|
36
|
-
const isProduction = process.env.NODE_ENV === "production";
|
|
37
|
-
const clientEntry = await GetClientEntryURL();
|
|
38
|
-
export function Scripts() {
|
|
39
|
-
if (headCache) return headCache;
|
|
40
|
-
|
|
41
|
-
const res = <>
|
|
42
|
-
<link href={GetSheetUrl()} rel="stylesheet"></link>
|
|
43
|
-
{ isProduction ? "" : <script type="module" src="/@vite/client"></script> }
|
|
44
|
-
<script type="module" src={clientEntry}></script>
|
|
45
|
-
<script src={GetMountUrl()}></script>
|
|
46
|
-
</>;
|
|
47
|
-
|
|
48
|
-
if (isProduction) headCache = res;
|
|
49
|
-
return res;
|
|
50
|
-
}
|
|
51
|
-
*/
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const generic = `import { DynamicReference } from "htmx-router/dynamic";
|
|
2
|
-
import { GenericContext } from "htmx-router/router";
|
|
3
|
-
|
|
4
|
-
export function Dynamic<T extends Record<string, string>>(props: {
|
|
5
|
-
params?: T,
|
|
6
|
-
loader: (ctx: GenericContext, params?: T) => Promise<JSX.Element>
|
|
7
|
-
children?: JSX.Element
|
|
8
|
-
}): JSX.Element {
|
|
9
|
-
return <div
|
|
10
|
-
hx-get={DynamicReference(props.loader, props.params)}
|
|
11
|
-
hx-trigger="load"
|
|
12
|
-
hx-swap="outerHTML transition:true"
|
|
13
|
-
style={{ display: "contents" }}
|
|
14
|
-
>{props.children ? props.children : ""}</div>
|
|
15
|
-
}`;
|
|
16
|
-
export default {
|
|
17
|
-
"*": generic
|
|
18
|
-
};
|
package/internal/hash.d.ts
DELETED
package/internal/hash.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Not the best hash in the world, but it's something really fast that will work on all JS runtimes
|
|
3
|
-
*/
|
|
4
|
-
export function QuickHash(input) {
|
|
5
|
-
let hash = 0;
|
|
6
|
-
for (let i = 0; i < input.length; i++) {
|
|
7
|
-
hash = (hash * 31 + input.charCodeAt(i)) >>> 0;
|
|
8
|
-
}
|
|
9
|
-
return hash.toString(36).slice(0, 5);
|
|
10
|
-
}
|
package/request/http.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from "http";
|
|
2
|
-
import type { ViteDevServer } from "vite";
|
|
3
|
-
import type { GenericContext } from "~/router.js";
|
|
4
|
-
type Config = {
|
|
5
|
-
build: Promise<any> | (() => Promise<Record<string, any>>);
|
|
6
|
-
viteDevServer: ViteDevServer | null;
|
|
7
|
-
render: GenericContext["render"];
|
|
8
|
-
};
|
|
9
|
-
export declare function createRequestHandler(config: Config): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
10
|
-
export {};
|
package/request/http.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Resolve } from "~/request/native.js";
|
|
2
|
-
export function createRequestHandler(config) {
|
|
3
|
-
return async (req, res) => {
|
|
4
|
-
try {
|
|
5
|
-
const mod = typeof config.build === "function" ? await config.build() : await config.build;
|
|
6
|
-
const request = NativeRequest(req);
|
|
7
|
-
let { response, headers } = await Resolve(request, mod.tree, config);
|
|
8
|
-
res.writeHead(response.status, headers);
|
|
9
|
-
if (response.body instanceof ReadableStream) {
|
|
10
|
-
const reader = response.body.getReader();
|
|
11
|
-
while (true) {
|
|
12
|
-
const { done, value } = await reader.read();
|
|
13
|
-
if (done)
|
|
14
|
-
break;
|
|
15
|
-
res.write(value); // `value` is a Uint8Array.
|
|
16
|
-
}
|
|
17
|
-
res.end();
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
const rendered = await response.text();
|
|
21
|
-
res.end(rendered);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
res.statusCode = 500;
|
|
26
|
-
if (e instanceof Error) {
|
|
27
|
-
console.error(e.stack);
|
|
28
|
-
config.viteDevServer?.ssrFixStacktrace(e);
|
|
29
|
-
res.end(e.stack);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
console.error(e);
|
|
33
|
-
res.end(String(e));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
function NativeRequest(req) {
|
|
39
|
-
const ctrl = new AbortController();
|
|
40
|
-
const headers = new Headers(req.headers);
|
|
41
|
-
const url = new URL(`http://${headers.get('host')}${req.originalUrl || req.url}`);
|
|
42
|
-
req.once('aborted', () => ctrl.abort());
|
|
43
|
-
const bodied = req.method !== "GET" && req.method !== "HEAD";
|
|
44
|
-
const request = new Request(url, {
|
|
45
|
-
headers,
|
|
46
|
-
method: req.method,
|
|
47
|
-
body: bodied ? req : undefined,
|
|
48
|
-
signal: ctrl.signal,
|
|
49
|
-
referrer: headers.get("referrer") || undefined,
|
|
50
|
-
// @ts-ignore
|
|
51
|
-
duplex: bodied ? 'half' : undefined
|
|
52
|
-
});
|
|
53
|
-
if (!request.headers.has("X-Real-IP")) {
|
|
54
|
-
const info = req.socket.address();
|
|
55
|
-
if ("address" in info)
|
|
56
|
-
request.headers.set("X-Real-IP", info.address);
|
|
57
|
-
}
|
|
58
|
-
return request;
|
|
59
|
-
}
|
package/request/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ViteDevServer } from "vite";
|
|
2
|
-
import type { GenericContext, RouteTree } from '~/router.js';
|
|
3
|
-
import * as native from "~/request/native.js";
|
|
4
|
-
import * as http from "~/request/http.js";
|
|
5
|
-
export type Config = {
|
|
6
|
-
build: Promise<any> | (() => Promise<Record<string, any>>);
|
|
7
|
-
viteDevServer: ViteDevServer | null;
|
|
8
|
-
render: GenericContext["render"];
|
|
9
|
-
};
|
|
10
|
-
export type RouterModule = {
|
|
11
|
-
tree: RouteTree;
|
|
12
|
-
};
|
|
13
|
-
export { http, native };
|
package/request/index.js
DELETED
package/request/native.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type RouteTree } from '~/router.js';
|
|
2
|
-
import type { Config } from '~/request/index.js';
|
|
3
|
-
export declare function createRequestHandler(config: Config): (req: Request) => Promise<Response>;
|
|
4
|
-
export declare function Resolve(request: Request, tree: RouteTree, config: Config): Promise<{
|
|
5
|
-
response: Response;
|
|
6
|
-
headers: {
|
|
7
|
-
[key: string]: string | string[];
|
|
8
|
-
};
|
|
9
|
-
}>;
|
package/request/native.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { GenericContext } from '~/router.js';
|
|
2
|
-
export function createRequestHandler(config) {
|
|
3
|
-
return async (req) => {
|
|
4
|
-
try {
|
|
5
|
-
const mod = typeof config.build === "function" ? await config.build() : await config.build;
|
|
6
|
-
let { response } = await Resolve(req, mod.tree, config);
|
|
7
|
-
return response;
|
|
8
|
-
}
|
|
9
|
-
catch (e) {
|
|
10
|
-
if (e instanceof Error) {
|
|
11
|
-
console.error(e.stack);
|
|
12
|
-
config.viteDevServer?.ssrFixStacktrace(e);
|
|
13
|
-
return new Response(e.message + "\n" + e.stack, { status: 500, statusText: "Internal Server Error" });
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
console.error(e);
|
|
17
|
-
return new Response(String(e), { status: 500, statusText: "Internal Server Error" });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
export async function Resolve(request, tree, config) {
|
|
23
|
-
const url = new URL(request.url);
|
|
24
|
-
const ctx = new GenericContext(request, url, config.render);
|
|
25
|
-
const x = ctx.url.pathname.endsWith("/") ? ctx.url.pathname.slice(0, -1) : ctx.url.pathname;
|
|
26
|
-
const fragments = x.split("/").slice(1);
|
|
27
|
-
let response = await tree.resolve(fragments, ctx);
|
|
28
|
-
if (response === null)
|
|
29
|
-
response = new Response("No Route Found", { status: 404, statusText: "Not Found", headers: ctx.headers });
|
|
30
|
-
// Override with context headers
|
|
31
|
-
if (response.headers !== ctx.headers) {
|
|
32
|
-
for (const [key, value] of ctx.headers) {
|
|
33
|
-
if (response.headers.has(key))
|
|
34
|
-
continue;
|
|
35
|
-
response.headers.set(key, value);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// Merge cookie changes
|
|
39
|
-
const headers = Object.fromEntries(response.headers);
|
|
40
|
-
const cookies = ctx.cookie.export();
|
|
41
|
-
if (cookies.length > 0) {
|
|
42
|
-
headers['set-cookie'] = cookies;
|
|
43
|
-
response.headers.set("Set-Cookie", cookies[0]); // Response object doesn't support multi-header..[]
|
|
44
|
-
}
|
|
45
|
-
return { response, headers };
|
|
46
|
-
}
|
package/vite/code-splitting.d.ts
DELETED
package/vite/code-splitting.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const serverPattern = /\.server\.[tj]s(x)?/;
|
|
2
|
-
const clientPattern = /\.client\.[tj]s(x)?/;
|
|
3
|
-
export function BundleSplitting() {
|
|
4
|
-
return {
|
|
5
|
-
name: "htmx-bundle-splitter",
|
|
6
|
-
enforce: "pre",
|
|
7
|
-
transform: (code, id, options) => {
|
|
8
|
-
const pattern = options?.ssr ? clientPattern : serverPattern;
|
|
9
|
-
if (pattern.test(id))
|
|
10
|
-
return "export {};";
|
|
11
|
-
return code;
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|