@nifrajs/web 4.0.2 → 5.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 +19 -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 +6 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +46 -18
- 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-port.d.ts +3 -2
- package/dist/dev-port.d.ts.map +1 -1
- package/dist/dev-port.js +2 -6
- package/dist/dev-port.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 +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- 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/package-entries.d.ts +34 -0
- package/dist/internal/package-entries.d.ts.map +1 -0
- package/dist/internal/package-entries.js +324 -0
- package/dist/internal/package-entries.js.map +1 -0
- 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 +437 -114
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/parity.d.ts.map +1 -1
- package/dist/internal/parity.js +15 -2
- package/dist/internal/parity.js.map +1 -1
- package/dist/internal/private-env.d.ts +8 -0
- package/dist/internal/private-env.d.ts.map +1 -1
- package/dist/internal/private-env.js +25 -10
- package/dist/internal/private-env.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 +5 -44
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +51 -63
- 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 +14 -0
- package/dist/internal/route-path.d.ts.map +1 -0
- package/dist/internal/route-path.js +19 -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 +190 -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 +25 -18
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +81 -24
- 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/without-query.d.ts +4 -0
- package/dist/internal/without-query.d.ts.map +1 -0
- package/dist/internal/without-query.js +9 -0
- package/dist/internal/without-query.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 +71 -20
- package/dist/internal/zone-graph.js.map +1 -1
- package/dist/isr.d.ts +59 -3
- package/dist/isr.d.ts.map +1 -1
- package/dist/isr.js +311 -41
- 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 +37 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +4 -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 +9 -1
- package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
- package/dist/plugins/vite-leak-guard.js +84 -7
- package/dist/plugins/vite-leak-guard.js.map +1 -1
- package/dist/plugins/vite-zone-guard.d.ts.map +1 -1
- package/dist/plugins/vite-zone-guard.js +17 -21
- package/dist/plugins/vite-zone-guard.js.map +1 -1
- package/dist/plugins/zone-guard.d.ts.map +1 -1
- package/dist/plugins/zone-guard.js +44 -3
- package/dist/plugins/zone-guard.js.map +1 -1
- package/dist/prerender.d.ts +5 -1
- package/dist/prerender.d.ts.map +1 -1
- package/dist/prerender.js +41 -19
- package/dist/prerender.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 +25 -2
- 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 +47 -50
- package/dist/router.js.map +1 -1
- package/dist/seo.d.ts +49 -0
- package/dist/seo.d.ts.map +1 -0
- package/dist/seo.js +48 -0
- package/dist/seo.js.map +1 -0
- 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 +64 -2
- package/dist/zones.d.ts.map +1 -1
- package/dist/zones.js +331 -28
- package/dist/zones.js.map +1 -1
- package/package.json +102 -4
- package/src/build-vite.ts +31 -9
- package/src/build.ts +109 -31
- package/src/cdn.ts +18 -12
- package/src/client.ts +48 -17
- package/src/deferred.ts +27 -9
- package/src/dev-feed.ts +24 -5
- package/src/dev-port.ts +4 -10
- 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 +5 -6
- 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/package-entries.ts +331 -0
- package/src/internal/page-execution.ts +573 -114
- package/src/internal/parity.ts +15 -2
- package/src/internal/private-env.ts +27 -13
- package/src/internal/progressive-cookies.ts +60 -0
- package/src/internal/public-env.ts +14 -0
- package/src/internal/render-document.ts +66 -89
- package/src/internal/response-controls.ts +31 -14
- package/src/internal/revive-dates.ts +35 -0
- package/src/internal/route-path.ts +24 -0
- package/src/internal/secret-scan.ts +190 -18
- package/src/internal/server-boundary.ts +29 -5
- package/src/internal/web-app.ts +126 -42
- package/src/internal/wire-date.ts +16 -0
- package/src/internal/without-query.ts +8 -0
- package/src/internal/zone-graph.ts +78 -25
- package/src/isr.ts +364 -45
- package/src/llms-txt.ts +32 -3
- package/src/manifest.ts +38 -4
- package/src/open-resolved.ts +64 -0
- package/src/plugins/kit.ts +31 -11
- package/src/plugins/vite-leak-guard.ts +104 -8
- package/src/plugins/vite-zone-guard.ts +21 -19
- package/src/plugins/zone-guard.ts +41 -2
- package/src/prerender.ts +39 -18
- package/src/public-dir.ts +27 -8
- package/src/query.ts +107 -26
- package/src/render-seam.ts +30 -2
- package/src/route-types.ts +34 -7
- package/src/router.ts +66 -59
- package/src/seo.ts +68 -0
- 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 +418 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nifrajs/web",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Framework-agnostic SSR core for nifra - the render seam + HTML document orchestration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"types": "./dist/client.d.ts",
|
|
43
43
|
"default": "./dist/client.js"
|
|
44
44
|
},
|
|
45
|
+
"./seo": {
|
|
46
|
+
"bun": "./src/seo.ts",
|
|
47
|
+
"types": "./dist/seo.d.ts",
|
|
48
|
+
"default": "./dist/seo.js"
|
|
49
|
+
},
|
|
45
50
|
"./vitals": {
|
|
46
51
|
"bun": "./src/vitals.ts",
|
|
47
52
|
"types": "./dist/vitals.d.ts",
|
|
@@ -227,6 +232,76 @@
|
|
|
227
232
|
"bun": "./src/internal/matches-runtime.ts",
|
|
228
233
|
"types": "./dist/internal/matches-runtime.d.ts",
|
|
229
234
|
"default": "./dist/internal/matches-runtime.js"
|
|
235
|
+
},
|
|
236
|
+
"./server-components": {
|
|
237
|
+
"bun": "./src/server-components.ts",
|
|
238
|
+
"types": "./dist/server-components.d.ts",
|
|
239
|
+
"default": "./dist/server-components.js"
|
|
240
|
+
},
|
|
241
|
+
"./server-components/client": {
|
|
242
|
+
"bun": "./src/server-components/client.ts",
|
|
243
|
+
"types": "./dist/server-components/client.d.ts",
|
|
244
|
+
"default": "./dist/server-components/client.js"
|
|
245
|
+
},
|
|
246
|
+
"./server-components/vite": {
|
|
247
|
+
"bun": "./src/server-components/vite.ts",
|
|
248
|
+
"types": "./dist/server-components/vite.d.ts",
|
|
249
|
+
"default": "./dist/server-components/vite.js"
|
|
250
|
+
},
|
|
251
|
+
"./server-components/build": {
|
|
252
|
+
"bun": "./src/server-components/build.ts",
|
|
253
|
+
"types": "./dist/server-components/build.d.ts",
|
|
254
|
+
"default": "./dist/server-components/build.js"
|
|
255
|
+
},
|
|
256
|
+
"./server-components/source": {
|
|
257
|
+
"bun": "./src/server-components/source.ts",
|
|
258
|
+
"types": "./dist/server-components/source.d.ts",
|
|
259
|
+
"default": "./dist/server-components/source.js"
|
|
260
|
+
},
|
|
261
|
+
"./server-components/props": {
|
|
262
|
+
"bun": "./src/server-components/props.ts",
|
|
263
|
+
"types": "./dist/server-components/props.d.ts",
|
|
264
|
+
"default": "./dist/server-components/props.js"
|
|
265
|
+
},
|
|
266
|
+
"./server-components/stream": {
|
|
267
|
+
"bun": "./src/server-components/stream.ts",
|
|
268
|
+
"types": "./dist/server-components/stream.d.ts",
|
|
269
|
+
"default": "./dist/server-components/stream.js"
|
|
270
|
+
},
|
|
271
|
+
"./server-components/state": {
|
|
272
|
+
"bun": "./src/server-components/state.ts",
|
|
273
|
+
"types": "./dist/server-components/state.d.ts",
|
|
274
|
+
"default": "./dist/server-components/state.js"
|
|
275
|
+
},
|
|
276
|
+
"./server-components/native": {
|
|
277
|
+
"bun": "./src/server-components/native.ts",
|
|
278
|
+
"types": "./dist/server-components/native.d.ts",
|
|
279
|
+
"default": "./dist/server-components/native.js"
|
|
280
|
+
},
|
|
281
|
+
"./server-components/islands": {
|
|
282
|
+
"bun": "./src/server-components/islands.ts",
|
|
283
|
+
"types": "./dist/server-components/islands.d.ts",
|
|
284
|
+
"default": "./dist/server-components/islands.js"
|
|
285
|
+
},
|
|
286
|
+
"./server-components/range": {
|
|
287
|
+
"bun": "./src/server-components/range.ts",
|
|
288
|
+
"types": "./dist/server-components/range.d.ts",
|
|
289
|
+
"default": "./dist/server-components/range.js"
|
|
290
|
+
},
|
|
291
|
+
"./server-components/build-info": {
|
|
292
|
+
"bun": "./src/server-components/build-info.ts",
|
|
293
|
+
"types": "./dist/server-components/build-info.d.ts",
|
|
294
|
+
"default": "./dist/server-components/build-info.js"
|
|
295
|
+
},
|
|
296
|
+
"./server-components/portal": {
|
|
297
|
+
"bun": "./src/server-components/portal.ts",
|
|
298
|
+
"types": "./dist/server-components/portal.d.ts",
|
|
299
|
+
"default": "./dist/server-components/portal.js"
|
|
300
|
+
},
|
|
301
|
+
"./server-components/trusted-html": {
|
|
302
|
+
"bun": "./src/server-components/trusted-html.ts",
|
|
303
|
+
"types": "./dist/server-components/trusted-html.d.ts",
|
|
304
|
+
"default": "./dist/server-components/trusted-html.js"
|
|
230
305
|
}
|
|
231
306
|
},
|
|
232
307
|
"files": [
|
|
@@ -244,8 +319,9 @@
|
|
|
244
319
|
"access": "public"
|
|
245
320
|
},
|
|
246
321
|
"dependencies": {
|
|
247
|
-
"@nifrajs/core": "
|
|
248
|
-
"@nifrajs/island-trigger": "
|
|
322
|
+
"@nifrajs/core": "5.1.0",
|
|
323
|
+
"@nifrajs/island-trigger": "5.1.0",
|
|
324
|
+
"parse5": "8.0.1"
|
|
249
325
|
},
|
|
250
326
|
"peerDependencies": {
|
|
251
327
|
"@babel/core": "^7.26.0",
|
|
@@ -255,7 +331,9 @@
|
|
|
255
331
|
"@stylexjs/babel-plugin": "^0.19.0",
|
|
256
332
|
"sass": "^1.0.0",
|
|
257
333
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
|
258
|
-
"web-vitals": "^6.0.0"
|
|
334
|
+
"web-vitals": "^6.0.0",
|
|
335
|
+
"typescript": "^5.9.0 || ^6.0.0",
|
|
336
|
+
"@vitejs/plugin-rsc": "0.5.35"
|
|
259
337
|
},
|
|
260
338
|
"peerDependenciesMeta": {
|
|
261
339
|
"@babel/core": {
|
|
@@ -281,6 +359,12 @@
|
|
|
281
359
|
},
|
|
282
360
|
"web-vitals": {
|
|
283
361
|
"optional": true
|
|
362
|
+
},
|
|
363
|
+
"typescript": {
|
|
364
|
+
"optional": true
|
|
365
|
+
},
|
|
366
|
+
"@vitejs/plugin-rsc": {
|
|
367
|
+
"optional": true
|
|
284
368
|
}
|
|
285
369
|
},
|
|
286
370
|
"devDependencies": {
|
|
@@ -292,10 +376,24 @@
|
|
|
292
376
|
"@nifrajs/schema": "workspace:*",
|
|
293
377
|
"@nifrajs/test-utils": "workspace:*",
|
|
294
378
|
"@nifrajs/web-react": "workspace:*",
|
|
379
|
+
"@preact/preset-vite": "2.10.5",
|
|
295
380
|
"@stylexjs/babel-plugin": "^0.19.0",
|
|
296
381
|
"@stylexjs/stylex": "^0.19.0",
|
|
382
|
+
"@sveltejs/vite-plugin-svelte": "7.3.1",
|
|
383
|
+
"@types/react": "19.2.17",
|
|
384
|
+
"@vitejs/plugin-rsc": "0.5.35",
|
|
385
|
+
"@vitejs/plugin-vue": "6.0.9",
|
|
386
|
+
"playwright": "1.63.0",
|
|
387
|
+
"preact": "10.29.8",
|
|
388
|
+
"preact-render-to-string": "6.7.0",
|
|
297
389
|
"sass": "^1.77.0",
|
|
390
|
+
"solid-js": "1.9.14",
|
|
391
|
+
"svelte": "5.56.8",
|
|
392
|
+
"svelte-check": "4.7.6",
|
|
298
393
|
"vite": "^8.2.1",
|
|
394
|
+
"vite-plugin-solid": "2.11.14",
|
|
395
|
+
"vue": "3.5.40",
|
|
396
|
+
"vue-tsc": "3.3.12",
|
|
299
397
|
"web-vitals": "^6.2.2"
|
|
300
398
|
},
|
|
301
399
|
"repository": {
|
package/src/build-vite.ts
CHANGED
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
* error the Bun build raises. A second production pipeline without those guards is exactly the hole the
|
|
18
18
|
* bundler-neutral module graph was built to close.
|
|
19
19
|
*/
|
|
20
|
+
|
|
20
21
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
21
22
|
import { dirname, join, relative, resolve as resolvePath } from "node:path"
|
|
23
|
+
import { singleCopyPackageNames } from "@nifrajs/core/single-copy"
|
|
22
24
|
import {
|
|
23
25
|
type BuildClientOptions,
|
|
24
26
|
type BuildTargetOptions,
|
|
@@ -72,6 +74,7 @@ type ViteBuildManifest = Readonly<Record<string, ViteManifestEntry>>
|
|
|
72
74
|
|
|
73
75
|
interface ViteModule {
|
|
74
76
|
build(config: Record<string, unknown>): Promise<unknown>
|
|
77
|
+
loadEnv(mode: string, envDir: string, prefixes: string): Record<string, string>
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
/** Load the app's Vite. Resolved from `root` so it's the project's copy, not this package's. */
|
|
@@ -181,6 +184,8 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
181
184
|
...(routeManifest.notFound ? [routeManifest.notFound.file] : []),
|
|
182
185
|
// A nested `_404` is an entry only for its stylesheet: it renders on the server, unhydrated.
|
|
183
186
|
...Object.values(routeManifest.notFounds ?? {}).map((page) => page.file),
|
|
187
|
+
// A `_loading` page is an entry for its stylesheet too: the bootstrap imports it lazily.
|
|
188
|
+
...Object.values(routeManifest.loadings ?? {}).map((page) => page.file),
|
|
184
189
|
]),
|
|
185
190
|
].sort()
|
|
186
191
|
|
|
@@ -220,7 +225,11 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
220
225
|
generatedFiles: [entryFile],
|
|
221
226
|
verified,
|
|
222
227
|
...(options.publicEnvPrefix !== undefined ? { publicEnvPrefix: options.publicEnvPrefix } : {}),
|
|
223
|
-
|
|
228
|
+
// Vite reads `.env.<mode>` files too; a value only there is still the app's secret to keep.
|
|
229
|
+
secrets: {
|
|
230
|
+
env: { ...vite.loadEnv(mode, root, ""), ...buildEnv },
|
|
231
|
+
...(exemptions ? { exemptions } : {}),
|
|
232
|
+
},
|
|
224
233
|
}
|
|
225
234
|
// nifra copies `public/` after the build; the main guard scans it with the bundle.
|
|
226
235
|
const publicDir = options.publicDir === false ? undefined : (options.publicDir ?? "public")
|
|
@@ -251,7 +260,7 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
251
260
|
// Same framework coverage as the Bun build's dedupe plugins, from the one policy table: one
|
|
252
261
|
// physical copy of react/react-dom, preact, and svelte, or a hook-using route gets a second
|
|
253
262
|
// dispatcher/options global. No-op per framework the app does not use.
|
|
254
|
-
dedupe: [...viteDedupePackages()],
|
|
263
|
+
dedupe: [...viteDedupePackages(), ...singleCopyPackageNames(root)],
|
|
255
264
|
...(options.conditions ? { conditions: [...options.conditions] } : {}),
|
|
256
265
|
},
|
|
257
266
|
css: {
|
|
@@ -352,14 +361,22 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
352
361
|
routes._404 = c !== undefined ? [c] : []
|
|
353
362
|
}
|
|
354
363
|
|
|
355
|
-
// CSS per route
|
|
364
|
+
// CSS per route. A manifest entry's `css` lists only that chunk's own stylesheets, so a page also
|
|
365
|
+
// needs those of every chunk it imports statically (a component two routes share gets a chunk of
|
|
366
|
+
// its own) and the bootstrap's, which every page loads (a stylesheet the client module imports).
|
|
367
|
+
// The bootstrap's come first: the whole-app stylesheet before any route-scoped one.
|
|
356
368
|
const stylesFor = (files: readonly string[]): readonly string[] => {
|
|
357
369
|
const urls = new Set<string>()
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
370
|
+
const seen = new Set<string>()
|
|
371
|
+
const visit = (key: string | undefined): void => {
|
|
372
|
+
if (key === undefined || seen.has(key)) return
|
|
373
|
+
seen.add(key)
|
|
374
|
+
const entry = viteManifest[key]
|
|
361
375
|
for (const css of entry?.css ?? []) urls.add(url(css))
|
|
376
|
+
for (const imported of entry?.imports ?? []) visit(imported)
|
|
362
377
|
}
|
|
378
|
+
visit(entryKey)
|
|
379
|
+
for (const file of files) visit(fileKey.get(file))
|
|
363
380
|
return [...urls]
|
|
364
381
|
}
|
|
365
382
|
// CSS aggregate - every stylesheet the app emits, the always-safe fallback. With native Vite
|
|
@@ -376,8 +393,13 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
376
393
|
// A single aggregate stylesheet is deliberately the route fallback. A per-route `[]` map would
|
|
377
394
|
// suppress it in `createWebApp` and produce unstyled SSR on every route.
|
|
378
395
|
if (css.length > 0 && cssCodeSplit) {
|
|
379
|
-
|
|
380
|
-
|
|
396
|
+
// A `_loading` page can show on a navigation from ANY page, and a document links only its own
|
|
397
|
+
// route's stylesheets - so every page that can start a navigation carries the loading pages' too.
|
|
398
|
+
const loadingFiles = Object.values(routeManifest.loadings ?? {}).map((page) => page.file)
|
|
399
|
+
for (const route of routeManifest.routes)
|
|
400
|
+
routeStyles[route.id] = stylesFor([...chainFiles(route), ...loadingFiles])
|
|
401
|
+
if (routeManifest.notFound)
|
|
402
|
+
routeStyles._404 = stylesFor([routeManifest.notFound.file, ...loadingFiles])
|
|
381
403
|
for (const [id, page] of Object.entries(routeManifest.notFounds ?? {})) {
|
|
382
404
|
routeStyles[id] = stylesFor([
|
|
383
405
|
...page.layoutIds.map((layoutId) => routeManifest.layouts[layoutId]?.file ?? ""),
|
|
@@ -574,7 +596,7 @@ export async function buildServerVite(options: BuildServerViteOptions): Promise<
|
|
|
574
596
|
"globalThis.__NIFRA_EDGE_RUNTIME__": edge ? "true" : "false",
|
|
575
597
|
},
|
|
576
598
|
resolve: {
|
|
577
|
-
dedupe: ["react", "react-dom"],
|
|
599
|
+
dedupe: ["react", "react-dom", ...singleCopyPackageNames(root)],
|
|
578
600
|
conditions: [...conditions],
|
|
579
601
|
},
|
|
580
602
|
plugins: [...(options.vitePlugins ?? [])],
|
package/src/build.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { publicEnvDefines } from "./internal/public-env.ts"
|
|
2
|
+
|
|
3
|
+
export { publicEnvDefines } from "./internal/public-env.ts"
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* `@nifrajs/web/build` - the production build (Bun-only, build-time). `buildClient` codegens + bundles
|
|
3
7
|
* the client entry (content-hashed, code-split); `buildServer` codegens the static-import server
|
|
@@ -9,6 +13,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync
|
|
|
9
13
|
import { cp, lstat, mkdir, realpath } from "node:fs/promises"
|
|
10
14
|
import {
|
|
11
15
|
dirname,
|
|
16
|
+
isAbsolute,
|
|
12
17
|
join,
|
|
13
18
|
basename as pathBasename,
|
|
14
19
|
posix,
|
|
@@ -25,6 +30,7 @@ import {
|
|
|
25
30
|
aggregateSizeReport,
|
|
26
31
|
type BuildManifest,
|
|
27
32
|
type BuildTarget,
|
|
33
|
+
type BuildTargetPlan,
|
|
28
34
|
type Bundler,
|
|
29
35
|
type ChunkSize,
|
|
30
36
|
detectNodeBuiltinsInClient,
|
|
@@ -44,6 +50,8 @@ import { sanitizeOutputNames } from "./chunk-names.ts"
|
|
|
44
50
|
import { type CssLoadingMode, normalizeCssCodeSplit, normalizeCssLoading } from "./css-contract.ts"
|
|
45
51
|
import { discoverRoutes } from "./fs.ts"
|
|
46
52
|
import { generateClientEntry, generateServerManifest } from "./index.ts"
|
|
53
|
+
import { assertDisposableDir } from "./internal/disposable-dir.ts"
|
|
54
|
+
import { entryChunks } from "./internal/entry-chunks.ts"
|
|
47
55
|
import { dedupePolicyFor } from "./internal/identity-policy.ts"
|
|
48
56
|
import {
|
|
49
57
|
assertDevelopmentProductionParity,
|
|
@@ -106,7 +114,14 @@ const entryName = (file: string): string => {
|
|
|
106
114
|
* `fromBunMetafile`; this smaller view is only for the per-route stylesheet map. */
|
|
107
115
|
interface BunMetafile {
|
|
108
116
|
readonly outputs?: Readonly<
|
|
109
|
-
Record<
|
|
117
|
+
Record<
|
|
118
|
+
string,
|
|
119
|
+
{
|
|
120
|
+
readonly entryPoint?: string
|
|
121
|
+
readonly cssBundle?: string
|
|
122
|
+
readonly inputs?: Readonly<Record<string, unknown>>
|
|
123
|
+
}
|
|
124
|
+
>
|
|
110
125
|
>
|
|
111
126
|
}
|
|
112
127
|
|
|
@@ -180,20 +195,6 @@ export interface BuildClientOptions {
|
|
|
180
195
|
* define resolves it to `undefined` in the client bundle. An empty `prefix` exposes nothing (the
|
|
181
196
|
* opt-out). Pure + exported so the prefix/redaction contract is unit-testable without a real build.
|
|
182
197
|
*/
|
|
183
|
-
export function publicEnvDefines(
|
|
184
|
-
prefix: string,
|
|
185
|
-
env: Readonly<Record<string, string | undefined>>,
|
|
186
|
-
): Record<string, string> {
|
|
187
|
-
const defines: Record<string, string> = {}
|
|
188
|
-
if (prefix === "") return defines // opt-out: bake in nothing
|
|
189
|
-
for (const [name, value] of Object.entries(env)) {
|
|
190
|
-
// Skip `undefined` (a deleted/unset key can still enumerate) so we never bake in `"undefined"`.
|
|
191
|
-
if (name.startsWith(prefix) && value !== undefined) {
|
|
192
|
-
defines[`process.env.${name}`] = JSON.stringify(value)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return defines
|
|
196
|
-
}
|
|
197
198
|
|
|
198
199
|
/**
|
|
199
200
|
* Cloudflare Pages rejects a `_routes.json` with more than 100 include+exclude rules combined, or any
|
|
@@ -629,21 +630,27 @@ export async function buildClient(options: BuildClientOptions): Promise<BuildMan
|
|
|
629
630
|
const renamed = sanitizeOutputNames(outputs)
|
|
630
631
|
const toUrl = (path: string): string =>
|
|
631
632
|
`${publicPath}${renamed.get(basename(path)) ?? basename(path)}`
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
//
|
|
633
|
+
// Each entry's chunk is the output the metafile names that entry's source for. The position among the
|
|
634
|
+
// entry-point outputs ([bootstrap, ...routeFiles]) is only the fallback, for an entry the metafile
|
|
635
|
+
// does not name by path (a `resolve` that returns a bare specifier). A route's chunks = its layout
|
|
636
|
+
// chain + own file.
|
|
635
637
|
const entryPoints = outputs.filter((o) => o.kind === "entry-point")
|
|
636
|
-
const bootstrap = entryPoints[0]
|
|
637
|
-
if (bootstrap === undefined) throw new Error("[nifra/web] build produced no entry-point output")
|
|
638
638
|
if (entryPoints.length !== routeFiles.length + 1) {
|
|
639
639
|
throw new Error(
|
|
640
640
|
`[nifra/web] expected ${routeFiles.length + 1} entry-point outputs (bootstrap + ${routeFiles.length} routes), got ${entryPoints.length}`,
|
|
641
641
|
)
|
|
642
642
|
}
|
|
643
|
+
const bySource = entryChunks(clientMeta?.outputs ?? {}, cwd)
|
|
644
|
+
const chunkOf = (source: string, position: number): string | undefined => {
|
|
645
|
+
const path = bySource.get(resolvePath(source)) ?? entryPoints[position]?.path
|
|
646
|
+
return path === undefined ? undefined : toUrl(path)
|
|
647
|
+
}
|
|
648
|
+
const entryUrl = chunkOf(entryFile, 0)
|
|
649
|
+
if (entryUrl === undefined) throw new Error("[nifra/web] build produced no entry-point output")
|
|
643
650
|
const fileToChunk = new Map<string, string>()
|
|
644
651
|
routeFiles.forEach((file, i) => {
|
|
645
|
-
const
|
|
646
|
-
if (
|
|
652
|
+
const url = chunkOf(resolve(file), i + 1)
|
|
653
|
+
if (url !== undefined) fileToChunk.set(file, url)
|
|
647
654
|
})
|
|
648
655
|
const chunksFor = (chainFiles: readonly string[]): string[] =>
|
|
649
656
|
chainFiles.map((f) => fileToChunk.get(f)).filter((u): u is string => u !== undefined)
|
|
@@ -684,15 +691,30 @@ export async function buildClient(options: BuildClientOptions): Promise<BuildMan
|
|
|
684
691
|
// links only its layout chain + own CSS (deduped); an empty array means the page needs no CSS at all.
|
|
685
692
|
// Absent (→ aggregate fallback) only if Bun emits no metafile/cssBundle - never silently incomplete.
|
|
686
693
|
const cssByEntry = new Map<string, string>()
|
|
694
|
+
const bootstrapEntry = resolvePath(entryFile)
|
|
695
|
+
let bootstrapSources: readonly string[] = []
|
|
696
|
+
const routeSources = new Set<string>()
|
|
687
697
|
for (const out of Object.values(clientMeta?.outputs ?? {})) {
|
|
688
698
|
if (out.entryPoint !== undefined && out.cssBundle !== undefined) {
|
|
689
|
-
|
|
699
|
+
const entry = resolvePath(cwd, out.entryPoint)
|
|
700
|
+
cssByEntry.set(entry, toUrl(out.cssBundle))
|
|
701
|
+
const sources = Object.keys(clientMeta?.outputs?.[out.cssBundle]?.inputs ?? {})
|
|
702
|
+
if (entry === bootstrapEntry) bootstrapSources = sources
|
|
703
|
+
else for (const source of sources) routeSources.add(source)
|
|
690
704
|
}
|
|
691
705
|
}
|
|
706
|
+
// A stylesheet the client module imports is bundled only into the bootstrap's CSS, which also holds
|
|
707
|
+
// every route's (the bootstrap imports each route lazily). When it carries CSS no route entry owns,
|
|
708
|
+
// every page links that bundle first, the whole-app stylesheet before any route-scoped one, as a
|
|
709
|
+
// Vite page links the bootstrap's; otherwise the page renders without it.
|
|
710
|
+
const leadingCss = bootstrapSources.some((source) => !routeSources.has(source))
|
|
711
|
+
? cssByEntry.get(bootstrapEntry)
|
|
712
|
+
: undefined
|
|
692
713
|
const stylesFor = (chainFiles: readonly string[]): readonly string[] => {
|
|
693
714
|
const urls = chainFiles
|
|
694
715
|
.map((f) => (f ? cssByEntry.get(resolvePath(resolve(f))) : undefined))
|
|
695
716
|
.filter((u): u is string => u !== undefined)
|
|
717
|
+
if (leadingCss !== undefined) urls.unshift(leadingCss)
|
|
696
718
|
return [...new Set(urls)]
|
|
697
719
|
}
|
|
698
720
|
const routeStyles: Record<string, readonly string[]> = {}
|
|
@@ -700,7 +722,7 @@ export async function buildClient(options: BuildClientOptions): Promise<BuildMan
|
|
|
700
722
|
// route entry (StyleX's atomic CSS is one example). In that shape there is no useful per-route map:
|
|
701
723
|
// emitting `routeId: []` would suppress the aggregate `styles` fallback in `createWebApp` and render
|
|
702
724
|
// SSR pages unstyled. Keep routeStyles absent until at least one authored route entry owns CSS.
|
|
703
|
-
const routeCssEntries = [...cssByEntry.keys()].filter((entry) => entry !==
|
|
725
|
+
const routeCssEntries = [...cssByEntry.keys()].filter((entry) => entry !== bootstrapEntry)
|
|
704
726
|
if (css.length > 0 && routeCssEntries.length > 0) {
|
|
705
727
|
// A `_loading` page can show on a navigation from ANY page, and a document links only its own
|
|
706
728
|
// route's stylesheets - so every page that can start a navigation carries the loading pages' too.
|
|
@@ -729,7 +751,7 @@ export async function buildClient(options: BuildClientOptions): Promise<BuildMan
|
|
|
729
751
|
publicDir !== undefined && existsSync(publicDir) ? await copyPublicDir(publicDir, outDir) : []
|
|
730
752
|
|
|
731
753
|
const manifest: BuildManifest = {
|
|
732
|
-
entry:
|
|
754
|
+
entry: entryUrl,
|
|
733
755
|
assets: outputs.map((o) => toUrl(o.path)),
|
|
734
756
|
routes,
|
|
735
757
|
...(publicFiles.length > 0 ? { publicFiles } : {}),
|
|
@@ -1009,11 +1031,22 @@ function withEmittedImports(
|
|
|
1009
1031
|
return { ...graph, chunks }
|
|
1010
1032
|
}
|
|
1011
1033
|
|
|
1012
|
-
/**
|
|
1034
|
+
/**
|
|
1035
|
+
* Refusals the bundler stopped on before it produced a graph, so without import chains. Files sharing
|
|
1036
|
+
* one reason share one line: with no chain to tell them apart, 50 lines would say one thing 50 times.
|
|
1037
|
+
*/
|
|
1013
1038
|
function formatRefusedFiles(refused: ReadonlyMap<string, string>, root: string): string {
|
|
1014
|
-
const
|
|
1039
|
+
const byReason = new Map<string, string[]>()
|
|
1040
|
+
for (const [file, reason] of refused) {
|
|
1015
1041
|
const rel = relative(root, file).replaceAll("\\", "/")
|
|
1016
|
-
|
|
1042
|
+
const shown = rel.startsWith("..") ? file : rel
|
|
1043
|
+
const files = byReason.get(reason)
|
|
1044
|
+
if (files === undefined) byReason.set(reason, [shown])
|
|
1045
|
+
else files.push(shown)
|
|
1046
|
+
}
|
|
1047
|
+
const lines = [...byReason].map(([reason, files]) => {
|
|
1048
|
+
const more = files.length > 5 ? ` and ${files.length - 5} more` : ""
|
|
1049
|
+
return ` - ${files.slice(0, 5).join(", ")}${more}: ${reason}`
|
|
1017
1050
|
})
|
|
1018
1051
|
return `[nifra/web] the browser build reached code that may not ship to a browser:\n${lines.join("\n")}`
|
|
1019
1052
|
}
|
|
@@ -1247,6 +1280,9 @@ export function generateServerEntry(options: {
|
|
|
1247
1280
|
readonly title?: string
|
|
1248
1281
|
/** Encoded root-relative public file paths copied into the deploy directory. */
|
|
1249
1282
|
readonly publicFiles?: readonly string[]
|
|
1283
|
+
/** URL paths of the content-hashed client outputs (the build manifest's `assets`). When given, a
|
|
1284
|
+
* self-hosted entry caches only these immutably; otherwise every file under `/assets/` is. */
|
|
1285
|
+
readonly hashedFiles?: readonly string[]
|
|
1250
1286
|
/** Trust the edge platform's client-address header for `c.clientIp`. See {@link ServerEntryClientIp}. */
|
|
1251
1287
|
readonly clientIp?: ServerEntryClientIp
|
|
1252
1288
|
}): string {
|
|
@@ -1258,6 +1294,7 @@ export function generateServerEntry(options: {
|
|
|
1258
1294
|
optionImports = {},
|
|
1259
1295
|
title = "nifra",
|
|
1260
1296
|
publicFiles = [],
|
|
1297
|
+
hashedFiles,
|
|
1261
1298
|
clientIp,
|
|
1262
1299
|
} = options
|
|
1263
1300
|
if (clientIp !== undefined && clientIp !== "platform") {
|
|
@@ -1355,6 +1392,9 @@ export function generateServerEntry(options: {
|
|
|
1355
1392
|
"// The client bundle and public files live next to this entry; serve only manifest-approved paths.",
|
|
1356
1393
|
'const STATIC_ROOT = new URL("./", import.meta.url)',
|
|
1357
1394
|
`const PUBLIC_FILES = new Set(${JSON.stringify(publicFiles)})`,
|
|
1395
|
+
...(hashedFiles !== undefined
|
|
1396
|
+
? [`const HASHED_FILES = new Set(${JSON.stringify(hashedFiles)})`]
|
|
1397
|
+
: []),
|
|
1358
1398
|
"const staticPath = (pathname: string): string | undefined => {",
|
|
1359
1399
|
" if (PUBLIC_FILES.has(pathname)) return '.' + pathname",
|
|
1360
1400
|
' if (!pathname.startsWith("/assets/")) return undefined',
|
|
@@ -1371,7 +1411,7 @@ export function generateServerEntry(options: {
|
|
|
1371
1411
|
`const TYPES: Record<string, string> = ${JSON.stringify(CONTENT_TYPES)}`,
|
|
1372
1412
|
"const staticHeaders = (pathname: string): Record<string, string> => ({",
|
|
1373
1413
|
' "content-type": TYPES[pathname.slice(pathname.lastIndexOf(".")).toLowerCase()] ?? "application/octet-stream",',
|
|
1374
|
-
` "cache-control": pathname.startsWith("/assets/") ? ${JSON.stringify(IMMUTABLE)} : ${JSON.stringify(ONE_DAY)},`,
|
|
1414
|
+
` "cache-control": ${hashedFiles !== undefined ? "HASHED_FILES.has(pathname)" : 'pathname.startsWith("/assets/")'} ? ${JSON.stringify(IMMUTABLE)} : ${JSON.stringify(ONE_DAY)},`,
|
|
1375
1415
|
' "x-content-type-options": "nosniff",',
|
|
1376
1416
|
"})",
|
|
1377
1417
|
)
|
|
@@ -1467,10 +1507,12 @@ async function measureOutputs(paths: readonly string[]): Promise<ChunkSize[]> {
|
|
|
1467
1507
|
export interface BuildTargetOptions {
|
|
1468
1508
|
/** The `routes/` directory to discover (absolute path). */
|
|
1469
1509
|
readonly routesDir: string
|
|
1470
|
-
/** Output directory for the assembled deploy dir (absolute path). Cleared and recreated
|
|
1510
|
+
/** Output directory for the assembled deploy dir (absolute path). Cleared and recreated, so the
|
|
1511
|
+
* build refuses one that is a filesystem root or is or contains the routes directory, the public
|
|
1512
|
+
* directory, an absolute entry module, or the working directory. */
|
|
1471
1513
|
readonly outDir: string
|
|
1472
1514
|
/** A scratch directory for intermediate codegen (the generated server entry + manifest) and the
|
|
1473
|
-
* server bundle, cleaned up after. Absolute path. */
|
|
1515
|
+
* server bundle, cleaned up after. Absolute path. Checked the same way as `outDir`. */
|
|
1474
1516
|
readonly workDir: string
|
|
1475
1517
|
/** The adapter's client runtime module (exports `mountRouter`), e.g. `"@nifrajs/web-react/client"`. */
|
|
1476
1518
|
readonly clientModule: string
|
|
@@ -1597,6 +1639,26 @@ export const bunBundler: Bundler = {
|
|
|
1597
1639
|
}),
|
|
1598
1640
|
}
|
|
1599
1641
|
|
|
1642
|
+
/** Refuse a public file that shares a path with a file the target writes into the same directory: the
|
|
1643
|
+
* build overwrites it, and the server would then answer that public path with its own bundle. */
|
|
1644
|
+
function assertNoPublicCollision(
|
|
1645
|
+
plan: BuildTargetPlan,
|
|
1646
|
+
publicFiles: readonly string[],
|
|
1647
|
+
outDir: string,
|
|
1648
|
+
): void {
|
|
1649
|
+
if (plan.kind !== "server" || plan.staticDir !== "") return
|
|
1650
|
+
const owned = [`/${plan.outputFile}`]
|
|
1651
|
+
if (plan.target === "cloudflare") owned.push("/_routes.json")
|
|
1652
|
+
// Compared case-insensitively: on a case-insensitive filesystem `Server.js` is the same file.
|
|
1653
|
+
const clashes = publicFiles.filter((file) => owned.includes(file.toLowerCase()))
|
|
1654
|
+
if (clashes.length > 0) {
|
|
1655
|
+
throw new Error(
|
|
1656
|
+
`[nifra/web] public file(s) ${clashes.join(", ")} would be overwritten by the ${plan.target} ` +
|
|
1657
|
+
`build's own output in ${outDir}. Rename or move them out of the public directory.`,
|
|
1658
|
+
)
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1600
1662
|
/** Build a full deploy dir for `target` using the default Bun bundler. See {@link buildTargetWith}. */
|
|
1601
1663
|
export async function buildTarget(
|
|
1602
1664
|
target: BuildTarget,
|
|
@@ -1622,6 +1684,20 @@ export async function buildTargetWith(
|
|
|
1622
1684
|
const requestedCssLoading =
|
|
1623
1685
|
options.cssLoading === undefined ? undefined : normalizeCssLoading(options.cssLoading)
|
|
1624
1686
|
const targetPlan = planBuildTarget(parseBuildTarget(target), outDir)
|
|
1687
|
+
const sources = [
|
|
1688
|
+
routesDir,
|
|
1689
|
+
process.cwd(),
|
|
1690
|
+
resolvePath(
|
|
1691
|
+
typeof options.publicDir === "string"
|
|
1692
|
+
? options.publicDir
|
|
1693
|
+
: join(dirname(routesDir), "public"),
|
|
1694
|
+
),
|
|
1695
|
+
...[options.adapterImport, options.backendImport, options.useImport].filter(
|
|
1696
|
+
(file): file is string => file !== undefined && isAbsolute(file),
|
|
1697
|
+
),
|
|
1698
|
+
]
|
|
1699
|
+
assertDisposableDir("outDir", outDir, sources)
|
|
1700
|
+
assertDisposableDir("workDir", workDir, sources)
|
|
1625
1701
|
const { rmSync } = await import("node:fs")
|
|
1626
1702
|
rmSync(outDir, { recursive: true, force: true })
|
|
1627
1703
|
rmSync(workDir, { recursive: true, force: true })
|
|
@@ -1672,6 +1748,7 @@ export async function buildTargetWith(
|
|
|
1672
1748
|
publicDir !== undefined && existsSync(publicDir)
|
|
1673
1749
|
? await copyPublicDir(publicDir, staticRoot)
|
|
1674
1750
|
: []
|
|
1751
|
+
assertNoPublicCollision(targetPlan, publicFiles, outDir)
|
|
1675
1752
|
if (publicFiles.length > 0) {
|
|
1676
1753
|
client = { ...client, publicFiles }
|
|
1677
1754
|
}
|
|
@@ -1734,6 +1811,7 @@ export async function buildTargetWith(
|
|
|
1734
1811
|
...(options.backendImport !== undefined ? { backendImport: options.backendImport } : {}),
|
|
1735
1812
|
...(options.title !== undefined ? { title: options.title } : {}),
|
|
1736
1813
|
...(publicFiles.length > 0 ? { publicFiles } : {}),
|
|
1814
|
+
hashedFiles: client.assets,
|
|
1737
1815
|
...(options.clientIp !== undefined ? { clientIp: options.clientIp } : {}),
|
|
1738
1816
|
}),
|
|
1739
1817
|
)
|
package/src/cdn.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* for any other. Backend-only: a browser build that reaches this module fails.
|
|
12
12
|
*/
|
|
13
13
|
import "@nifrajs/web/backend-only"
|
|
14
|
+
import { writableResponse } from "@nifrajs/core/server"
|
|
14
15
|
import { isDraftEnabled } from "./draft.ts"
|
|
15
16
|
import type { CdnProvider } from "./internal/cdn/core.ts"
|
|
16
17
|
import { pathTag } from "./internal/cdn/core.ts"
|
|
@@ -84,15 +85,9 @@ const isHtml = (res: Response): boolean =>
|
|
|
84
85
|
(res.headers.get("content-type") ?? "").toLowerCase().includes("text/html")
|
|
85
86
|
|
|
86
87
|
function withHeaders(res: Response, set: Readonly<Record<string, string>>): Response {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
} catch {
|
|
91
|
-
// A `fetch()` response has immutable headers: rebuild it around the same body instead.
|
|
92
|
-
const headers = new Headers(res.headers)
|
|
93
|
-
for (const [name, value] of Object.entries(set)) headers.set(name, value)
|
|
94
|
-
return new Response(res.body, { status: res.status, statusText: res.statusText, headers })
|
|
95
|
-
}
|
|
88
|
+
const target = writableResponse(res)
|
|
89
|
+
for (const [name, value] of Object.entries(set)) target.headers.set(name, value)
|
|
90
|
+
return target
|
|
96
91
|
}
|
|
97
92
|
|
|
98
93
|
/**
|
|
@@ -150,6 +145,12 @@ export interface InvalidatorOptions {
|
|
|
150
145
|
readonly key?: (path: string) => string | null
|
|
151
146
|
/** The `query` policy given to `withISR`. Default `"bypass"`. Ignored with `key`. */
|
|
152
147
|
readonly query?: ISRQuery
|
|
148
|
+
/**
|
|
149
|
+
* Caches below the pages whose entries carry the same tags, such as a `@nifrajs/cache` holding
|
|
150
|
+
* loader data. Tags reach each of them before the store, so a page regenerated mid-purge cannot be
|
|
151
|
+
* rebuilt from stale data; a failure rejects before the store is touched. Paths do not reach them.
|
|
152
|
+
*/
|
|
153
|
+
readonly dataCaches?: readonly { invalidateTag(tag: string): unknown }[]
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
export interface InvalidateResult {
|
|
@@ -196,11 +197,16 @@ export function createInvalidator(options: InvalidatorOptions): {
|
|
|
196
197
|
throw new TypeError("[nifra/web/cdn] invalidate paths must start with /")
|
|
197
198
|
}
|
|
198
199
|
}
|
|
200
|
+
if (store !== undefined && tags.length > 0 && store.invalidateTag === undefined) {
|
|
201
|
+
throw new TypeError("[nifra/web/cdn] this store cannot invalidate by tag")
|
|
202
|
+
}
|
|
203
|
+
if (tags.length > 0) {
|
|
204
|
+
for (const cache of options.dataCaches ?? []) {
|
|
205
|
+
for (const tag of tags) await cache.invalidateTag(tag)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
199
208
|
let origin: InvalidateResult["origin"] = "skipped"
|
|
200
209
|
if (store !== undefined) {
|
|
201
|
-
if (tags.length > 0 && store.invalidateTag === undefined) {
|
|
202
|
-
throw new TypeError("[nifra/web/cdn] this store cannot invalidate by tag")
|
|
203
|
-
}
|
|
204
210
|
for (const path of paths) {
|
|
205
211
|
const key = keyOf?.(path)
|
|
206
212
|
if (key !== null && key !== undefined) await store.delete(key)
|