@nifrajs/web 4.0.2 → 5.0.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 +11 -0
- package/dist/build-vite.d.ts +19 -0
- package/dist/build-vite.d.ts.map +1 -1
- package/dist/build-vite.js +31 -10
- package/dist/build-vite.js.map +1 -1
- package/dist/build.d.ts +8 -10
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +90 -31
- package/dist/build.js.map +1 -1
- package/dist/cdn.d.ts +8 -0
- package/dist/cdn.d.ts.map +1 -1
- package/dist/cdn.js +14 -15
- package/dist/cdn.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +25 -7
- package/dist/client.js.map +1 -1
- package/dist/deferred.d.ts +2 -2
- package/dist/deferred.d.ts.map +1 -1
- package/dist/deferred.js +28 -7
- package/dist/deferred.js.map +1 -1
- package/dist/dev-feed.d.ts.map +1 -1
- package/dist/dev-feed.js +24 -5
- package/dist/dev-feed.js.map +1 -1
- package/dist/dev-session.d.ts.map +1 -1
- package/dist/dev-session.js +4 -14
- package/dist/dev-session.js.map +1 -1
- package/dist/dev.d.ts +7 -17
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +13 -1
- package/dist/dev.js.map +1 -1
- package/dist/draft.d.ts +8 -5
- package/dist/draft.d.ts.map +1 -1
- package/dist/draft.js +30 -13
- package/dist/draft.js.map +1 -1
- package/dist/fonts-google.d.ts.map +1 -1
- package/dist/fonts-google.js +7 -0
- package/dist/fonts-google.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/codegen.d.ts +1 -0
- package/dist/internal/codegen.d.ts.map +1 -1
- package/dist/internal/codegen.js +56 -29
- package/dist/internal/codegen.js.map +1 -1
- package/dist/internal/disposable-dir.d.ts +8 -0
- package/dist/internal/disposable-dir.d.ts.map +1 -0
- package/dist/internal/disposable-dir.js +25 -0
- package/dist/internal/disposable-dir.js.map +1 -0
- package/dist/internal/entry-chunks.d.ts +9 -0
- package/dist/internal/entry-chunks.d.ts.map +1 -0
- package/dist/internal/entry-chunks.js +15 -0
- package/dist/internal/entry-chunks.js.map +1 -0
- package/dist/internal/evidence-traversal.d.ts +12 -0
- package/dist/internal/evidence-traversal.d.ts.map +1 -0
- package/dist/internal/evidence-traversal.js +48 -0
- package/dist/internal/evidence-traversal.js.map +1 -0
- package/dist/internal/head-merge.d.ts +6 -0
- package/dist/internal/head-merge.d.ts.map +1 -1
- package/dist/internal/head-merge.js +9 -0
- package/dist/internal/head-merge.js.map +1 -1
- package/dist/internal/js-string.d.ts +2 -0
- package/dist/internal/js-string.d.ts.map +1 -1
- package/dist/internal/js-string.js +5 -1
- package/dist/internal/js-string.js.map +1 -1
- package/dist/internal/mount-shadow.js +1 -1
- package/dist/internal/mount-shadow.js.map +1 -1
- package/dist/internal/output-guard.d.ts +7 -0
- package/dist/internal/output-guard.d.ts.map +1 -1
- package/dist/internal/output-guard.js +80 -8
- package/dist/internal/output-guard.js.map +1 -1
- package/dist/internal/page-execution.d.ts +6 -0
- package/dist/internal/page-execution.d.ts.map +1 -1
- package/dist/internal/page-execution.js +377 -108
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/progressive-cookies.d.ts +14 -0
- package/dist/internal/progressive-cookies.d.ts.map +1 -0
- package/dist/internal/progressive-cookies.js +43 -0
- package/dist/internal/progressive-cookies.js.map +1 -0
- package/dist/internal/public-env.d.ts +2 -0
- package/dist/internal/public-env.d.ts.map +1 -0
- package/dist/internal/public-env.js +13 -0
- package/dist/internal/public-env.js.map +1 -0
- package/dist/internal/render-document.d.ts +1 -0
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +28 -5
- package/dist/internal/render-document.js.map +1 -1
- package/dist/internal/response-controls.d.ts +2 -0
- package/dist/internal/response-controls.d.ts.map +1 -1
- package/dist/internal/response-controls.js +26 -16
- package/dist/internal/response-controls.js.map +1 -1
- package/dist/internal/revive-dates.d.ts +16 -0
- package/dist/internal/revive-dates.d.ts.map +1 -0
- package/dist/internal/revive-dates.js +32 -0
- package/dist/internal/revive-dates.js.map +1 -0
- package/dist/internal/route-path.d.ts +8 -0
- package/dist/internal/route-path.d.ts.map +1 -0
- package/dist/internal/route-path.js +8 -0
- package/dist/internal/route-path.js.map +1 -0
- package/dist/internal/secret-scan.d.ts.map +1 -1
- package/dist/internal/secret-scan.js +88 -20
- package/dist/internal/secret-scan.js.map +1 -1
- package/dist/internal/server-boundary.d.ts.map +1 -1
- package/dist/internal/server-boundary.js +33 -5
- package/dist/internal/server-boundary.js.map +1 -1
- package/dist/internal/web-app.d.ts +21 -16
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +73 -21
- package/dist/internal/web-app.js.map +1 -1
- package/dist/internal/wire-date.d.ts +3 -0
- package/dist/internal/wire-date.d.ts.map +1 -0
- package/dist/internal/wire-date.js +14 -0
- package/dist/internal/wire-date.js.map +1 -0
- package/dist/internal/zone-graph.d.ts +4 -0
- package/dist/internal/zone-graph.d.ts.map +1 -1
- package/dist/internal/zone-graph.js +54 -14
- package/dist/internal/zone-graph.js.map +1 -1
- package/dist/isr.d.ts +58 -2
- package/dist/isr.d.ts.map +1 -1
- package/dist/isr.js +296 -39
- package/dist/isr.js.map +1 -1
- package/dist/llms-txt.d.ts +2 -0
- package/dist/llms-txt.d.ts.map +1 -1
- package/dist/llms-txt.js +29 -3
- package/dist/llms-txt.js.map +1 -1
- package/dist/manifest.d.ts +28 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +3 -0
- package/dist/manifest.js.map +1 -1
- package/dist/open-resolved.d.ts +18 -0
- package/dist/open-resolved.d.ts.map +1 -0
- package/dist/open-resolved.js +62 -0
- package/dist/open-resolved.js.map +1 -0
- package/dist/plugins/kit.d.ts +1 -0
- package/dist/plugins/kit.d.ts.map +1 -1
- package/dist/plugins/kit.js +26 -11
- package/dist/plugins/kit.js.map +1 -1
- package/dist/plugins/vite-leak-guard.d.ts +3 -1
- package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
- package/dist/plugins/vite-leak-guard.js +4 -0
- package/dist/plugins/vite-leak-guard.js.map +1 -1
- package/dist/public-dir.d.ts +8 -1
- package/dist/public-dir.d.ts.map +1 -1
- package/dist/public-dir.js +17 -6
- package/dist/public-dir.js.map +1 -1
- package/dist/query.d.ts +13 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +89 -26
- package/dist/query.js.map +1 -1
- package/dist/render-seam.d.ts +2 -0
- package/dist/render-seam.d.ts.map +1 -1
- package/dist/render-seam.js +1 -0
- package/dist/render-seam.js.map +1 -1
- package/dist/route-types.d.ts.map +1 -1
- package/dist/route-types.js +20 -9
- package/dist/route-types.js.map +1 -1
- package/dist/router.d.ts +9 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +39 -46
- package/dist/router.js.map +1 -1
- package/dist/server-components/build-info.d.ts +3 -0
- package/dist/server-components/build-info.d.ts.map +1 -0
- package/dist/server-components/build-info.js +7 -0
- package/dist/server-components/build-info.js.map +1 -0
- package/dist/server-components/build-target.d.ts +12 -0
- package/dist/server-components/build-target.d.ts.map +1 -0
- package/dist/server-components/build-target.js +153 -0
- package/dist/server-components/build-target.js.map +1 -0
- package/dist/server-components/build.d.ts +24 -0
- package/dist/server-components/build.d.ts.map +1 -0
- package/dist/server-components/build.js +366 -0
- package/dist/server-components/build.js.map +1 -0
- package/dist/server-components/bundle-proof.d.ts +3 -0
- package/dist/server-components/bundle-proof.d.ts.map +1 -0
- package/dist/server-components/bundle-proof.js +23 -0
- package/dist/server-components/bundle-proof.js.map +1 -0
- package/dist/server-components/client.d.ts +46 -0
- package/dist/server-components/client.d.ts.map +1 -0
- package/dist/server-components/client.js +594 -0
- package/dist/server-components/client.js.map +1 -0
- package/dist/server-components/definition.d.ts +11 -0
- package/dist/server-components/definition.d.ts.map +1 -0
- package/dist/server-components/definition.js +94 -0
- package/dist/server-components/definition.js.map +1 -0
- package/dist/server-components/dev-http.d.ts +5 -0
- package/dist/server-components/dev-http.d.ts.map +1 -0
- package/dist/server-components/dev-http.js +71 -0
- package/dist/server-components/dev-http.js.map +1 -0
- package/dist/server-components/error.d.ts +9 -0
- package/dist/server-components/error.d.ts.map +1 -0
- package/dist/server-components/error.js +24 -0
- package/dist/server-components/error.js.map +1 -0
- package/dist/server-components/frames.d.ts +7 -0
- package/dist/server-components/frames.d.ts.map +1 -0
- package/dist/server-components/frames.js +169 -0
- package/dist/server-components/frames.js.map +1 -0
- package/dist/server-components/html-policy.d.ts +6 -0
- package/dist/server-components/html-policy.d.ts.map +1 -0
- package/dist/server-components/html-policy.js +75 -0
- package/dist/server-components/html-policy.js.map +1 -0
- package/dist/server-components/html.d.ts +4 -0
- package/dist/server-components/html.d.ts.map +1 -0
- package/dist/server-components/html.js +67 -0
- package/dist/server-components/html.js.map +1 -0
- package/dist/server-components/islands.d.ts +44 -0
- package/dist/server-components/islands.d.ts.map +1 -0
- package/dist/server-components/islands.js +42 -0
- package/dist/server-components/islands.js.map +1 -0
- package/dist/server-components/native.d.ts +4 -0
- package/dist/server-components/native.d.ts.map +1 -0
- package/dist/server-components/native.js +81 -0
- package/dist/server-components/native.js.map +1 -0
- package/dist/server-components/portal.d.ts +6 -0
- package/dist/server-components/portal.d.ts.map +1 -0
- package/dist/server-components/portal.js +35 -0
- package/dist/server-components/portal.js.map +1 -0
- package/dist/server-components/props.d.ts +3 -0
- package/dist/server-components/props.d.ts.map +1 -0
- package/dist/server-components/props.js +14 -0
- package/dist/server-components/props.js.map +1 -0
- package/dist/server-components/protocol.d.ts +44 -0
- package/dist/server-components/protocol.d.ts.map +1 -0
- package/dist/server-components/protocol.js +139 -0
- package/dist/server-components/protocol.js.map +1 -0
- package/dist/server-components/range.d.ts +24 -0
- package/dist/server-components/range.d.ts.map +1 -0
- package/dist/server-components/range.js +263 -0
- package/dist/server-components/range.js.map +1 -0
- package/dist/server-components/registry.d.ts +6 -0
- package/dist/server-components/registry.d.ts.map +1 -0
- package/dist/server-components/registry.js +30 -0
- package/dist/server-components/registry.js.map +1 -0
- package/dist/server-components/response.d.ts +4 -0
- package/dist/server-components/response.d.ts.map +1 -0
- package/dist/server-components/response.js +32 -0
- package/dist/server-components/response.js.map +1 -0
- package/dist/server-components/router-integration.d.ts +9 -0
- package/dist/server-components/router-integration.d.ts.map +1 -0
- package/dist/server-components/router-integration.js +29 -0
- package/dist/server-components/router-integration.js.map +1 -0
- package/dist/server-components/runtime.d.ts +14 -0
- package/dist/server-components/runtime.d.ts.map +1 -0
- package/dist/server-components/runtime.js +276 -0
- package/dist/server-components/runtime.js.map +1 -0
- package/dist/server-components/scheduler.d.ts +14 -0
- package/dist/server-components/scheduler.d.ts.map +1 -0
- package/dist/server-components/scheduler.js +74 -0
- package/dist/server-components/scheduler.js.map +1 -0
- package/dist/server-components/schema.d.ts +4 -0
- package/dist/server-components/schema.d.ts.map +1 -0
- package/dist/server-components/schema.js +77 -0
- package/dist/server-components/schema.js.map +1 -0
- package/dist/server-components/server-entry.d.ts +12 -0
- package/dist/server-components/server-entry.d.ts.map +1 -0
- package/dist/server-components/server-entry.js +90 -0
- package/dist/server-components/server-entry.js.map +1 -0
- package/dist/server-components/source.d.ts +15 -0
- package/dist/server-components/source.d.ts.map +1 -0
- package/dist/server-components/source.js +269 -0
- package/dist/server-components/source.js.map +1 -0
- package/dist/server-components/state.d.ts +4 -0
- package/dist/server-components/state.d.ts.map +1 -0
- package/dist/server-components/state.js +123 -0
- package/dist/server-components/state.js.map +1 -0
- package/dist/server-components/stream.d.ts +6 -0
- package/dist/server-components/stream.d.ts.map +1 -0
- package/dist/server-components/stream.js +70 -0
- package/dist/server-components/stream.js.map +1 -0
- package/dist/server-components/trusted-html.d.ts +3 -0
- package/dist/server-components/trusted-html.d.ts.map +1 -0
- package/dist/server-components/trusted-html.js +14 -0
- package/dist/server-components/trusted-html.js.map +1 -0
- package/dist/server-components/types.d.ts +107 -0
- package/dist/server-components/types.d.ts.map +1 -0
- package/dist/server-components/types.js +2 -0
- package/dist/server-components/types.js.map +1 -0
- package/dist/server-components/typescript.d.ts +11 -0
- package/dist/server-components/typescript.d.ts.map +1 -0
- package/dist/server-components/typescript.js +28 -0
- package/dist/server-components/typescript.js.map +1 -0
- package/dist/server-components/value.d.ts +5 -0
- package/dist/server-components/value.d.ts.map +1 -0
- package/dist/server-components/value.js +77 -0
- package/dist/server-components/value.js.map +1 -0
- package/dist/server-components/vite.d.ts +12 -0
- package/dist/server-components/vite.d.ts.map +1 -0
- package/dist/server-components/vite.js +197 -0
- package/dist/server-components/vite.js.map +1 -0
- package/dist/server-components.d.ts +5 -0
- package/dist/server-components.d.ts.map +1 -0
- package/dist/server-components.js +4 -0
- package/dist/server-components.js.map +1 -0
- package/dist/service-worker.d.ts +8 -1
- package/dist/service-worker.d.ts.map +1 -1
- package/dist/service-worker.js +20 -6
- package/dist/service-worker.js.map +1 -1
- package/dist/vite.d.ts +12 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +7 -1
- package/dist/vite.js.map +1 -1
- package/dist/zones.d.ts +40 -0
- package/dist/zones.d.ts.map +1 -1
- package/dist/zones.js +170 -6
- package/dist/zones.js.map +1 -1
- package/package.json +97 -4
- package/src/build-vite.ts +31 -9
- package/src/build.ts +109 -31
- package/src/cdn.ts +18 -12
- package/src/client.ts +25 -6
- package/src/deferred.ts +27 -9
- package/src/dev-feed.ts +24 -5
- package/src/dev-session.ts +4 -13
- package/src/dev.ts +29 -1
- package/src/draft.ts +35 -14
- package/src/fonts-google.ts +10 -0
- package/src/index.ts +3 -2
- package/src/internal/codegen.ts +60 -29
- package/src/internal/disposable-dir.ts +24 -0
- package/src/internal/entry-chunks.ts +18 -0
- package/src/internal/evidence-traversal.ts +57 -0
- package/src/internal/head-merge.ts +16 -0
- package/src/internal/js-string.ts +6 -1
- package/src/internal/mount-shadow.ts +1 -1
- package/src/internal/output-guard.ts +88 -7
- package/src/internal/page-execution.ts +506 -108
- package/src/internal/progressive-cookies.ts +60 -0
- package/src/internal/public-env.ts +14 -0
- package/src/internal/render-document.ts +26 -11
- package/src/internal/response-controls.ts +31 -14
- package/src/internal/revive-dates.ts +35 -0
- package/src/internal/route-path.ts +8 -0
- package/src/internal/secret-scan.ts +90 -18
- package/src/internal/server-boundary.ts +29 -5
- package/src/internal/web-app.ts +116 -37
- package/src/internal/wire-date.ts +16 -0
- package/src/internal/zone-graph.ts +59 -19
- package/src/isr.ts +351 -43
- package/src/llms-txt.ts +32 -3
- package/src/manifest.ts +28 -4
- package/src/open-resolved.ts +64 -0
- package/src/plugins/kit.ts +31 -11
- package/src/plugins/vite-leak-guard.ts +5 -1
- package/src/public-dir.ts +27 -8
- package/src/query.ts +107 -26
- package/src/render-seam.ts +2 -0
- package/src/route-types.ts +34 -7
- package/src/router.ts +58 -55
- package/src/server-components/build-info.ts +11 -0
- package/src/server-components/build-target.ts +194 -0
- package/src/server-components/build.ts +419 -0
- package/src/server-components/bundle-proof.ts +33 -0
- package/src/server-components/client.ts +663 -0
- package/src/server-components/definition.ts +125 -0
- package/src/server-components/dev-http.ts +75 -0
- package/src/server-components/error.ts +24 -0
- package/src/server-components/frames.ts +181 -0
- package/src/server-components/html-policy.ts +94 -0
- package/src/server-components/html.ts +81 -0
- package/src/server-components/islands.ts +111 -0
- package/src/server-components/native.ts +101 -0
- package/src/server-components/portal.ts +42 -0
- package/src/server-components/props.ts +19 -0
- package/src/server-components/protocol.ts +167 -0
- package/src/server-components/range.ts +313 -0
- package/src/server-components/registry.ts +34 -0
- package/src/server-components/response.ts +44 -0
- package/src/server-components/router-integration.ts +40 -0
- package/src/server-components/runtime.ts +376 -0
- package/src/server-components/scheduler.ts +84 -0
- package/src/server-components/schema.ts +69 -0
- package/src/server-components/server-entry.ts +98 -0
- package/src/server-components/source.ts +324 -0
- package/src/server-components/state.ts +143 -0
- package/src/server-components/stream.ts +71 -0
- package/src/server-components/trusted-html.ts +21 -0
- package/src/server-components/types.ts +138 -0
- package/src/server-components/typescript.ts +39 -0
- package/src/server-components/value.ts +82 -0
- package/src/server-components/vite.ts +242 -0
- package/src/server-components.ts +32 -0
- package/src/service-worker.ts +24 -7
- package/src/vite.ts +8 -1
- package/src/zones.ts +208 -7
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createRequire } from "node:module"
|
|
2
|
+
import type * as TS from "typescript"
|
|
3
|
+
|
|
4
|
+
/** The code of the error a TypeScript without the in-process compiler API raises here. */
|
|
5
|
+
export const UNSUPPORTED_TYPESCRIPT = "NIFRA_TS_UNSUPPORTED"
|
|
6
|
+
|
|
7
|
+
function isCompiler(value: unknown): value is typeof TS {
|
|
8
|
+
return (
|
|
9
|
+
typeof value === "object" &&
|
|
10
|
+
value !== null &&
|
|
11
|
+
"createSourceFile" in value &&
|
|
12
|
+
typeof value.createSourceFile === "function"
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The TypeScript compiler API, resolved from `from` the way `import "typescript"` there would be.
|
|
18
|
+
* TypeScript 7's package ships no in-process compiler API (its root export is only `version`), so
|
|
19
|
+
* it raises an error that names the fix instead of a TypeError on first use.
|
|
20
|
+
*/
|
|
21
|
+
export function loadTypeScript(from: string = import.meta.url): typeof TS {
|
|
22
|
+
const loaded: unknown = createRequire(from)("typescript")
|
|
23
|
+
if (isCompiler(loaded)) return loaded
|
|
24
|
+
const version =
|
|
25
|
+
typeof loaded === "object" &&
|
|
26
|
+
loaded !== null &&
|
|
27
|
+
"version" in loaded &&
|
|
28
|
+
typeof loaded.version === "string"
|
|
29
|
+
? loaded.version
|
|
30
|
+
: "unknown"
|
|
31
|
+
throw Object.assign(
|
|
32
|
+
new Error(
|
|
33
|
+
`${UNSUPPORTED_TYPESCRIPT}: server components read component modules with the TypeScript compiler API, which TypeScript ${version} does not ship. Pin the project to TypeScript 6 (for example, \`bun add -d typescript@^6\`).`,
|
|
34
|
+
),
|
|
35
|
+
{ code: UNSUPPORTED_TYPESCRIPT, version },
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const ts: typeof TS = loadTypeScript()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ServerComponentError } from "./error.ts"
|
|
2
|
+
import type { ComponentValue } from "./types.ts"
|
|
3
|
+
|
|
4
|
+
/** Property order does not identify a resource; callers supply already-validated DTO inputs. */
|
|
5
|
+
export function componentInputKey(value: ComponentValue): string {
|
|
6
|
+
if (Array.isArray(value)) return `[${value.map(componentInputKey).join(",")}]`
|
|
7
|
+
if (typeof value === "object" && value !== null)
|
|
8
|
+
return `{${Object.keys(value)
|
|
9
|
+
.sort()
|
|
10
|
+
.map((key) => `${JSON.stringify(key)}:${componentInputKey(Reflect.get(value, key))}`)
|
|
11
|
+
.join(",")}}`
|
|
12
|
+
return JSON.stringify(value)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const encoder = new TextEncoder()
|
|
16
|
+
const forbidden = new Set(["__proto__", "prototype", "constructor"])
|
|
17
|
+
|
|
18
|
+
export function componentValue(value: unknown, maxBytes: number = 65536): ComponentValue {
|
|
19
|
+
const seen = new Set<object>()
|
|
20
|
+
let nodes = 0
|
|
21
|
+
let bytes = 0
|
|
22
|
+
const charge = (text: string): void => {
|
|
23
|
+
bytes += encoder.encode(text).byteLength
|
|
24
|
+
if (bytes > maxBytes) throw new ServerComponentError("component_limit", 413)
|
|
25
|
+
}
|
|
26
|
+
const visit = (item: unknown, depth: number): ComponentValue => {
|
|
27
|
+
if (++nodes > 8192 || depth > 16) throw new ServerComponentError("component_limit", 413)
|
|
28
|
+
if (
|
|
29
|
+
item === null ||
|
|
30
|
+
typeof item === "string" ||
|
|
31
|
+
typeof item === "boolean" ||
|
|
32
|
+
(typeof item === "number" && Number.isFinite(item))
|
|
33
|
+
) {
|
|
34
|
+
charge(JSON.stringify(item))
|
|
35
|
+
return item
|
|
36
|
+
}
|
|
37
|
+
if (typeof item !== "object" || item === null || seen.has(item))
|
|
38
|
+
throw new ServerComponentError("component_contract")
|
|
39
|
+
const array = Array.isArray(item)
|
|
40
|
+
const prototype = Object.getPrototypeOf(item)
|
|
41
|
+
if (
|
|
42
|
+
array ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null
|
|
43
|
+
) {
|
|
44
|
+
throw new ServerComponentError("component_contract")
|
|
45
|
+
}
|
|
46
|
+
// Reject custom serializers without invoking them, including inherited serializers.
|
|
47
|
+
if ("toJSON" in item || Object.getOwnPropertySymbols(item).length > 0)
|
|
48
|
+
throw new ServerComponentError("component_contract")
|
|
49
|
+
const descriptors = Object.getOwnPropertyDescriptors(item)
|
|
50
|
+
const names = Object.keys(descriptors)
|
|
51
|
+
if (array && (item.length > 8192 || names.length !== item.length + 1))
|
|
52
|
+
throw new ServerComponentError("component_contract")
|
|
53
|
+
const result: ComponentValue[] | Record<string, ComponentValue> = array
|
|
54
|
+
? []
|
|
55
|
+
: Object.create(null)
|
|
56
|
+
seen.add(item)
|
|
57
|
+
charge(array ? "[]" : "{}")
|
|
58
|
+
let count = 0
|
|
59
|
+
for (const name of names) {
|
|
60
|
+
if (array && name === "length") continue
|
|
61
|
+
const property = descriptors[name]!
|
|
62
|
+
if (
|
|
63
|
+
forbidden.has(name) ||
|
|
64
|
+
!property.enumerable ||
|
|
65
|
+
!Object.hasOwn(property, "value") ||
|
|
66
|
+
(array && (!/^(0|[1-9][0-9]*)$/.test(name) || Number(name) >= item.length))
|
|
67
|
+
) {
|
|
68
|
+
throw new ServerComponentError("component_contract")
|
|
69
|
+
}
|
|
70
|
+
charge((count++ === 0 ? "" : ",") + (array ? "" : `${JSON.stringify(name)}:`))
|
|
71
|
+
Object.defineProperty(result, name, {
|
|
72
|
+
value: visit(property.value, depth + 1),
|
|
73
|
+
enumerable: true,
|
|
74
|
+
writable: true,
|
|
75
|
+
configurable: true,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
seen.delete(item)
|
|
79
|
+
return result
|
|
80
|
+
}
|
|
81
|
+
return visit(value, 0)
|
|
82
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
2
|
+
import { createRequire } from "node:module"
|
|
3
|
+
import { resolve } from "node:path"
|
|
4
|
+
import type * as TS from "typescript"
|
|
5
|
+
import { type Plugin, version as viteVersion } from "vite"
|
|
6
|
+
import {
|
|
7
|
+
compileComponentModule,
|
|
8
|
+
componentReference,
|
|
9
|
+
directive,
|
|
10
|
+
exportedValues,
|
|
11
|
+
guardCreateElementCalls,
|
|
12
|
+
sourceFile,
|
|
13
|
+
} from "./source.ts"
|
|
14
|
+
import { ts } from "./typescript.ts"
|
|
15
|
+
|
|
16
|
+
const componentFile = /\.component\.server\.[cm]?[jt]sx?$/
|
|
17
|
+
const islandFile = /\.island\.[cm]?[jt]sx?$/
|
|
18
|
+
const referencePrefix = "\0nifra-component-reference:"
|
|
19
|
+
const nativeQuery = "nifra-native-client-reference"
|
|
20
|
+
const reactRuntime = "\0nifra-component-react-runtime"
|
|
21
|
+
// Vite uses forward slashes for module IDs even when the filesystem uses backslashes.
|
|
22
|
+
const bare = (id: string): string => (id.split("?")[0] ?? id).replaceAll("\\", "/")
|
|
23
|
+
|
|
24
|
+
export interface ServerComponentsPluginOptions {
|
|
25
|
+
readonly root: string
|
|
26
|
+
readonly adapter: "react" | "vue" | "svelte" | "solid" | "preact"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function nativeFacade(source: string, file: string): string {
|
|
30
|
+
const prefix = file.replace(/\.[cm]?[jt]sx?$/, ".props.")
|
|
31
|
+
const extensions = /\.[cm]?jsx?$/.test(file)
|
|
32
|
+
? ["js", "mjs", "cjs", "ts"]
|
|
33
|
+
: ["ts", "mts", "cts", "js"]
|
|
34
|
+
const companion =
|
|
35
|
+
extensions.map((extension) => prefix + extension).find(existsSync) ?? prefix + extensions[0]
|
|
36
|
+
if (!existsSync(companion))
|
|
37
|
+
throw new Error(
|
|
38
|
+
`[nifra/components] ${file} requires ${companion}: export a closed props schema for every native client component`,
|
|
39
|
+
)
|
|
40
|
+
const schemas = sourceFile(readFileSync(companion, "utf8"), companion)
|
|
41
|
+
const registered = new Set(exportedValues(schemas))
|
|
42
|
+
const slots = new Map<string, readonly string[]>()
|
|
43
|
+
for (const statement of schemas.statements) {
|
|
44
|
+
if (!ts.isVariableStatement(statement)) continue
|
|
45
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
46
|
+
if (!ts.isIdentifier(declaration.name) || !declaration.name.text.endsWith("Slots")) continue
|
|
47
|
+
let value = declaration.initializer
|
|
48
|
+
if (value !== undefined && ts.isAsExpression(value)) value = value.expression
|
|
49
|
+
if (
|
|
50
|
+
value === undefined ||
|
|
51
|
+
!ts.isArrayLiteralExpression(value) ||
|
|
52
|
+
!value.elements.every(ts.isStringLiteral)
|
|
53
|
+
)
|
|
54
|
+
throw new Error("[nifra/components] Managed slot names must be a literal array")
|
|
55
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The compiler inspects trusted AST/package metadata and its own populated stub map; application data never supplies these values.
|
|
56
|
+
const names = value.elements.map((node) => (node as TS.StringLiteral).text)
|
|
57
|
+
if (
|
|
58
|
+
names.some(
|
|
59
|
+
(name) =>
|
|
60
|
+
!/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(name) ||
|
|
61
|
+
name === "ref" ||
|
|
62
|
+
name === "key" ||
|
|
63
|
+
name === "constructor",
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
throw new Error("[nifra/components] Invalid managed slot name")
|
|
67
|
+
slots.set(declaration.name.text.slice(0, -5), names)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const names = exportedValues(sourceFile(source, file))
|
|
71
|
+
const exports = names.map((name, index) => {
|
|
72
|
+
if (!registered.has(name))
|
|
73
|
+
throw new Error(
|
|
74
|
+
`[nifra/components] Native client export ${name} in ${file} has no registered props schema`,
|
|
75
|
+
)
|
|
76
|
+
if (name !== "default" && !/^[$A-Z_a-z][$\w]*$/.test(name))
|
|
77
|
+
throw new Error("[nifra/components] Native client export names must be identifiers")
|
|
78
|
+
const local = `__nifra_client_${index}`
|
|
79
|
+
const value = `__guard(__native[${JSON.stringify(name)}], __schemas[${JSON.stringify(name)}], ${JSON.stringify(slots.get(name) ?? [])})`
|
|
80
|
+
return name === "default"
|
|
81
|
+
? `const ${local} = ${value}; export default ${local};`
|
|
82
|
+
: `export const ${name} = ${value};`
|
|
83
|
+
})
|
|
84
|
+
return [
|
|
85
|
+
'import { guardedClientReference as __guard } from "@nifrajs/web-react/server-components/guard";',
|
|
86
|
+
`import * as __native from ${JSON.stringify(`${file}?${nativeQuery}`)};`,
|
|
87
|
+
`import * as __schemas from ${JSON.stringify(companion)};`,
|
|
88
|
+
...exports,
|
|
89
|
+
].join("\n")
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Compiler bridge. The ordinary build must continue rejecting arbitrary server imports. */
|
|
93
|
+
export function serverComponentsPlugin(
|
|
94
|
+
options: ServerComponentsPluginOptions,
|
|
95
|
+
): Plugin & { readonly api: { readonly componentModules: ReadonlySet<string> } } {
|
|
96
|
+
const stubs = new Map<string, string>()
|
|
97
|
+
const internal = new Set<string>()
|
|
98
|
+
const nativeReferences = new Set<string>()
|
|
99
|
+
const componentModules = new Set<string>()
|
|
100
|
+
return {
|
|
101
|
+
api: { componentModules },
|
|
102
|
+
name: "nifra:server-components",
|
|
103
|
+
enforce: "pre",
|
|
104
|
+
configResolved(config) {
|
|
105
|
+
if (viteVersion !== "8.2.1")
|
|
106
|
+
throw new Error(
|
|
107
|
+
"[nifra/components] Use the certified Vite 8.2.1 component pipeline; Bun remains a supported server runtime",
|
|
108
|
+
)
|
|
109
|
+
if (options.adapter === "react") {
|
|
110
|
+
const require = createRequire(resolve(config.root, "package.json"))
|
|
111
|
+
const versions = ["react", "react-dom", "react-server-dom-webpack"].map((name) => {
|
|
112
|
+
try {
|
|
113
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The compiler inspects trusted AST/package metadata and its own populated stub map; application data never supplies these values.
|
|
114
|
+
return (require(`${name}/package.json`) as { version: string }).version
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`[nifra/components] Install ${name}@19.2.8 for the React component pipeline`,
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
if (versions.some((version) => version !== "19.2.8"))
|
|
122
|
+
throw new Error(
|
|
123
|
+
"[nifra/components] React, React DOM, and Flight must all use the matching 19.2.8 version",
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
async resolveId(source, importer) {
|
|
128
|
+
const environment = this.environment.name
|
|
129
|
+
if (source === "react" && environment === "rsc" && !internal.has(bare(importer ?? ""))) {
|
|
130
|
+
internal.add(reactRuntime)
|
|
131
|
+
const guard = await this.resolve("@nifrajs/web-react/server-components/guard", importer, {
|
|
132
|
+
skipSelf: true,
|
|
133
|
+
})
|
|
134
|
+
if (guard !== null) internal.add(bare(guard.id))
|
|
135
|
+
return reactRuntime
|
|
136
|
+
}
|
|
137
|
+
if (source.startsWith("\0virtual:vite-rsc/") && environment !== "rsc") return null
|
|
138
|
+
if (source.startsWith("@nifrajs/web-react/server-components/")) {
|
|
139
|
+
const resolved = await this.resolve(source, importer, { skipSelf: true })
|
|
140
|
+
if (resolved !== null) internal.add(bare(resolved.id))
|
|
141
|
+
return resolved
|
|
142
|
+
}
|
|
143
|
+
if (source.includes(nativeQuery)) {
|
|
144
|
+
const file = source.startsWith("/@fs/")
|
|
145
|
+
? source.slice("/@fs".length).replace(/^\/(?=[A-Za-z]:[\\/])/, "")
|
|
146
|
+
: existsSync(bare(source))
|
|
147
|
+
? source
|
|
148
|
+
: resolve(options.root, `.${source}`)
|
|
149
|
+
if (
|
|
150
|
+
!nativeReferences.has(bare(file)) ||
|
|
151
|
+
(environment === "rsc" && (importer === undefined || bare(importer) !== bare(file)))
|
|
152
|
+
)
|
|
153
|
+
throw new Error(
|
|
154
|
+
"[nifra/components] Raw native client references are compiler-owned; import the registered client component",
|
|
155
|
+
)
|
|
156
|
+
return file
|
|
157
|
+
}
|
|
158
|
+
if (source.startsWith(referencePrefix) || source.startsWith("\0")) return null
|
|
159
|
+
if (
|
|
160
|
+
environment === "rsc" &&
|
|
161
|
+
options.adapter === "react" &&
|
|
162
|
+
(source === "react/jsx-runtime" || source === "react/jsx-dev-runtime") &&
|
|
163
|
+
!internal.has(bare(importer ?? ""))
|
|
164
|
+
) {
|
|
165
|
+
const resolved = await this.resolve(
|
|
166
|
+
`@nifrajs/web-react/server-components/${source.endsWith("dev-runtime") ? "jsx-dev-runtime" : "jsx-runtime"}`,
|
|
167
|
+
importer,
|
|
168
|
+
{ skipSelf: true },
|
|
169
|
+
)
|
|
170
|
+
if (resolved === null)
|
|
171
|
+
throw new Error("[nifra/components] Install the matching @nifrajs/web-react adapter")
|
|
172
|
+
internal.add(bare(resolved.id))
|
|
173
|
+
const guard = await this.resolve("@nifrajs/web-react/server-components/guard", importer, {
|
|
174
|
+
skipSelf: true,
|
|
175
|
+
})
|
|
176
|
+
if (guard !== null) internal.add(bare(guard.id))
|
|
177
|
+
return resolved
|
|
178
|
+
}
|
|
179
|
+
if (environment !== "client") return null
|
|
180
|
+
const resolved = await this.resolve(source, importer, { skipSelf: true })
|
|
181
|
+
if (resolved === null || !componentFile.test(bare(resolved.id))) return null
|
|
182
|
+
if (resolved.id !== bare(resolved.id))
|
|
183
|
+
throw new Error("[nifra/components] Server component source cannot be imported as an asset")
|
|
184
|
+
const compiled = compileComponentModule(
|
|
185
|
+
readFileSync(resolved.id, "utf8"),
|
|
186
|
+
resolved.id,
|
|
187
|
+
options.root,
|
|
188
|
+
"client",
|
|
189
|
+
)
|
|
190
|
+
const id = referencePrefix + componentReference(resolved.id, options.root, "module")
|
|
191
|
+
stubs.set(id, compiled.code)
|
|
192
|
+
return id
|
|
193
|
+
},
|
|
194
|
+
load(id) {
|
|
195
|
+
if (id === reactRuntime)
|
|
196
|
+
return {
|
|
197
|
+
code: 'import * as Native from "react"; import { guardedCreateElement as createElement, guardedCloneElement as cloneElement } from "@nifrajs/web-react/server-components/guard"; export { Children, Fragment, Profiler, StrictMode, Suspense, __SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, cache, cacheSignal, captureOwnerStack, createRef, forwardRef, isValidElement, lazy, memo, use, useCallback, useDebugValue, useId, useMemo, version } from "react"; export { createElement, cloneElement }; export default { ...Native, createElement, cloneElement };',
|
|
198
|
+
map: null,
|
|
199
|
+
}
|
|
200
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The compiler inspects trusted AST/package metadata and its own populated stub map; application data never supplies these values.
|
|
201
|
+
if (stubs.has(id)) return { code: stubs.get(id) as string, map: null }
|
|
202
|
+
const path = bare(id)
|
|
203
|
+
if (id.endsWith(`?${nativeQuery}`)) return { code: readFileSync(path, "utf8"), map: null }
|
|
204
|
+
if (!/\.[cm]?[jt]sx?$/.test(path) || !existsSync(path)) return null
|
|
205
|
+
const source = readFileSync(path, "utf8")
|
|
206
|
+
const ast = sourceFile(source, path)
|
|
207
|
+
if (directive(ast, "use server"))
|
|
208
|
+
throw new Error(
|
|
209
|
+
`[nifra/components] Native use-server actions in ${path} are unsupported; use a validated serverFn in a *.fn.ts module`,
|
|
210
|
+
)
|
|
211
|
+
if (
|
|
212
|
+
this.environment.name === "rsc" &&
|
|
213
|
+
options.adapter === "react" &&
|
|
214
|
+
directive(ast, "use client")
|
|
215
|
+
) {
|
|
216
|
+
nativeReferences.add(path)
|
|
217
|
+
return { code: nativeFacade(source, path), map: null }
|
|
218
|
+
}
|
|
219
|
+
return null
|
|
220
|
+
},
|
|
221
|
+
transform(source, id) {
|
|
222
|
+
if (id.includes(nativeQuery) || internal.has(bare(id))) return null
|
|
223
|
+
const path = bare(id)
|
|
224
|
+
let code = source
|
|
225
|
+
if (componentFile.test(path)) {
|
|
226
|
+
code = compileComponentModule(source, path, options.root, this.environment.name).code
|
|
227
|
+
componentModules.add(path)
|
|
228
|
+
}
|
|
229
|
+
if (islandFile.test(path))
|
|
230
|
+
code = compileComponentModule(
|
|
231
|
+
source,
|
|
232
|
+
path,
|
|
233
|
+
options.root,
|
|
234
|
+
this.environment.name,
|
|
235
|
+
"island",
|
|
236
|
+
).code
|
|
237
|
+
if (this.environment.name === "rsc" && options.adapter === "react")
|
|
238
|
+
code = guardCreateElementCalls(code, path)
|
|
239
|
+
return code === source ? null : { code, map: null }
|
|
240
|
+
},
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export {
|
|
2
|
+
defineServerComponent,
|
|
3
|
+
inheritOwnerAuthorization,
|
|
4
|
+
isServerComponent,
|
|
5
|
+
prepareServerComponent,
|
|
6
|
+
} from "./server-components/definition.ts"
|
|
7
|
+
export { type ComponentErrorCode, ServerComponentError } from "./server-components/error.ts"
|
|
8
|
+
export {
|
|
9
|
+
createServerComponents,
|
|
10
|
+
defineComponentOwner,
|
|
11
|
+
type ServerComponentsOptions,
|
|
12
|
+
serverComponentIdentity,
|
|
13
|
+
serverComponentInstance,
|
|
14
|
+
} from "./server-components/runtime.ts"
|
|
15
|
+
export type {
|
|
16
|
+
ComponentInstance,
|
|
17
|
+
ComponentIsland,
|
|
18
|
+
ComponentKey,
|
|
19
|
+
ComponentOwner,
|
|
20
|
+
ComponentRecord,
|
|
21
|
+
ComponentRender,
|
|
22
|
+
ComponentRenderContext,
|
|
23
|
+
ComponentState,
|
|
24
|
+
ComponentValue,
|
|
25
|
+
PreparedServerComponent,
|
|
26
|
+
ServerComponent,
|
|
27
|
+
ServerComponentContext,
|
|
28
|
+
ServerComponentDefinition,
|
|
29
|
+
ServerComponentHandle,
|
|
30
|
+
ServerComponentRenderAdapter,
|
|
31
|
+
ServerComponentRuntime,
|
|
32
|
+
} from "./server-components/types.ts"
|
package/src/service-worker.ts
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
* - **GET, same-origin, `ok`, and not `no-store`.** Anything else goes straight to the network.
|
|
14
14
|
* - **The cache name carries the build id.** A deploy that changed the assets gets a new cache, and
|
|
15
15
|
* activation deletes every older one, so a stale worker cannot pin an old build indefinitely.
|
|
16
|
+
* Only caches named `<cacheName>:<buildId>` are the worker's: the origin's other caches - another
|
|
17
|
+
* app's, or data the page stored itself - are never read, written or deleted.
|
|
18
|
+
* - **Only this build's precached URLs are answered.** Every other request, an API call included,
|
|
19
|
+
* goes to the network untouched.
|
|
16
20
|
*
|
|
17
21
|
* It is opt-in and generated at build time; an app that does not call this ships nothing.
|
|
18
22
|
*/
|
|
@@ -36,7 +40,10 @@ export interface ServiceWorkerOptions {
|
|
|
36
40
|
* bytes. Omit it and failed navigations simply fail, which is the honest default.
|
|
37
41
|
*/
|
|
38
42
|
readonly offlineUrl?: string
|
|
39
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Cache name prefix, and the namespace activation cleans: every cache named `<cacheName>:<id>` other
|
|
45
|
+
* than this build's is deleted. Give each worker sharing an origin its own. Default `nifra`.
|
|
46
|
+
*/
|
|
40
47
|
readonly cacheName?: string
|
|
41
48
|
/** Extra same-origin URLs to precache. Only pass immutable ones. */
|
|
42
49
|
readonly additionalPrecache?: readonly string[]
|
|
@@ -101,8 +108,11 @@ export function generateServiceWorker(
|
|
|
101
108
|
const urls = [...new Set(offline === undefined ? precache : [...precache, offline])].sort()
|
|
102
109
|
|
|
103
110
|
return `// Generated by @nifrajs/web/service-worker. Do not edit.
|
|
104
|
-
const
|
|
111
|
+
const OWNED = ${JSON.stringify(`${prefix}:`)}
|
|
112
|
+
const CACHE = OWNED + ${JSON.stringify(options.buildId)}
|
|
105
113
|
const PRECACHE = ${JSON.stringify(urls)}
|
|
114
|
+
const OWN_URLS = new Set(PRECACHE)
|
|
115
|
+
const OWN = { cacheName: CACHE }
|
|
106
116
|
const OFFLINE = ${offline === undefined ? "null" : JSON.stringify(offline)}
|
|
107
117
|
|
|
108
118
|
self.addEventListener("install", (event) => {
|
|
@@ -115,7 +125,9 @@ self.addEventListener("activate", (event) => {
|
|
|
115
125
|
event.waitUntil(
|
|
116
126
|
caches
|
|
117
127
|
.keys()
|
|
118
|
-
|
|
128
|
+
// Neither the prefix nor a build id can hold a colon, so the first one ends the namespace.
|
|
129
|
+
.then((keys) => keys.filter((k) => k !== CACHE && k.startsWith(OWNED)))
|
|
130
|
+
.then((old) => Promise.all(old.map((k) => caches.delete(k))))
|
|
119
131
|
.then(() => self.clients.claim()),
|
|
120
132
|
)
|
|
121
133
|
})
|
|
@@ -130,20 +142,25 @@ self.addEventListener("fetch", (event) => {
|
|
|
130
142
|
// how one user gets served the page rendered for another, so nothing is stored here.
|
|
131
143
|
if (request.mode === "navigate") {
|
|
132
144
|
if (OFFLINE === null) return
|
|
133
|
-
event.respondWith(
|
|
145
|
+
event.respondWith(
|
|
146
|
+
fetch(request).catch(() => caches.match(OFFLINE, OWN).then((r) => r ?? Response.error())),
|
|
147
|
+
)
|
|
134
148
|
return
|
|
135
149
|
}
|
|
136
150
|
|
|
137
|
-
// Assets: cache first, because every precached URL is content-hashed and therefore immutable.
|
|
151
|
+
// Assets: cache first, because every precached URL is content-hashed and therefore immutable. Only
|
|
152
|
+
// this build's URLs are answered, and only from this build's cache: every other request, an API
|
|
153
|
+
// call included, goes to the network, and another cache on the origin is never read.
|
|
154
|
+
if (!OWN_URLS.has(url.pathname)) return
|
|
138
155
|
event.respondWith(
|
|
139
|
-
caches.match(request).then((hit) => {
|
|
156
|
+
caches.match(request, OWN).then((hit) => {
|
|
140
157
|
if (hit !== undefined) return hit
|
|
141
158
|
return fetch(request).then((response) => {
|
|
142
159
|
const cacheable =
|
|
143
160
|
response.ok &&
|
|
144
161
|
response.type === "basic" &&
|
|
145
162
|
!(response.headers.get("cache-control") ?? "").includes("no-store")
|
|
146
|
-
if (cacheable
|
|
163
|
+
if (cacheable) {
|
|
147
164
|
const copy = response.clone()
|
|
148
165
|
void caches.open(CACHE).then((c) => c.put(request, copy))
|
|
149
166
|
}
|
package/src/vite.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* injects its HMR client + the framework's refresh preamble. Node `http` (not `Bun.serve`) because
|
|
11
11
|
* Vite's `middlewares` are Connect-style - it runs fine under Bun.
|
|
12
12
|
*/
|
|
13
|
+
|
|
13
14
|
import { type Dirent, readdirSync, writeFileSync } from "node:fs"
|
|
14
15
|
import {
|
|
15
16
|
createServer as createHttpServer,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
type ServerResponse,
|
|
18
19
|
} from "node:http"
|
|
19
20
|
import { dirname, isAbsolute, join, relative, resolve as resolvePath, sep } from "node:path"
|
|
21
|
+
import { singleCopyPackageNames } from "@nifrajs/core/single-copy"
|
|
20
22
|
import { CLIENT_BATCH_MAX_BYTES } from "./dev-client.ts"
|
|
21
23
|
import { DEV_REQUEST_ID_HEADER, DEV_SERVER_FILES } from "./dev-feed.ts"
|
|
22
24
|
import { listenOrExplain } from "./dev-port.ts"
|
|
@@ -632,6 +634,10 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
632
634
|
// Ahead of the user's plugins: the zone guard refuses backend code before anything serves or
|
|
633
635
|
// transforms it, and a `*.fn` module must be replaced before anything else reads it.
|
|
634
636
|
plugins: [zoneGuard, viteServerFnStub(), ...plugins],
|
|
637
|
+
// Vite pre-bundles what it finds by crawling `index.html`, and this app has none: every dependency
|
|
638
|
+
// would be found mid-session instead, each one re-optimizing and reloading the page. The client
|
|
639
|
+
// entry imports every route's frontend module, so crawling it covers the whole route graph.
|
|
640
|
+
optimizeDeps: { entries: [DEV_ENTRY] },
|
|
635
641
|
resolve: {
|
|
636
642
|
conditions: resolveConditions,
|
|
637
643
|
// Dedupe each framework runtime to ONE copy. In a multi-root workspace a shared package can pull
|
|
@@ -640,7 +646,8 @@ export async function createViteDevServer(options: ViteDevServerOptions): Promis
|
|
|
640
646
|
// on any hook-using route (the error points at the component, not the resolution - brutal to
|
|
641
647
|
// diagnose). Same policy table the production builds read, so dev matches prod. No-op per
|
|
642
648
|
// framework the app does not use (the package simply isn't present to dedupe).
|
|
643
|
-
|
|
649
|
+
// The app's single-copy declaration pins its packages the same way.
|
|
650
|
+
dedupe: [...viteDedupePackages(), ...singleCopyPackageNames(root)],
|
|
644
651
|
},
|
|
645
652
|
ssr: {
|
|
646
653
|
// Explicit listing forces external even for workspace-LINKED packages (Vite's default keeps
|