@janit/fu 0.0.4 → 0.1.0
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/README.md +31 -14
- package/dist/app.d.ts +0 -2
- package/dist/app.js +0 -4
- package/dist/app.js.map +1 -1
- package/dist/build.d.ts +0 -2
- package/dist/build.js +10 -85
- package/dist/build.js.map +1 -1
- package/dist/cli.js +7 -7
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +7 -1
- package/dist/client.js +18 -7
- package/dist/client.js.map +1 -1
- package/dist/dev.js +13 -66
- package/dist/dev.js.map +1 -1
- package/dist/driver.d.ts +66 -0
- package/dist/driver.js +182 -0
- package/dist/driver.js.map +1 -0
- package/dist/hmr-runtime.js +21 -19
- package/dist/plugins.d.ts +7 -24
- package/dist/plugins.js +18 -58
- package/dist/plugins.js.map +1 -1
- package/dist/render.d.ts +3 -3
- package/dist/render.js +6 -9
- package/dist/render.js.map +1 -1
- package/dist/router.d.ts +17 -0
- package/dist/router.js +37 -6
- package/dist/router.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,9 +8,10 @@ No Vite, no Babel, no esbuild. The bundler, JSX transform and CSS engine are
|
|
|
8
8
|
all Rust.
|
|
9
9
|
|
|
10
10
|
```
|
|
11
|
-
core ~
|
|
12
|
-
drivers ~
|
|
11
|
+
core ~560 lines router + render + client + hmr runtime
|
|
12
|
+
drivers ~490 lines build + dev + shared driver glue + rolldown plugins
|
|
13
13
|
```
|
|
14
|
+
(code lines, comments and blanks excluded)
|
|
14
15
|
|
|
15
16
|
## What this is
|
|
16
17
|
|
|
@@ -47,15 +48,19 @@ deno task todo:dev # the fu-todo example app
|
|
|
47
48
|
deno task todo:build
|
|
48
49
|
deno task todo:start # serve its build on :1337
|
|
49
50
|
|
|
50
|
-
deno task test #
|
|
51
|
-
deno task check # types
|
|
52
|
-
deno task check:pkg # build and serve a real app from the packed npm artefact
|
|
51
|
+
deno task test # 59 unit tests
|
|
52
|
+
deno task check # format, lint, types (framework and both apps), tests, jsr dry-run
|
|
53
|
+
deno task check:pkg # build, serve and dev-serve a real app from the packed npm artefact
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
Both example apps build against **this checkout's `src/`**, never a published
|
|
56
57
|
package, so the framework and the apps can be changed and tested together
|
|
57
|
-
before anything is released.
|
|
58
|
-
|
|
58
|
+
before anything is released. The drivers make that hold: they alias the
|
|
59
|
+
framework's own package name to the runtime copy they are running from, so an
|
|
60
|
+
app's `import { App } from "@janit/fu"` cannot drift to a stale
|
|
61
|
+
`dist/` through Node's package self-reference. The apps are Deno workspace
|
|
62
|
+
members, so `deno check` sees the same mapping. `npm install` at the root is
|
|
63
|
+
the only setup step; it serves the whole repo.
|
|
59
64
|
|
|
60
65
|
Then run the build on whichever runtime you like — one artifact, three runtimes:
|
|
61
66
|
|
|
@@ -232,9 +237,17 @@ type RouteManifest = Record<string, () => Promise<RouteModule>>;
|
|
|
232
237
|
type Assets = { js: { href: string }[]; css: { href: string }[] };
|
|
233
238
|
```
|
|
234
239
|
|
|
235
|
-
Everything bundler-specific lives in the drivers (`src/build.ts`, `src/dev.ts`)
|
|
236
|
-
|
|
237
|
-
|
|
240
|
+
Everything bundler-specific lives in the drivers (`src/build.ts`, `src/dev.ts`),
|
|
241
|
+
the glue they share (`src/driver.ts`: locating the runtime modules, scanning a
|
|
242
|
+
project, the rolldown and nitro option sets) and the rolldown plugins
|
|
243
|
+
(`src/plugins.ts`). The same core ran unchanged under a Vite driver during
|
|
244
|
+
prototyping, so swapping the build layer stays cheap.
|
|
245
|
+
|
|
246
|
+
Routing is on `URLPattern`, but `exec` costs microseconds per route on Deno,
|
|
247
|
+
so it only runs when it can matter: a route with no pattern syntax is matched
|
|
248
|
+
by string equality against its canonical pathname, and a pattern whose
|
|
249
|
+
segment count cannot fit the path is skipped. A static hit is ~65 ns and a
|
|
250
|
+
dynamic one ~1.6 µs with 16 routes, down from 28 µs and 57 µs.
|
|
238
251
|
|
|
239
252
|
See [the design doc](docs/design.md) for
|
|
240
253
|
the full rationale and the nine undocumented traps this implementation encodes.
|
|
@@ -250,11 +263,12 @@ failure modes this framework actually hit, so each one guards a real regression:
|
|
|
250
263
|
|
|
251
264
|
| area | what it pins down |
|
|
252
265
|
|---|---|
|
|
253
|
-
| router | static beats dynamic beats wildcard; wildcards span segments; params decode |
|
|
266
|
+
| router | static beats dynamic beats wildcard; wildcards span segments and match their own base path; params decode; a non-ASCII static route matches its percent-encoded request |
|
|
254
267
|
| middleware | outer unwinds last and decorates inner short-circuits; `next()` twice rejects; throws propagate |
|
|
255
268
|
| render | head escaping; JSON-LD cannot close its own `<script>`; 404 vs 405; islands get a marker |
|
|
256
269
|
| errors | a 500 never leaks its message; error responses are uncacheable; a broken error page falls back |
|
|
257
|
-
| plugins | `composes` keeps every class name; CSS output changes with content; the JSX transform never touches rolldown's runtime; the
|
|
270
|
+
| plugins | `composes` keeps every class name; CSS output changes with content; the JSX transform never touches rolldown's runtime; the package self-alias |
|
|
271
|
+
| driver | the server entry imports only the optional files that exist; the H3Event unwrap |
|
|
258
272
|
|
|
259
273
|
Two of these were found by writing the suite, not before it: `ctx.next()` called
|
|
260
274
|
twice resumed at the wrong depth, and a middleware throwing synchronously
|
|
@@ -274,8 +288,11 @@ private history leaks:
|
|
|
274
288
|
the privacy boundary, a staged-tree backstop that refuses the push if anything
|
|
275
289
|
private reaches the index anyway, semver tagging derived from the public repo's
|
|
276
290
|
existing tags, and version stamping so the git tag and `deno.json` cannot drift.
|
|
277
|
-
`fu-todo/` is stripped from `janit/fu
|
|
278
|
-
from `../src/mod.ts` on the way into
|
|
291
|
+
`fu-todo/` is stripped from `janit/fu`, and from its Deno workspace; the
|
|
292
|
+
framework specifier is rewritten from `../src/mod.ts` on the way into
|
|
293
|
+
`janit/fu-todo`, which also gets its own `nodeModulesDir` since it is no
|
|
294
|
+
longer a workspace member there. Both flows can be rehearsed against a local
|
|
295
|
+
bare repository by overriding `PUBLIC_REPO`.
|
|
279
296
|
|
|
280
297
|
## Known gaps
|
|
281
298
|
|
package/dist/app.d.ts
CHANGED
|
@@ -20,6 +20,4 @@ export declare class App<S = Record<string, unknown>> {
|
|
|
20
20
|
use(middleware: Middleware<S>): this;
|
|
21
21
|
/** The registered chain, in registration order. */
|
|
22
22
|
get middleware(): readonly Middleware<S>[];
|
|
23
|
-
/** Wrap a terminal handler in this app's chain. */
|
|
24
|
-
compose(terminal: (ctx: Ctx<S>) => Response | Promise<Response>): (ctx: Ctx<S>) => Promise<Response>;
|
|
25
23
|
}
|
package/dist/app.js
CHANGED
package/dist/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,SAAS,MAAM,CAAC,EAAsC;IACpD,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,UAAoC,EACpC,QAAuD;IAEvD,OAAO,CAAC,IAAY,EAAqB,EAAE;QACzC,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,IAAY,EAAqB,EAAE;YAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YACzB,oEAAoE;YACpE,sEAAsE;YACtE,uCAAuC;YACvC,IAAI,CAAC,EAAE;gBAAE,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAE7C,qEAAqE;YACrE,yEAAyE;YACzE,qEAAqE;YACrE,yDAAyD;YACzD,IAAI,MAAM,GAAG,KAAK,CAAC;YACnB,MAAM,GAAG,GAAW;gBAClB,GAAG,IAAI;gBACP,IAAI,EAAE,GAAG,EAAE;oBACT,IAAI,MAAM,EAAE,CAAC;wBACX,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,wDAAwD,CAAC,CACpE,CAAC;oBACJ,CAAC;oBACD,MAAM,GAAG,IAAI,CAAC;oBACd,OAAO,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC9B,CAAC;aACF,CAAC;YACF,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC;QACF,OAAO,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,GAAG;IACL,WAAW,GAAoB,EAAE,CAAC;IAE3C,gEAAgE;IAChE,GAAG,CAAC,UAAyB;QAC3B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mDAAmD;IACnD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,SAAS,MAAM,CAAC,EAAsC;IACpD,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,UAAoC,EACpC,QAAuD;IAEvD,OAAO,CAAC,IAAY,EAAqB,EAAE;QACzC,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,IAAY,EAAqB,EAAE;YAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YACzB,oEAAoE;YACpE,sEAAsE;YACtE,uCAAuC;YACvC,IAAI,CAAC,EAAE;gBAAE,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAE7C,qEAAqE;YACrE,yEAAyE;YACzE,qEAAqE;YACrE,yDAAyD;YACzD,IAAI,MAAM,GAAG,KAAK,CAAC;YACnB,MAAM,GAAG,GAAW;gBAClB,GAAG,IAAI;gBACP,IAAI,EAAE,GAAG,EAAE;oBACT,IAAI,MAAM,EAAE,CAAC;wBACX,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,wDAAwD,CAAC,CACpE,CAAC;oBACJ,CAAC;oBACD,MAAM,GAAG,IAAI,CAAC;oBACd,OAAO,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC9B,CAAC;aACF,CAAC;YACF,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC;QACF,OAAO,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,GAAG;IACL,WAAW,GAAoB,EAAE,CAAC;IAE3C,gEAAgE;IAChE,GAAG,CAAC,UAAyB;QAC3B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mDAAmD;IACnD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF"}
|
package/dist/build.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
import type { FuOptions } from "./types.js";
|
|
2
2
|
export declare function build(opts: FuOptions): Promise<void>;
|
|
3
|
-
/** Concatenate collected stylesheets into one hashed file. Returns its name. */
|
|
4
|
-
export declare function writeSheets(dir: string, sheets: Map<string, string>): string | null;
|
package/dist/build.js
CHANGED
|
@@ -1,52 +1,17 @@
|
|
|
1
1
|
// Production driver: rolldown builds the client, nitro builds the server.
|
|
2
2
|
import { rolldown } from "rolldown";
|
|
3
3
|
import { build as nitroBuild, copyPublicAssets, createNitro } from "nitro/builder";
|
|
4
|
-
import * as fs from "node:fs";
|
|
5
4
|
import * as path from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
/**
|
|
8
|
-
* Directory holding the framework's own runtime modules, whose paths are handed
|
|
9
|
-
* to rolldown. `import.meta.dirname` is undefined when this module is loaded
|
|
10
|
-
* from a remote URL, and a bundler cannot fetch `https:` modules anyway — so
|
|
11
|
-
* fail with the reason rather than a TypeError three frames later.
|
|
12
|
-
*/
|
|
13
|
-
const HERE = import.meta.dirname ?? remoteFrameworkError();
|
|
14
|
-
/**
|
|
15
|
-
* Extension of the framework's own runtime modules: `.ts` when running from
|
|
16
|
-
* source (this repo, or JSR), `.js` when running from the compiled npm build.
|
|
17
|
-
*/
|
|
18
|
-
const EXT = import.meta.url.endsWith(".js") ? ".js" : ".ts";
|
|
19
|
-
function remoteFrameworkError() {
|
|
20
|
-
throw new Error("fu: the framework is loaded from a remote URL (" + import.meta.url + "), " +
|
|
21
|
-
"so its runtime modules cannot be handed to the bundler. Install it " +
|
|
22
|
-
"instead — `npm:@janit/fu` in a Deno import map, or `npm i @janit/fu` — " +
|
|
23
|
-
"so it resolves to a real directory.");
|
|
24
|
-
}
|
|
5
|
+
import { clientInput, emptyDir, nitroOptions, scanProject, writeSheets, writeSsrEntry, } from "./driver.js";
|
|
25
6
|
export async function build(opts) {
|
|
26
|
-
const
|
|
27
|
-
const outDir = opts.outDir ? path.resolve(opts.outDir) : path.join(root, ".output");
|
|
28
|
-
const clientDir = path.join(root, "dist/client");
|
|
29
|
-
const genDir = path.join(root, ".fu");
|
|
30
|
-
const routeFiles = walk(root, path.join(root, "routes"));
|
|
31
|
-
const islandFiles = walk(root, path.join(root, "islands"));
|
|
7
|
+
const project = scanProject(opts.root);
|
|
8
|
+
const outDir = opts.outDir ? path.resolve(opts.outDir) : path.join(project.root, ".output");
|
|
32
9
|
// ---- client ----
|
|
33
|
-
|
|
34
|
-
fs.mkdirSync(clientDir, { recursive: true });
|
|
10
|
+
emptyDir(project.clientDir);
|
|
35
11
|
const sheets = new Map();
|
|
36
|
-
const bundle = await rolldown(
|
|
37
|
-
input: { boot: "fu:boot" },
|
|
38
|
-
plugins: [
|
|
39
|
-
virtual({ "fu:boot": bootModule(path.join(HERE, `client${EXT}`), islandFiles, root) }),
|
|
40
|
-
css(sheets),
|
|
41
|
-
jsx(),
|
|
42
|
-
],
|
|
43
|
-
platform: "browser",
|
|
44
|
-
// rolldown types modules by extension and refuses to bundle CSS; css()
|
|
45
|
-
// has already replaced their contents with JS.
|
|
46
|
-
moduleTypes: { ".css": "js" },
|
|
47
|
-
});
|
|
12
|
+
const bundle = await rolldown(clientInput(project, sheets));
|
|
48
13
|
const result = await bundle.write({
|
|
49
|
-
dir: clientDir,
|
|
14
|
+
dir: project.clientDir,
|
|
50
15
|
format: "esm",
|
|
51
16
|
entryFileNames: "[name]-[hash].js",
|
|
52
17
|
chunkFileNames: "[name]-[hash].js",
|
|
@@ -55,54 +20,14 @@ export async function build(opts) {
|
|
|
55
20
|
const entry = result.output.find((o) => o.type === "chunk" && o.isEntry);
|
|
56
21
|
if (!entry)
|
|
57
22
|
throw new Error("fu: client build produced no entry chunk");
|
|
58
|
-
const
|
|
23
|
+
const cssFile = writeSheets(project.clientDir, sheets);
|
|
59
24
|
// ---- server ----
|
|
60
|
-
|
|
61
|
-
fs.mkdirSync(genDir, { recursive: true });
|
|
62
|
-
const assets = {
|
|
25
|
+
const ssrEntry = writeSsrEntry(project, {
|
|
63
26
|
js: [{ href: "/" + entry.fileName }],
|
|
64
|
-
css:
|
|
65
|
-
};
|
|
66
|
-
// nitro path-resolves `handlers[].handler`, so a virtual id would not survive
|
|
67
|
-
// its routing codegen — generate a real file.
|
|
68
|
-
const ssrEntry = path.join(genDir, "ssr.ts");
|
|
69
|
-
fs.writeFileSync(ssrEntry, ssrModule({
|
|
70
|
-
renderPath: path.join(HERE, `render${EXT}`),
|
|
71
|
-
routeFiles,
|
|
72
|
-
root,
|
|
73
|
-
assets: JSON.stringify(assets),
|
|
74
|
-
appPath: optional(root, "app.ts", "app.tsx"),
|
|
75
|
-
shellPath: optional(root, "routes/_app.tsx"),
|
|
76
|
-
errorPath: optional(root, "routes/_error.tsx"),
|
|
77
|
-
}));
|
|
78
|
-
const nitro = await createNitro({
|
|
79
|
-
rootDir: root,
|
|
80
|
-
// Point nitro's scanner at the generated dir, never the project root, or it
|
|
81
|
-
// claims `routes/` as its own server routes and shadows our catch-all.
|
|
82
|
-
serverDir: genDir,
|
|
83
|
-
scanDirs: [],
|
|
84
|
-
output: { dir: outDir },
|
|
85
|
-
publicAssets: [{ dir: clientDir, baseURL: "/" }],
|
|
86
|
-
handlers: [{ route: "/**", handler: ssrEntry, format: "web", lazy: false }],
|
|
87
|
-
rollupConfig: {
|
|
88
|
-
// Islands are imported on the server too, so SSR needs the same handling.
|
|
89
|
-
plugins: [css(new Map()), jsx({ stampIslands: true })],
|
|
90
|
-
moduleTypes: { ".css": "js" },
|
|
91
|
-
},
|
|
27
|
+
css: cssFile ? [{ href: "/" + cssFile }] : [],
|
|
92
28
|
});
|
|
29
|
+
const nitro = await createNitro({ ...nitroOptions(project, ssrEntry), output: { dir: outDir } });
|
|
93
30
|
await copyPublicAssets(nitro);
|
|
94
31
|
await nitroBuild(nitro);
|
|
95
32
|
}
|
|
96
|
-
/** Concatenate collected stylesheets into one hashed file. Returns its name. */
|
|
97
|
-
export function writeSheets(dir, sheets) {
|
|
98
|
-
if (sheets.size === 0)
|
|
99
|
-
return null;
|
|
100
|
-
const merged = [...sheets.values()].join("\n");
|
|
101
|
-
let h = 7;
|
|
102
|
-
for (let i = 0; i < merged.length; i++)
|
|
103
|
-
h = (Math.imul(h, 31) + merged.charCodeAt(i)) >>> 0;
|
|
104
|
-
const name = `style-${h.toString(36)}.css`;
|
|
105
|
-
fs.writeFileSync(path.join(dir, name), merged);
|
|
106
|
-
return name;
|
|
107
|
-
}
|
|
108
33
|
//# sourceMappingURL=build.js.map
|
package/dist/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,WAAW,EACX,aAAa,GACd,MAAM,aAAa,CAAC;AAGrB,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAe;IACzC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAE5F,mBAAmB;IACnB,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;QAChC,GAAG,EAAE,OAAO,CAAC,SAAS;QACtB,MAAM,EAAE,KAAK;QACb,cAAc,EAAE,kBAAkB;QAClC,cAAc,EAAE,kBAAkB;KACnC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IAErB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEvD,mBAAmB;IACnB,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,EAAE;QACtC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QACpC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KAC9C,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IACjG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env -S deno run -A
|
|
2
|
+
import process from "node:process";
|
|
2
3
|
import { build } from "./build.js";
|
|
3
4
|
import { dev } from "./dev.js";
|
|
4
5
|
export async function main(argv) {
|
|
5
6
|
const [cmd = "dev", ...rest] = argv;
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const rootArg = rest.find((a) => !a.startsWith("-"));
|
|
7
|
+
const flag = (name) => rest.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3);
|
|
8
|
+
const port = flag("port");
|
|
9
9
|
const opts = {
|
|
10
|
-
root:
|
|
11
|
-
port:
|
|
12
|
-
hostname:
|
|
10
|
+
root: rest.find((a) => !a.startsWith("-")) ?? process.cwd(),
|
|
11
|
+
port: port ? Number(port) : undefined,
|
|
12
|
+
hostname: flag("host"),
|
|
13
13
|
};
|
|
14
14
|
if (cmd === "build")
|
|
15
15
|
await build(opts);
|
|
@@ -21,5 +21,5 @@ export async function main(argv) {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
if (import.meta.main)
|
|
24
|
-
await main(
|
|
24
|
+
await main(process.argv.slice(2));
|
|
25
25
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc;IACvC,MAAM,CAAC,GAAG,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc;IACvC,MAAM,CAAC,GAAG,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAC5B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG;QACX,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE;QAC3D,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QACrC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;KACvB,CAAC;IACF,IAAI,GAAG,KAAK,OAAO;QAAE,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;SAClC,IAAI,GAAG,KAAK,KAAK;QAAE,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC;SACnC,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,wBAAwB,CAAC,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,IAAI,OAAO,IAAI,CAAC,IAAI;IAAE,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type FunctionComponent } from "preact";
|
|
2
2
|
type Props = Record<string, unknown>;
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Hydrate every `[data-island]` marker the server rendered.
|
|
5
|
+
*
|
|
6
|
+
* Every distinct island module is fetched at once, then the markers are
|
|
7
|
+
* hydrated in document order; awaiting each in turn would serialise one
|
|
8
|
+
* network round-trip per island.
|
|
9
|
+
*/
|
|
4
10
|
export declare function hydrateIslands(manifest: Record<string, () => Promise<{
|
|
5
11
|
default: FunctionComponent<Props>;
|
|
6
12
|
}>>): Promise<void>;
|
package/dist/client.js
CHANGED
|
@@ -25,18 +25,29 @@ function proxyFor(key, impl) {
|
|
|
25
25
|
proxies.set(key, entry);
|
|
26
26
|
return entry;
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Hydrate every `[data-island]` marker the server rendered.
|
|
30
|
+
*
|
|
31
|
+
* Every distinct island module is fetched at once, then the markers are
|
|
32
|
+
* hydrated in document order; awaiting each in turn would serialise one
|
|
33
|
+
* network round-trip per island.
|
|
34
|
+
*/
|
|
29
35
|
export async function hydrateIslands(manifest) {
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
const els = [...document.querySelectorAll("[data-island]")];
|
|
37
|
+
const keys = [...new Set(els.map((el) => el.dataset.island))];
|
|
38
|
+
const loaded = new Map(await Promise.all(keys.map(async (key) => {
|
|
32
39
|
const loader = manifest[key];
|
|
33
|
-
if (!loader)
|
|
40
|
+
if (!loader)
|
|
34
41
|
console.warn("[fu] no island module for", key);
|
|
42
|
+
return [key, loader ? (await loader()).default : null];
|
|
43
|
+
})));
|
|
44
|
+
for (const el of els) {
|
|
45
|
+
const key = el.dataset.island;
|
|
46
|
+
const impl = loaded.get(key);
|
|
47
|
+
if (!impl)
|
|
35
48
|
continue;
|
|
36
|
-
}
|
|
37
|
-
const mod = await loader();
|
|
38
49
|
const props = JSON.parse(el.dataset.props || "{}");
|
|
39
|
-
hydrate(h(proxyFor(key,
|
|
50
|
+
hydrate(h(proxyFor(key, impl).Component, props), el);
|
|
40
51
|
const list = mounted.get(key) ?? [];
|
|
41
52
|
list.push({ el, props });
|
|
42
53
|
mounted.set(key, list);
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAepE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;AAC7C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;AAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,GAAW,EAAE,IAA8B;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAC7B,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjC,6EAA6E;IAC7E,8EAA8E;IAC9E,uCAAuC;IACvC,MAAM,SAAS,GAAG,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAS,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClF,MAAM,KAAK,GAAgB,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC;AACf,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/dev.js
CHANGED
|
@@ -5,71 +5,38 @@ import { serve } from "crossws/server";
|
|
|
5
5
|
import { build as nitroBuild, createDevServer, createNitro, prepare } from "nitro/builder";
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
import {
|
|
9
|
-
/**
|
|
10
|
-
* Directory holding the framework's own runtime modules, whose paths are handed
|
|
11
|
-
* to rolldown. `import.meta.dirname` is undefined when this module is loaded
|
|
12
|
-
* from a remote URL, and a bundler cannot fetch `https:` modules anyway — so
|
|
13
|
-
* fail with the reason rather than a TypeError three frames later.
|
|
14
|
-
*/
|
|
15
|
-
const HERE = import.meta.dirname ?? remoteFrameworkError();
|
|
16
|
-
/**
|
|
17
|
-
* Extension of the framework's own runtime modules: `.ts` when running from
|
|
18
|
-
* source (this repo, or JSR), `.js` when running from the compiled npm build.
|
|
19
|
-
*/
|
|
20
|
-
const EXT = import.meta.url.endsWith(".js") ? ".js" : ".ts";
|
|
21
|
-
function remoteFrameworkError() {
|
|
22
|
-
throw new Error("fu: the framework is loaded from a remote URL (" + import.meta.url + "), " +
|
|
23
|
-
"so its runtime modules cannot be handed to the bundler. Install it " +
|
|
24
|
-
"instead — `npm:@janit/fu` in a Deno import map, or `npm i @janit/fu` — " +
|
|
25
|
-
"so it resolves to a real directory.");
|
|
26
|
-
}
|
|
8
|
+
import { clientInput, emptyDir, nitroOptions, runtime, scanProject, writeSheets, writeSsrEntry, } from "./driver.js";
|
|
27
9
|
export async function dev(opts) {
|
|
28
|
-
const
|
|
10
|
+
const project = scanProject(opts.root);
|
|
11
|
+
const { clientDir } = project;
|
|
29
12
|
const port = opts.port ?? 1337;
|
|
30
13
|
// Bind all interfaces so the dev server is reachable from other machines
|
|
31
14
|
// and from inside containers, not just loopback.
|
|
32
15
|
const hostname = opts.hostname ?? "0.0.0.0";
|
|
33
16
|
const hmrPort = port + 1;
|
|
34
|
-
|
|
35
|
-
const genDir = path.join(root, ".fu");
|
|
36
|
-
const routeFiles = walk(root, path.join(root, "routes"));
|
|
37
|
-
const islandFiles = walk(root, path.join(root, "islands"));
|
|
38
|
-
fs.rmSync(clientDir, { recursive: true, force: true });
|
|
39
|
-
fs.mkdirSync(clientDir, { recursive: true });
|
|
17
|
+
emptyDir(clientDir);
|
|
40
18
|
const sheets = new Map();
|
|
41
19
|
const peers = new Map();
|
|
42
20
|
let cssVersion = 0;
|
|
43
|
-
const
|
|
44
|
-
if (sheets.size)
|
|
45
|
-
fs.writeFileSync(path.join(clientDir, "style.css"), [...sheets.values()].join("\n"));
|
|
46
|
-
};
|
|
21
|
+
const flushCss = () => writeSheets(clientDir, sheets, "style.css");
|
|
47
22
|
// `implement` takes the runtime SOURCE, not a path — a path gets inlined
|
|
48
23
|
// literally and parsed as a regex. `$ADDR` is only substituted in rolldown's
|
|
49
24
|
// own default runtime, so do it here.
|
|
50
|
-
const hmrRuntime = fs.readFileSync(
|
|
51
|
-
.replaceAll("$ADDR", `localhost:${hmrPort}`);
|
|
25
|
+
const hmrRuntime = fs.readFileSync(runtime.hmr, "utf8").replaceAll("$ADDR", `localhost:${hmrPort}`);
|
|
52
26
|
const engine = await DevEngine.create({
|
|
53
|
-
|
|
54
|
-
plugins: [
|
|
55
|
-
virtual({ "fu:boot": bootModule(path.join(HERE, `client${EXT}`), islandFiles, root) }),
|
|
56
|
-
css(sheets),
|
|
57
|
-
jsx({ hmr: true }),
|
|
58
|
-
],
|
|
59
|
-
platform: "browser",
|
|
60
|
-
moduleTypes: { ".css": "js" },
|
|
27
|
+
...clientInput(project, sheets, true),
|
|
61
28
|
experimental: { devMode: { host: "localhost", port: hmrPort, implement: hmrRuntime } },
|
|
62
29
|
}, { dir: clientDir, format: "esm", entryFileNames: "[name].js", chunkFileNames: "[name].js" }, {
|
|
63
30
|
watch: { enabled: true },
|
|
64
31
|
onOutput(o) {
|
|
65
32
|
if (o instanceof Error)
|
|
66
33
|
return console.error("[fu] client build failed:", o.message);
|
|
67
|
-
|
|
34
|
+
flushCss();
|
|
68
35
|
},
|
|
69
36
|
onHmrUpdates(r) {
|
|
70
37
|
if (r instanceof Error)
|
|
71
38
|
return console.error("[fu] hmr error:", r.message);
|
|
72
|
-
|
|
39
|
+
flushCss();
|
|
73
40
|
for (const { clientId, update } of r.updates) {
|
|
74
41
|
const peer = peers.get(clientId);
|
|
75
42
|
if (!peer || update.type === "Noop")
|
|
@@ -132,31 +99,11 @@ export async function dev(opts) {
|
|
|
132
99
|
},
|
|
133
100
|
});
|
|
134
101
|
// SSR.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const assets = `{ js: [{ href: "/boot.js" }], css: [{ href: "/style.css" }] }`;
|
|
139
|
-
fs.writeFileSync(ssrEntry, ssrModule({
|
|
140
|
-
renderPath: path.join(HERE, `render${EXT}`),
|
|
141
|
-
routeFiles,
|
|
142
|
-
root,
|
|
143
|
-
assets,
|
|
144
|
-
appPath: optional(root, "app.ts", "app.tsx"),
|
|
145
|
-
shellPath: optional(root, "routes/_app.tsx"),
|
|
146
|
-
errorPath: optional(root, "routes/_error.tsx"),
|
|
147
|
-
}));
|
|
148
|
-
const nitro = await createNitro({
|
|
149
|
-
dev: true,
|
|
150
|
-
rootDir: root,
|
|
151
|
-
serverDir: genDir,
|
|
152
|
-
scanDirs: [],
|
|
153
|
-
publicAssets: [{ dir: clientDir, baseURL: "/" }],
|
|
154
|
-
handlers: [{ route: "/**", handler: ssrEntry, format: "web", lazy: false }],
|
|
155
|
-
rollupConfig: {
|
|
156
|
-
plugins: [css(new Map()), jsx({ stampIslands: true })],
|
|
157
|
-
moduleTypes: { ".css": "js" },
|
|
158
|
-
},
|
|
102
|
+
const ssrEntry = writeSsrEntry(project, {
|
|
103
|
+
js: [{ href: "/boot.js" }],
|
|
104
|
+
css: [{ href: "/style.css" }],
|
|
159
105
|
});
|
|
106
|
+
const nitro = await createNitro({ ...nitroOptions(project, ssrEntry), dev: true });
|
|
160
107
|
const server = createDevServer(nitro);
|
|
161
108
|
server.listen({ port, hostname });
|
|
162
109
|
// Order matters: listen -> prepare -> build. `build` starts the dev runner.
|
package/dist/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,4CAA4C;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"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"}
|
package/dist/driver.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { createNitro } from "nitro/builder";
|
|
2
|
+
import type { InputOptions } from "rolldown";
|
|
3
|
+
import type { Assets } from "./types.js";
|
|
4
|
+
/** Absolute paths of the runtime modules the generated code imports. */
|
|
5
|
+
export declare const runtime: {
|
|
6
|
+
client: string;
|
|
7
|
+
render: string;
|
|
8
|
+
hmr: string;
|
|
9
|
+
};
|
|
10
|
+
/** Everything a driver needs to know about a project, found once up front. */
|
|
11
|
+
export interface Project {
|
|
12
|
+
root: string;
|
|
13
|
+
/** Root-relative, e.g. "/routes/blog/[slug].tsx". */
|
|
14
|
+
routeFiles: string[];
|
|
15
|
+
islandFiles: string[];
|
|
16
|
+
/** Absolute path to `app.ts`, if the project has one. */
|
|
17
|
+
appPath: string | null;
|
|
18
|
+
/** Absolute path to `routes/_app.tsx`, if the project has one. */
|
|
19
|
+
shellPath: string | null;
|
|
20
|
+
/** Absolute path to `routes/_error.tsx`, if the project has one. */
|
|
21
|
+
errorPath: string | null;
|
|
22
|
+
/** Client bundle output, served as public assets. */
|
|
23
|
+
clientDir: string;
|
|
24
|
+
/** Generated server entry. */
|
|
25
|
+
genDir: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function scanProject(root: string): Project;
|
|
28
|
+
/**
|
|
29
|
+
* Recursively list source files under `<root>/<sub>`, as root-relative
|
|
30
|
+
* "/sub/a/b.tsx". Underscore-prefixed files are skipped: they are framework
|
|
31
|
+
* files (`routes/_app.tsx`), not routes.
|
|
32
|
+
*/
|
|
33
|
+
export declare function walk(root: string, sub: string): string[];
|
|
34
|
+
/** Absolute path to an optional project file, or null when absent. */
|
|
35
|
+
export declare function optional(root: string, ...names: string[]): string | null;
|
|
36
|
+
/** Recreate `dir` empty. */
|
|
37
|
+
export declare function emptyDir(dir: string): void;
|
|
38
|
+
/** Rolldown input for the client bundle. */
|
|
39
|
+
export declare function clientInput(project: Project, sheets: Map<string, string>, hmr?: boolean): InputOptions;
|
|
40
|
+
/**
|
|
41
|
+
* Nitro options both drivers share. `serverDir` is the generated dir, never the
|
|
42
|
+
* project root, or nitro claims `routes/` as its own server routes and shadows
|
|
43
|
+
* the catch-all. Islands are imported on the server too, so SSR needs the same
|
|
44
|
+
* CSS and JSX handling as the client.
|
|
45
|
+
*/
|
|
46
|
+
export declare function nitroOptions(project: Project, ssrEntry: string): Parameters<typeof createNitro>[0];
|
|
47
|
+
/** Concatenate collected stylesheets into one file; hashed unless a name is given. */
|
|
48
|
+
export declare function writeSheets(dir: string, sheets: Map<string, string>, name?: string): string | null;
|
|
49
|
+
/** The client entry: hydrate every island the page carries. */
|
|
50
|
+
export declare function bootModule(project: Pick<Project, "root" | "islandFiles">): string;
|
|
51
|
+
/**
|
|
52
|
+
* The server entry: the route manifest, the optional app, shell and error
|
|
53
|
+
* page, and the handler wired to nitro.
|
|
54
|
+
*
|
|
55
|
+
* Nitro invokes the handler with an H3Event, not a Request. The event exposes
|
|
56
|
+
* `url`/`headers` directly — which is why routing worked long before anyone
|
|
57
|
+
* read a body — but has no json()/text()/formData(). The real Request is
|
|
58
|
+
* `event.req`.
|
|
59
|
+
*/
|
|
60
|
+
export declare function ssrModule(project: Pick<Project, "root" | "routeFiles" | "appPath" | "shellPath" | "errorPath">, assets: Assets): string;
|
|
61
|
+
/**
|
|
62
|
+
* Write the generated server entry and return its path. It has to be a real
|
|
63
|
+
* file: nitro path-resolves `handlers[].handler`, so a virtual id would not
|
|
64
|
+
* survive its routing codegen.
|
|
65
|
+
*/
|
|
66
|
+
export declare function writeSsrEntry(project: Project, assets: Assets): string;
|