@nifrajs/web 3.5.0 → 4.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/dist/backend-only.d.ts +15 -0
- package/dist/backend-only.d.ts.map +1 -0
- package/dist/backend-only.js +16 -0
- package/dist/backend-only.js.map +1 -0
- package/dist/boundary.d.ts +5 -0
- package/dist/boundary.d.ts.map +1 -1
- package/dist/boundary.js +11 -2
- package/dist/boundary.js.map +1 -1
- package/dist/build-plan.d.ts +18 -6
- package/dist/build-plan.d.ts.map +1 -1
- package/dist/build-plan.js +82 -34
- package/dist/build-plan.js.map +1 -1
- package/dist/build-vite.d.ts +4 -0
- package/dist/build-vite.d.ts.map +1 -1
- package/dist/build-vite.js +68 -13
- package/dist/build-vite.js.map +1 -1
- package/dist/build.d.ts +57 -23
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +356 -85
- package/dist/build.js.map +1 -1
- package/dist/bun-dev-entry.d.ts +1 -1
- package/dist/bun-dev-entry.js +1 -1
- package/dist/cdn.d.ts +74 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.js +132 -0
- package/dist/cdn.js.map +1 -0
- package/dist/client.d.ts +3 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +111 -15
- package/dist/client.js.map +1 -1
- package/dist/conformance.d.ts +4 -3
- package/dist/conformance.d.ts.map +1 -1
- package/dist/conformance.js +12 -3
- package/dist/conformance.js.map +1 -1
- package/dist/csp.d.ts +93 -0
- package/dist/csp.d.ts.map +1 -0
- package/dist/csp.js +122 -0
- package/dist/csp.js.map +1 -0
- package/dist/dev-client.d.ts +76 -0
- package/dist/dev-client.d.ts.map +1 -0
- package/dist/dev-client.js +280 -0
- package/dist/dev-client.js.map +1 -0
- package/dist/dev-diagnostics.d.ts +26 -2
- package/dist/dev-diagnostics.d.ts.map +1 -1
- package/dist/dev-diagnostics.js +38 -7
- package/dist/dev-diagnostics.js.map +1 -1
- package/dist/dev-error.d.ts +4 -13
- package/dist/dev-error.d.ts.map +1 -1
- package/dist/dev-error.js +46 -4
- package/dist/dev-error.js.map +1 -1
- package/dist/dev-feed.d.ts +298 -0
- package/dist/dev-feed.d.ts.map +1 -0
- package/dist/dev-feed.js +797 -0
- package/dist/dev-feed.js.map +1 -0
- package/dist/dev-indicator.d.ts +38 -0
- package/dist/dev-indicator.d.ts.map +1 -0
- package/dist/dev-indicator.js +93 -0
- package/dist/dev-indicator.js.map +1 -0
- package/dist/dev-session.d.ts +77 -0
- package/dist/dev-session.d.ts.map +1 -0
- package/dist/dev-session.js +580 -0
- package/dist/dev-session.js.map +1 -0
- package/dist/dev-sourcemap.d.ts +27 -0
- package/dist/dev-sourcemap.d.ts.map +1 -0
- package/dist/dev-sourcemap.js +235 -0
- package/dist/dev-sourcemap.js.map +1 -0
- package/dist/dev-ssr-graph.d.ts.map +1 -1
- package/dist/dev-ssr-graph.js +13 -5
- package/dist/dev-ssr-graph.js.map +1 -1
- package/dist/dev.d.ts +15 -2
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +69 -44
- package/dist/dev.js.map +1 -1
- package/dist/diagnostic-catalog.d.ts +35 -0
- package/dist/diagnostic-catalog.d.ts.map +1 -0
- package/dist/diagnostic-catalog.js +203 -0
- package/dist/diagnostic-catalog.js.map +1 -0
- package/dist/diagnostic-prompt.d.ts +49 -0
- package/dist/diagnostic-prompt.d.ts.map +1 -0
- package/dist/diagnostic-prompt.js +303 -0
- package/dist/diagnostic-prompt.js.map +1 -0
- package/dist/diagnostic.d.ts +17 -23
- package/dist/diagnostic.d.ts.map +1 -1
- package/dist/diagnostic.js +31 -39
- package/dist/diagnostic.js.map +1 -1
- package/dist/draft.d.ts.map +1 -1
- package/dist/draft.js +4 -1
- package/dist/draft.js.map +1 -1
- package/dist/fn.d.ts +5 -0
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +13 -3
- package/dist/fn.js.map +1 -1
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +4 -2
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +13 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -12
- package/dist/index.js.map +1 -1
- package/dist/internal/cdn/cloudflare.d.ts +48 -0
- package/dist/internal/cdn/cloudflare.d.ts.map +1 -0
- package/dist/internal/cdn/cloudflare.js +94 -0
- package/dist/internal/cdn/cloudflare.js.map +1 -0
- package/dist/internal/cdn/core.d.ts +91 -0
- package/dist/internal/cdn/core.d.ts.map +1 -0
- package/dist/internal/cdn/core.js +220 -0
- package/dist/internal/cdn/core.js.map +1 -0
- package/dist/internal/cdn/fastly.d.ts +17 -0
- package/dist/internal/cdn/fastly.d.ts.map +1 -0
- package/dist/internal/cdn/fastly.js +43 -0
- package/dist/internal/cdn/fastly.js.map +1 -0
- package/dist/internal/cdn/vercel.d.ts +31 -0
- package/dist/internal/cdn/vercel.d.ts.map +1 -0
- package/dist/internal/cdn/vercel.js +56 -0
- package/dist/internal/cdn/vercel.js.map +1 -0
- package/dist/internal/code-unit-order.d.ts +4 -0
- package/dist/internal/code-unit-order.d.ts.map +1 -0
- package/dist/internal/code-unit-order.js +6 -0
- package/dist/internal/code-unit-order.js.map +1 -0
- package/dist/internal/codegen.d.ts.map +1 -1
- package/dist/internal/codegen.js +141 -25
- package/dist/internal/codegen.js.map +1 -1
- package/dist/internal/dev-csp.d.ts +24 -0
- package/dist/internal/dev-csp.d.ts.map +1 -0
- package/dist/internal/dev-csp.js +160 -0
- package/dist/internal/dev-csp.js.map +1 -0
- package/dist/internal/dev-reserved.d.ts +25 -0
- package/dist/internal/dev-reserved.d.ts.map +1 -0
- package/dist/internal/dev-reserved.js +39 -0
- package/dist/internal/dev-reserved.js.map +1 -0
- package/dist/internal/html-spans.d.ts +10 -0
- package/dist/internal/html-spans.d.ts.map +1 -0
- package/dist/internal/html-spans.js +46 -0
- package/dist/internal/html-spans.js.map +1 -0
- package/dist/internal/loading-runtime.d.ts +44 -0
- package/dist/internal/loading-runtime.d.ts.map +1 -0
- package/dist/internal/loading-runtime.js +206 -0
- package/dist/internal/loading-runtime.js.map +1 -0
- package/dist/internal/matches-runtime.d.ts +8 -0
- package/dist/internal/matches-runtime.d.ts.map +1 -0
- package/dist/internal/matches-runtime.js +61 -0
- package/dist/internal/matches-runtime.js.map +1 -0
- package/dist/internal/mount-shadow.d.ts +36 -0
- package/dist/internal/mount-shadow.d.ts.map +1 -0
- package/dist/internal/mount-shadow.js +65 -0
- package/dist/internal/mount-shadow.js.map +1 -0
- package/dist/internal/node-builtins.d.ts +3 -0
- package/dist/internal/node-builtins.d.ts.map +1 -0
- package/dist/internal/node-builtins.js +79 -0
- package/dist/internal/node-builtins.js.map +1 -0
- package/dist/internal/output-guard.d.ts +65 -0
- package/dist/internal/output-guard.d.ts.map +1 -0
- package/dist/internal/output-guard.js +630 -0
- package/dist/internal/output-guard.js.map +1 -0
- package/dist/internal/page-execution.d.ts +20 -8
- package/dist/internal/page-execution.d.ts.map +1 -1
- package/dist/internal/page-execution.js +571 -105
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/parity.d.ts +21 -0
- package/dist/internal/parity.d.ts.map +1 -1
- package/dist/internal/parity.js +104 -22
- package/dist/internal/parity.js.map +1 -1
- package/dist/internal/private-env.d.ts +12 -0
- package/dist/internal/private-env.d.ts.map +1 -0
- package/dist/internal/private-env.js +335 -0
- package/dist/internal/private-env.js.map +1 -0
- package/dist/internal/public-url.d.ts +3 -0
- package/dist/internal/public-url.d.ts.map +1 -0
- package/dist/internal/public-url.js +18 -0
- package/dist/internal/public-url.js.map +1 -0
- package/dist/internal/render-document.d.ts +25 -19
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +77 -61
- package/dist/internal/render-document.js.map +1 -1
- package/dist/internal/response-controls.d.ts +75 -0
- package/dist/internal/response-controls.d.ts.map +1 -0
- package/dist/internal/response-controls.js +256 -0
- package/dist/internal/response-controls.js.map +1 -0
- package/dist/internal/runtime-contract.d.ts +11 -16
- package/dist/internal/runtime-contract.d.ts.map +1 -1
- package/dist/internal/runtime-contract.js.map +1 -1
- package/dist/internal/secret-scan.d.ts +104 -0
- package/dist/internal/secret-scan.d.ts.map +1 -0
- package/dist/internal/secret-scan.js +485 -0
- package/dist/internal/secret-scan.js.map +1 -0
- package/dist/internal/server-boundary.d.ts +6 -29
- package/dist/internal/server-boundary.d.ts.map +1 -1
- package/dist/internal/server-boundary.js +6 -66
- package/dist/internal/server-boundary.js.map +1 -1
- package/dist/internal/source-map.d.ts +47 -0
- package/dist/internal/source-map.d.ts.map +1 -0
- package/dist/internal/source-map.js +225 -0
- package/dist/internal/source-map.js.map +1 -0
- package/dist/internal/target-compat.d.ts +27 -0
- package/dist/internal/target-compat.d.ts.map +1 -0
- package/dist/internal/target-compat.js +77 -0
- package/dist/internal/target-compat.js.map +1 -0
- package/dist/internal/timing-safe-equal.d.ts +6 -0
- package/dist/internal/timing-safe-equal.d.ts.map +1 -1
- package/dist/internal/timing-safe-equal.js +10 -0
- package/dist/internal/timing-safe-equal.js.map +1 -1
- package/dist/internal/vitals-runtime.d.ts +18 -0
- package/dist/internal/vitals-runtime.d.ts.map +1 -0
- package/dist/internal/vitals-runtime.js +38 -0
- package/dist/internal/vitals-runtime.js.map +1 -0
- package/dist/internal/web-app.d.ts +38 -9
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +199 -59
- package/dist/internal/web-app.js.map +1 -1
- package/dist/internal/zone-graph.d.ts +89 -0
- package/dist/internal/zone-graph.d.ts.map +1 -0
- package/dist/internal/zone-graph.js +492 -0
- package/dist/internal/zone-graph.js.map +1 -0
- package/dist/isr.d.ts +83 -6
- package/dist/isr.d.ts.map +1 -1
- package/dist/isr.js +263 -36
- package/dist/isr.js.map +1 -1
- package/dist/llms-txt.d.ts.map +1 -1
- package/dist/llms-txt.js +31 -6
- package/dist/llms-txt.js.map +1 -1
- package/dist/manifest.d.ts +220 -13
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +386 -9
- package/dist/manifest.js.map +1 -1
- package/dist/module-graph.d.ts +26 -5
- package/dist/module-graph.d.ts.map +1 -1
- package/dist/module-graph.js +17 -7
- package/dist/module-graph.js.map +1 -1
- package/dist/navigation.d.ts +17 -3
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +11 -5
- package/dist/navigation.js.map +1 -1
- package/dist/nonce.d.ts +47 -0
- package/dist/nonce.d.ts.map +1 -0
- package/dist/nonce.js +63 -0
- package/dist/nonce.js.map +1 -0
- package/dist/plugins/css-modules.d.ts.map +1 -1
- package/dist/plugins/css-modules.js +4 -3
- package/dist/plugins/css-modules.js.map +1 -1
- package/dist/plugins/kit.d.ts +9 -0
- package/dist/plugins/kit.d.ts.map +1 -1
- package/dist/plugins/kit.js +18 -0
- package/dist/plugins/kit.js.map +1 -1
- package/dist/plugins/svg.d.ts +22 -3
- package/dist/plugins/svg.d.ts.map +1 -1
- package/dist/plugins/svg.js +112 -1
- package/dist/plugins/svg.js.map +1 -1
- package/dist/plugins/vite-leak-guard.d.ts +107 -3
- package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
- package/dist/plugins/vite-leak-guard.js +378 -17
- package/dist/plugins/vite-leak-guard.js.map +1 -1
- package/dist/plugins/vite-zone-guard.d.ts +61 -0
- package/dist/plugins/vite-zone-guard.d.ts.map +1 -0
- package/dist/plugins/vite-zone-guard.js +208 -0
- package/dist/plugins/vite-zone-guard.js.map +1 -0
- package/dist/plugins/zone-guard.d.ts +27 -0
- package/dist/plugins/zone-guard.d.ts.map +1 -0
- package/dist/plugins/zone-guard.js +72 -0
- package/dist/plugins/zone-guard.js.map +1 -0
- package/dist/prerender.d.ts +10 -0
- package/dist/prerender.d.ts.map +1 -1
- package/dist/prerender.js +35 -3
- package/dist/prerender.js.map +1 -1
- package/dist/public-dir.d.ts +9 -0
- package/dist/public-dir.d.ts.map +1 -1
- package/dist/public-dir.js +67 -9
- package/dist/public-dir.js.map +1 -1
- package/dist/pwa-manifest.d.ts +68 -0
- package/dist/pwa-manifest.d.ts.map +1 -0
- package/dist/pwa-manifest.js +178 -0
- package/dist/pwa-manifest.js.map +1 -0
- package/dist/query.js +4 -4
- package/dist/query.js.map +1 -1
- package/dist/render-seam.d.ts +42 -2
- package/dist/render-seam.d.ts.map +1 -1
- package/dist/render-seam.js +6 -0
- package/dist/render-seam.js.map +1 -1
- package/dist/route-manifest.d.ts +3 -0
- package/dist/route-manifest.d.ts.map +1 -1
- package/dist/route-manifest.js +26 -3
- package/dist/route-manifest.js.map +1 -1
- package/dist/route-types.d.ts +24 -0
- package/dist/route-types.d.ts.map +1 -0
- package/dist/route-types.js +195 -0
- package/dist/route-types.js.map +1 -0
- package/dist/router.d.ts +28 -6
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +129 -40
- package/dist/router.js.map +1 -1
- package/dist/vitals.d.ts +33 -0
- package/dist/vitals.d.ts.map +1 -0
- package/dist/vitals.js +16 -0
- package/dist/vitals.js.map +1 -0
- package/dist/vite.d.ts +16 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +187 -36
- package/dist/vite.js.map +1 -1
- package/dist/zones.d.ts +70 -0
- package/dist/zones.d.ts.map +1 -0
- package/dist/zones.js +365 -0
- package/dist/zones.js.map +1 -0
- package/package.json +67 -14
- package/src/backend-only.ts +16 -0
- package/src/boundary.ts +18 -5
- package/src/build-plan.ts +90 -35
- package/src/build-vite.ts +77 -11
- package/src/build.ts +466 -96
- package/src/bun-dev-entry.ts +1 -1
- package/src/cdn.ts +216 -0
- package/src/client.ts +111 -18
- package/src/conformance.ts +16 -3
- package/src/csp.ts +194 -0
- package/src/dev-client.ts +349 -0
- package/src/dev-diagnostics.ts +60 -7
- package/src/dev-error.ts +49 -5
- package/src/dev-feed.ts +1140 -0
- package/src/dev-indicator.ts +113 -0
- package/src/dev-session.ts +729 -0
- package/src/dev-sourcemap.ts +281 -0
- package/src/dev-ssr-graph.ts +16 -5
- package/src/dev.ts +86 -43
- package/src/diagnostic-catalog.ts +243 -0
- package/src/diagnostic-prompt.ts +355 -0
- package/src/diagnostic.ts +63 -66
- package/src/draft.ts +4 -1
- package/src/fn.ts +19 -3
- package/src/fs.ts +13 -2
- package/src/index.ts +42 -10
- package/src/internal/cdn/cloudflare.ts +146 -0
- package/src/internal/cdn/core.ts +316 -0
- package/src/internal/cdn/fastly.ts +62 -0
- package/src/internal/cdn/vercel.ts +95 -0
- package/src/internal/code-unit-order.ts +5 -0
- package/src/internal/codegen.ts +161 -24
- package/src/internal/dev-csp.ts +176 -0
- package/src/internal/dev-reserved.ts +52 -0
- package/src/internal/html-spans.ts +50 -0
- package/src/internal/loading-runtime.ts +244 -0
- package/src/internal/matches-runtime.ts +62 -0
- package/src/internal/mount-shadow.ts +88 -0
- package/src/internal/node-builtins.ts +79 -0
- package/src/internal/output-guard.ts +701 -0
- package/src/internal/page-execution.ts +795 -185
- package/src/internal/parity.ts +150 -36
- package/src/internal/private-env.ts +334 -0
- package/src/internal/public-url.ts +22 -0
- package/src/internal/render-document.ts +114 -67
- package/src/internal/response-controls.ts +284 -0
- package/src/internal/runtime-contract.ts +10 -15
- package/src/internal/secret-scan.ts +623 -0
- package/src/internal/server-boundary.ts +6 -69
- package/src/internal/source-map.ts +256 -0
- package/src/internal/target-compat.ts +92 -0
- package/src/internal/timing-safe-equal.ts +13 -0
- package/src/internal/vitals-runtime.ts +53 -0
- package/src/internal/web-app.ts +262 -84
- package/src/internal/zone-graph.ts +593 -0
- package/src/isr.ts +325 -37
- package/src/llms-txt.ts +28 -4
- package/src/manifest.ts +670 -16
- package/src/module-graph.ts +53 -9
- package/src/navigation.ts +29 -6
- package/src/nonce.ts +104 -0
- package/src/plugins/css-modules.ts +5 -3
- package/src/plugins/kit.ts +24 -0
- package/src/plugins/svg.ts +135 -4
- package/src/plugins/vite-leak-guard.ts +529 -16
- package/src/plugins/vite-zone-guard.ts +263 -0
- package/src/plugins/zone-guard.ts +110 -0
- package/src/prerender.ts +49 -3
- package/src/public-dir.ts +69 -8
- package/src/pwa-manifest.ts +226 -0
- package/src/query.ts +4 -4
- package/src/render-seam.ts +46 -1
- package/src/route-manifest.ts +15 -3
- package/src/route-types.ts +264 -0
- package/src/router.ts +163 -63
- package/src/vitals.ts +44 -0
- package/src/vite.ts +207 -36
- package/src/zones.ts +430 -0
- package/dist/plugins/vite-server-only.d.ts +0 -49
- package/dist/plugins/vite-server-only.d.ts.map +0 -1
- package/dist/plugins/vite-server-only.js +0 -57
- package/dist/plugins/vite-server-only.js.map +0 -1
- package/dist/server-only.d.ts +0 -21
- package/dist/server-only.d.ts.map +0 -1
- package/dist/server-only.js +0 -25
- package/dist/server-only.js.map +0 -1
- package/src/plugins/vite-server-only.ts +0 -75
- package/src/server-only.ts +0 -25
package/src/build-plan.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { basename as pathBasename } from "node:path"
|
|
2
2
|
import type { CssLoadingMode } from "./css-contract.ts"
|
|
3
|
+
import { codeUnitOrder } from "./internal/code-unit-order.ts"
|
|
4
|
+
import { isBareNodeBuiltin } from "./internal/node-builtins.ts"
|
|
5
|
+
import type { SecretExemption } from "./internal/secret-scan.ts"
|
|
3
6
|
import type { ClientModuleGraph } from "./module-graph.ts"
|
|
4
7
|
|
|
5
8
|
export interface BuildManifest {
|
|
@@ -51,7 +54,7 @@ export interface ServerBuild {
|
|
|
51
54
|
// ===================================================================================================
|
|
52
55
|
|
|
53
56
|
/** A deploy target `nifra build --target <t>` can emit. `static` is pure SSG (no server). */
|
|
54
|
-
export const BUILD_TARGETS = ["bun", "node", "deno", "
|
|
57
|
+
export const BUILD_TARGETS = ["bun", "node", "deno", "cloudflare", "vercel", "static"] as const
|
|
55
58
|
export type BuildTarget = (typeof BUILD_TARGETS)[number]
|
|
56
59
|
|
|
57
60
|
/** A type guard narrowing an arbitrary string to a {@link BuildTarget}. */
|
|
@@ -59,6 +62,16 @@ export function isBuildTarget(value: string): value is BuildTarget {
|
|
|
59
62
|
return (BUILD_TARGETS as readonly string[]).includes(value)
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
/** `value` as a {@link BuildTarget}, or throw naming the valid ones (and the renamed `cf-pages`). */
|
|
66
|
+
export function parseBuildTarget(value: string, label = "target"): BuildTarget {
|
|
67
|
+
if (isBuildTarget(value)) return value
|
|
68
|
+
throw new Error(
|
|
69
|
+
value === "cf-pages"
|
|
70
|
+
? `[nifra] the ${label} "cf-pages" is now "cloudflare"`
|
|
71
|
+
: `[nifra] unknown ${label} "${value}". Valid: ${BUILD_TARGETS.join(", ")}`,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
62
75
|
export type ServerBuildTarget = "browser" | "node" | "bun"
|
|
63
76
|
|
|
64
77
|
export interface StaticBuildTargetPlan {
|
|
@@ -66,6 +79,7 @@ export interface StaticBuildTargetPlan {
|
|
|
66
79
|
readonly kind: "static"
|
|
67
80
|
readonly serverTarget: undefined
|
|
68
81
|
readonly outputFile: undefined
|
|
82
|
+
readonly staticDir: ""
|
|
69
83
|
readonly run: string
|
|
70
84
|
}
|
|
71
85
|
|
|
@@ -73,8 +87,10 @@ export interface ServerBuildTargetPlan {
|
|
|
73
87
|
readonly target: Exclude<BuildTarget, "static">
|
|
74
88
|
readonly kind: "server"
|
|
75
89
|
readonly serverTarget: ServerBuildTarget
|
|
76
|
-
/** The worker's final
|
|
77
|
-
readonly outputFile: "_worker.js" | "index.js" | "server.js"
|
|
90
|
+
/** The worker's final path inside the assembled deploy directory. */
|
|
91
|
+
readonly outputFile: "_worker.js" | "functions/index.func/index.js" | "server.js"
|
|
92
|
+
/** Where the host serves static files from, relative to the deploy directory (`""` = its root). */
|
|
93
|
+
readonly staticDir: "" | "static"
|
|
78
94
|
readonly run: string
|
|
79
95
|
}
|
|
80
96
|
|
|
@@ -106,15 +122,17 @@ export function planBuildTarget(target: BuildTarget, outDir: string): BuildTarge
|
|
|
106
122
|
kind: "static",
|
|
107
123
|
serverTarget: undefined,
|
|
108
124
|
outputFile: undefined,
|
|
125
|
+
staticDir: "",
|
|
109
126
|
run: `static site → ${outDir} (serve the directory with any static host)`,
|
|
110
127
|
}
|
|
111
128
|
}
|
|
112
|
-
if (target === "
|
|
129
|
+
if (target === "cloudflare") {
|
|
113
130
|
return {
|
|
114
131
|
target,
|
|
115
132
|
kind: "server",
|
|
116
133
|
serverTarget: "browser",
|
|
117
134
|
outputFile: "_worker.js",
|
|
135
|
+
staticDir: "",
|
|
118
136
|
run: `Cloudflare Pages → ${outDir} (deploy: wrangler pages deploy ${finalPathSegment(outDir)})`,
|
|
119
137
|
}
|
|
120
138
|
}
|
|
@@ -123,8 +141,10 @@ export function planBuildTarget(target: BuildTarget, outDir: string): BuildTarge
|
|
|
123
141
|
target,
|
|
124
142
|
kind: "server",
|
|
125
143
|
serverTarget: "browser",
|
|
126
|
-
|
|
127
|
-
|
|
144
|
+
// Vercel's Build Output API: `vercel deploy --prebuilt` uploads this tree as it is.
|
|
145
|
+
outputFile: "functions/index.func/index.js",
|
|
146
|
+
staticDir: "static",
|
|
147
|
+
run: `Vercel (Build Output API) → ${outDir} (deploy: vercel deploy --prebuilt)`,
|
|
128
148
|
}
|
|
129
149
|
}
|
|
130
150
|
return {
|
|
@@ -132,6 +152,7 @@ export function planBuildTarget(target: BuildTarget, outDir: string): BuildTarge
|
|
|
132
152
|
kind: "server",
|
|
133
153
|
serverTarget: target === "node" ? "node" : target === "bun" ? "bun" : "browser",
|
|
134
154
|
outputFile: "server.js",
|
|
155
|
+
staticDir: "",
|
|
135
156
|
run: `${target} server → ${outDir} (run: ${target === "node" ? "node" : target} ${finalPathSegment(outDir)}/server.js)`,
|
|
136
157
|
}
|
|
137
158
|
}
|
|
@@ -161,6 +182,8 @@ export interface Bundler {
|
|
|
161
182
|
readonly cssLoading?: CssLoadingMode
|
|
162
183
|
/** Project root (Vite needs it; the Bun strategy ignores it). */
|
|
163
184
|
readonly root?: string
|
|
185
|
+
/** Reviewed false positives of the secret scan. */
|
|
186
|
+
readonly secretExemptions?: readonly SecretExemption[]
|
|
164
187
|
}): Promise<BuildManifest>
|
|
165
188
|
/** Build the server worker → the shared {@link ServerBuild}. */
|
|
166
189
|
buildServer(input: {
|
|
@@ -178,12 +201,17 @@ export interface Bundler {
|
|
|
178
201
|
/** CSS activation policy to bake into the generated server manifest. */
|
|
179
202
|
readonly cssLoading?: CssLoadingMode
|
|
180
203
|
readonly root?: string
|
|
204
|
+
/** Modules the zone rules treat as generated: the adapter module the generated entry imports. */
|
|
205
|
+
readonly generatedFiles?: readonly string[]
|
|
206
|
+
/** The public-env prefix browser code may read (default `"PUBLIC_"`). */
|
|
207
|
+
readonly publicEnvPrefix?: string
|
|
181
208
|
}): Promise<ServerBuild>
|
|
182
209
|
}
|
|
183
210
|
|
|
184
211
|
interface GraphImport {
|
|
185
212
|
readonly path?: string
|
|
186
213
|
readonly original?: string
|
|
214
|
+
readonly external?: boolean
|
|
187
215
|
}
|
|
188
216
|
|
|
189
217
|
interface GraphInput {
|
|
@@ -195,7 +223,11 @@ const basename = (path: string): string => pathBasename(path)
|
|
|
195
223
|
const nodeBuiltinOf = (im: GraphImport): string | undefined => {
|
|
196
224
|
if (im.original?.startsWith("node:")) return im.original
|
|
197
225
|
if (im.path?.startsWith("node:")) return im.path
|
|
198
|
-
|
|
226
|
+
// A bare built-in only counts when the bundler left it external: a bundled `fs` resolved to an
|
|
227
|
+
// installed package (or a polyfill keyed `node:fs`) is handled above or is not a built-in at all.
|
|
228
|
+
// Labeled with the prefix, so `fs/promises` reads the same from either bundler.
|
|
229
|
+
const spec = im.external === true ? (im.original ?? im.path) : undefined
|
|
230
|
+
return spec !== undefined && isBareNodeBuiltin(spec) ? `node:${spec}` : undefined
|
|
199
231
|
}
|
|
200
232
|
|
|
201
233
|
/** One `node:`-builtin-in-the-client finding: the offending builtin, the emitted chunk it landed in,
|
|
@@ -302,29 +334,43 @@ export function detectNodeBuiltinsInClient(
|
|
|
302
334
|
chains.set(builtin, chain)
|
|
303
335
|
return chain
|
|
304
336
|
}
|
|
337
|
+
// (1b) Builtins the bundler left EXTERNAL: the import ships in the importer's chunk but the module
|
|
338
|
+
// is in no output, so (2) can't find it as a chunk member. Bun does this for a dynamic
|
|
339
|
+
// `import("node:fs")` in a browser build; the browser then fails to load it.
|
|
340
|
+
const externalsOf = new Map<string, string[]>()
|
|
341
|
+
for (const [inputKey, input] of Object.entries(inputs)) {
|
|
342
|
+
if (inputKey.startsWith("node:")) continue
|
|
343
|
+
for (const im of input.imports ?? []) {
|
|
344
|
+
if (im.external !== true) continue
|
|
345
|
+
const builtin = nodeBuiltinOf(im)
|
|
346
|
+
if (builtin === undefined) continue
|
|
347
|
+
const list = externalsOf.get(inputKey) ?? []
|
|
348
|
+
if (!list.includes(builtin)) list.push(builtin)
|
|
349
|
+
externalsOf.set(inputKey, list)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
305
352
|
// (2) Locate which emitted chunk each user-imported builtin reached, via the per-output `inputs`.
|
|
306
353
|
const findings = new Map<string, NodeBuiltinFinding>()
|
|
354
|
+
const report = (builtin: string, outputPath: string): void => {
|
|
355
|
+
const chunk = basename(outputPath)
|
|
356
|
+
findings.set(`${builtin}\0${chunk}`, { builtin, chunk, chain: chainFor(builtin) })
|
|
357
|
+
}
|
|
307
358
|
for (const [outputPath, output] of Object.entries(graph.chunks)) {
|
|
308
359
|
for (const inputKey of output.modules) {
|
|
309
|
-
if (
|
|
310
|
-
const
|
|
311
|
-
findings.set(`${inputKey}\0${chunk}`, {
|
|
312
|
-
builtin: inputKey,
|
|
313
|
-
chunk,
|
|
314
|
-
chain: chainFor(inputKey),
|
|
315
|
-
})
|
|
360
|
+
if (userImported.has(inputKey)) report(inputKey, outputPath)
|
|
361
|
+
for (const builtin of externalsOf.get(inputKey) ?? []) report(builtin, outputPath)
|
|
316
362
|
}
|
|
317
363
|
}
|
|
318
364
|
return [...findings.values()].sort((a, b) =>
|
|
319
|
-
a.builtin === b.builtin ? a.chunk
|
|
365
|
+
a.builtin === b.builtin ? codeUnitOrder(a.chunk, b.chunk) : codeUnitOrder(a.builtin, b.builtin),
|
|
320
366
|
)
|
|
321
367
|
}
|
|
322
368
|
|
|
323
369
|
// ---------------------------------------------------------------------------------------------------
|
|
324
|
-
// `
|
|
370
|
+
// `backend-only` poison-import guard (§3.3/§5.1). The complement to the zones + the
|
|
325
371
|
// node-builtin guard: a module of PURE server logic with NO `node:` import (a secret-bearing constant,
|
|
326
372
|
// a server-only API call) that an author wants to FAIL LOUD if it reaches the client opts in with a
|
|
327
|
-
// side-effect `import "@nifrajs/web/
|
|
373
|
+
// side-effect `import "@nifrajs/web/backend-only"` (Next's `import "server-only"`). On the SERVER build
|
|
328
374
|
// the marker is an empty no-op; the CLIENT build detects - via the SAME Bun metafile graph the
|
|
329
375
|
// node-builtin guard walks - any module that imports the marker AND lands in a client chunk, and fails
|
|
330
376
|
// the build with the import chain. Graph-based (never the emitted text), so it survives minification.
|
|
@@ -332,18 +378,18 @@ export function detectNodeBuiltinsInClient(
|
|
|
332
378
|
|
|
333
379
|
/** The marker specifier an author imports to opt a module into the client-leak guard. Matched on the
|
|
334
380
|
* import edge's *as-written* `original` first (the robust signal: it's exactly what the author typed,
|
|
335
|
-
* before Bun resolves it to `src/
|
|
336
|
-
export const SERVER_ONLY_MARKER = "@nifrajs/web/
|
|
381
|
+
* before Bun resolves it to `src/backend-only.ts` / `dist/backend-only.js`). */
|
|
382
|
+
export const SERVER_ONLY_MARKER = "@nifrajs/web/backend-only"
|
|
337
383
|
|
|
338
384
|
const isServerOnlyMarkerImport = (im: GraphImport): boolean => {
|
|
339
385
|
if (im.original === SERVER_ONLY_MARKER) return true
|
|
340
|
-
return im.path !== undefined && /(^|\/)
|
|
386
|
+
return im.path !== undefined && /(^|\/)backend-only\.[cm]?[jt]s$/.test(im.path)
|
|
341
387
|
}
|
|
342
388
|
|
|
343
|
-
/** True when an INPUT graph key is the marker module file itself (`…/
|
|
389
|
+
/** True when an INPUT graph key is the marker module file itself (`…/backend-only.{ts,js}` under web).
|
|
344
390
|
* Excluded from the "marked" set - the marker is the import target, not an opt-in module. */
|
|
345
391
|
const isServerOnlyMarkerModule = (inputKey: string): boolean =>
|
|
346
|
-
/(^|\/)
|
|
392
|
+
/(^|\/)backend-only\.[cm]?[jt]s$/.test(inputKey)
|
|
347
393
|
|
|
348
394
|
/** One `server-only`-module-in-the-client finding: the offending module (the as-written marker-import
|
|
349
395
|
* chain's tail before the marker), the emitted chunk it landed in, and the shortest USER-module import
|
|
@@ -398,7 +444,7 @@ function shortestServerOnlyChain(
|
|
|
398
444
|
): string[] {
|
|
399
445
|
// The label for the marked module's tail: its as-written specifier (filled when we cross the edge
|
|
400
446
|
// that reaches it) suffixed with `(marked server-only)`; the entry case uses the entry key itself.
|
|
401
|
-
const tail = (label: string): string => `${label} (marked
|
|
447
|
+
const tail = (label: string): string => `${label} (marked backend-only)`
|
|
402
448
|
// An entry that is ITSELF the marked module - the chain is just that one node.
|
|
403
449
|
if (entryInputs.includes(markedModule)) return [tail(markedModule)]
|
|
404
450
|
const seen = new Set(entryInputs)
|
|
@@ -427,7 +473,7 @@ function shortestServerOnlyChain(
|
|
|
427
473
|
|
|
428
474
|
/**
|
|
429
475
|
* Scan a build's metafile for any module that opts into the `server-only` marker (a side-effect
|
|
430
|
-
* `import "@nifrajs/web/
|
|
476
|
+
* `import "@nifrajs/web/backend-only"`) yet landed in a CLIENT output chunk, returning a sorted, deduped
|
|
431
477
|
* list of {@link ServerOnlyFinding}s. Mirrors {@link detectNodeBuiltinsInClient}: it reads the SAME
|
|
432
478
|
* graph facts - which inputs import the marker (the "marked" modules), which chunk each landed in (the
|
|
433
479
|
* per-output `inputs`), and the shortest import chain from a user entry to it. The marker module ITSELF
|
|
@@ -466,17 +512,28 @@ export function detectServerOnlyInClient(
|
|
|
466
512
|
}
|
|
467
513
|
// (2) Locate which emitted chunk each marked module reached, via the per-output `inputs`.
|
|
468
514
|
const findings = new Map<string, ServerOnlyFinding>()
|
|
515
|
+
const placed = new Set<string>()
|
|
469
516
|
for (const [outputPath, output] of Object.entries(graph.chunks)) {
|
|
470
517
|
for (const inputKey of output.modules) {
|
|
471
518
|
if (!marked.has(inputKey)) continue
|
|
472
519
|
const chunk = basename(outputPath)
|
|
520
|
+
placed.add(inputKey)
|
|
473
521
|
findings.set(`${inputKey}\0${chunk}`, { chunk, chain: chainFor(inputKey) })
|
|
474
522
|
}
|
|
475
523
|
}
|
|
524
|
+
// A marked module the build loaded but no chunk lists: the bundler inlined what it exports (a
|
|
525
|
+
// constant ships without its module) or dropped it. The import crossed the boundary either way.
|
|
526
|
+
for (const inputKey of marked) {
|
|
527
|
+
if (placed.has(inputKey)) continue
|
|
528
|
+
findings.set(`${inputKey}\0`, {
|
|
529
|
+
chunk: "none, inlined or shaken out",
|
|
530
|
+
chain: chainFor(inputKey),
|
|
531
|
+
})
|
|
532
|
+
}
|
|
476
533
|
return [...findings.values()].sort((a, b) => {
|
|
477
534
|
const am = a.chain[a.chain.length - 1] ?? ""
|
|
478
535
|
const bm = b.chain[b.chain.length - 1] ?? ""
|
|
479
|
-
return am === bm ? a.chunk
|
|
536
|
+
return am === bm ? codeUnitOrder(a.chunk, b.chunk) : codeUnitOrder(am, bm)
|
|
480
537
|
})
|
|
481
538
|
}
|
|
482
539
|
|
|
@@ -498,9 +555,8 @@ export function formatNodeBuiltinLeak(
|
|
|
498
555
|
: ` - ${finding.builtin} reached the client bundle via ${finding.chunk}`,
|
|
499
556
|
)
|
|
500
557
|
return (
|
|
501
|
-
`[nifra/web] Node built-in(s) in the client bundle -
|
|
502
|
-
`
|
|
503
|
-
`top level):\n${lines.join("\n")}`
|
|
558
|
+
`[nifra/web] Node built-in(s) in the client bundle - built-ins run on the server only: import ` +
|
|
559
|
+
`them in a route's backend half (x.backend.ts) or under backend/, never in browser code:\n${lines.join("\n")}`
|
|
504
560
|
)
|
|
505
561
|
}
|
|
506
562
|
|
|
@@ -511,14 +567,13 @@ export function formatServerOnlyLeak(
|
|
|
511
567
|
if (findings.length === 0) return undefined
|
|
512
568
|
const lines = findings.map((finding) =>
|
|
513
569
|
finding.chain.length > 1
|
|
514
|
-
? ` -
|
|
515
|
-
: ` -
|
|
570
|
+
? ` - backend-only module reached the client bundle via ${finding.chain.join(" → ")} (chunk: ${finding.chunk})`
|
|
571
|
+
: ` - backend-only module reached the client bundle via ${finding.chunk}`,
|
|
516
572
|
)
|
|
517
573
|
return (
|
|
518
|
-
`[nifra/web]
|
|
519
|
-
`\`import "${SERVER_ONLY_MARKER}"\` reached the browser. Move it
|
|
520
|
-
`
|
|
521
|
-
`to the client:\n${lines.join("\n")}`
|
|
574
|
+
`[nifra/web] backend-only module(s) in the client bundle - a module marked ` +
|
|
575
|
+
`\`import "${SERVER_ONLY_MARKER}"\` reached the browser. Move it under backend/ and reach it ` +
|
|
576
|
+
`from a route's backend half (x.backend.ts) or a *.fn.ts server function:\n${lines.join("\n")}`
|
|
522
577
|
)
|
|
523
578
|
}
|
|
524
579
|
|
|
@@ -555,7 +610,7 @@ export interface SizeReport {
|
|
|
555
610
|
*/
|
|
556
611
|
export function aggregateSizeReport(chunks: readonly ChunkSize[]): SizeReport {
|
|
557
612
|
const sorted = [...chunks].sort(
|
|
558
|
-
(a, b) => b.gzip - a.gzip || b.bytes - a.bytes || a.name
|
|
613
|
+
(a, b) => b.gzip - a.gzip || b.bytes - a.bytes || codeUnitOrder(a.name, b.name),
|
|
559
614
|
)
|
|
560
615
|
let totalBytes = 0
|
|
561
616
|
let totalGzip = 0
|
package/src/build-vite.ts
CHANGED
|
@@ -44,12 +44,17 @@ import {
|
|
|
44
44
|
collectDevelopmentParityInput,
|
|
45
45
|
} from "./internal/parity.ts"
|
|
46
46
|
import { vitePublicEnvPrefix } from "./internal/server-boundary.ts"
|
|
47
|
+
import { unsupportedBuiltin } from "./internal/target-compat.ts"
|
|
47
48
|
import { importVite, isViteUnresolved } from "./internal/vite-import.ts"
|
|
48
49
|
import { scopedName } from "./plugins/css-modules.ts"
|
|
49
50
|
import { reproduciblePath } from "./plugins/kit.ts"
|
|
50
|
-
import {
|
|
51
|
+
import {
|
|
52
|
+
viteAssetUrlGuard,
|
|
53
|
+
viteBareBuiltinExternal,
|
|
54
|
+
viteLeakGuard,
|
|
55
|
+
viteServerZoneGuard,
|
|
56
|
+
} from "./plugins/vite-leak-guard.ts"
|
|
51
57
|
import { viteServerFnStub } from "./plugins/vite-server-fn.ts"
|
|
52
|
-
import { viteServerOnlyEmpty } from "./plugins/vite-server-only.ts"
|
|
53
58
|
|
|
54
59
|
// ---------------------------------------------------------------------------------------------------
|
|
55
60
|
// Structural Vite typings - no hard `vite` dependency (mirrors vite.ts). Only the build API is used.
|
|
@@ -174,6 +179,8 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
174
179
|
...routeManifest.routes.map((r) => r.file),
|
|
175
180
|
...Object.values(routeManifest.layouts).map((l) => l.file),
|
|
176
181
|
...(routeManifest.notFound ? [routeManifest.notFound.file] : []),
|
|
182
|
+
// A nested `_404` is an entry only for its stylesheet: it renders on the server, unhydrated.
|
|
183
|
+
...Object.values(routeManifest.notFounds ?? {}).map((page) => page.file),
|
|
177
184
|
]),
|
|
178
185
|
].sort()
|
|
179
186
|
|
|
@@ -201,7 +208,28 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
201
208
|
const buildEnv = (typeof Bun !== "undefined" ? Bun.env : undefined) ?? process.env
|
|
202
209
|
const publicDefines = publicEnvDefines(options.publicEnvPrefix ?? "PUBLIC_", buildEnv)
|
|
203
210
|
const vite = await loadVite()
|
|
204
|
-
|
|
211
|
+
// A worker is bundled by its own sub-build the main graph never sees, so it gets its own guard; the
|
|
212
|
+
// main guard then accepts the worker chunks that guard verified.
|
|
213
|
+
const verified = new Set<string>()
|
|
214
|
+
const exemptions = options.secretExemptions
|
|
215
|
+
const guardOptions = {
|
|
216
|
+
appRoot: dirname(routesDir),
|
|
217
|
+
routesDir,
|
|
218
|
+
root,
|
|
219
|
+
outDir: resolvePath(outDir),
|
|
220
|
+
generatedFiles: [entryFile],
|
|
221
|
+
verified,
|
|
222
|
+
...(options.publicEnvPrefix !== undefined ? { publicEnvPrefix: options.publicEnvPrefix } : {}),
|
|
223
|
+
secrets: { env: buildEnv, ...(exemptions ? { exemptions } : {}) },
|
|
224
|
+
}
|
|
225
|
+
// nifra copies `public/` after the build; the main guard scans it with the bundle.
|
|
226
|
+
const publicDir = options.publicDir === false ? undefined : (options.publicDir ?? "public")
|
|
227
|
+
const leakGuard = viteLeakGuard({
|
|
228
|
+
...guardOptions,
|
|
229
|
+
secrets: { ...guardOptions.secrets, ...(publicDir !== undefined ? { publicDir } : {}) },
|
|
230
|
+
})
|
|
231
|
+
const assetUrlGuard = viteAssetUrlGuard(guardOptions)
|
|
232
|
+
const workerGuards: { readonly leak?: string | undefined }[] = []
|
|
205
233
|
try {
|
|
206
234
|
await withSerializedNodeEnv(mode, () =>
|
|
207
235
|
vite.build({
|
|
@@ -235,7 +263,17 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
235
263
|
scopedName(reproduciblePath(filename), name),
|
|
236
264
|
},
|
|
237
265
|
},
|
|
238
|
-
|
|
266
|
+
// First, so a bare built-in is named before Vite turns it into an anonymous stub.
|
|
267
|
+
// The asset URL guard last, so it reads each module after any framework plugin made it JavaScript.
|
|
268
|
+
plugins: [viteBareBuiltinExternal(), ...(options.vitePlugins ?? []), assetUrlGuard],
|
|
269
|
+
worker: {
|
|
270
|
+
plugins: () => {
|
|
271
|
+
const guard = viteLeakGuard(guardOptions)
|
|
272
|
+
const urlGuard = viteAssetUrlGuard(guardOptions)
|
|
273
|
+
workerGuards.push(guard, urlGuard)
|
|
274
|
+
return [viteBareBuiltinExternal(), viteServerFnStub(), guard, urlGuard]
|
|
275
|
+
},
|
|
276
|
+
},
|
|
239
277
|
build: {
|
|
240
278
|
outDir,
|
|
241
279
|
emptyOutDir: false, // buildTargetWith owns outDir lifecycle; never let Vite wipe sibling files
|
|
@@ -251,7 +289,7 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
251
289
|
external: [/^node:/],
|
|
252
290
|
input,
|
|
253
291
|
// The leak guard is a Rollup plugin - last, so it sees the final graph.
|
|
254
|
-
plugins: [viteServerFnStub(),
|
|
292
|
+
plugins: [viteServerFnStub(), leakGuard],
|
|
255
293
|
output: {
|
|
256
294
|
entryFileNames: "[name]-[hash].js",
|
|
257
295
|
chunkFileNames: "[name]-[hash].js",
|
|
@@ -267,7 +305,11 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
267
305
|
// that construction fails, replacing a precise "node:crypto reached the client bundle" with an
|
|
268
306
|
// internal complaint naming nothing. Raising it here puts the message beyond anything that can
|
|
269
307
|
// rewrite it; the bundler's error is kept as `cause` for the rest of the context.
|
|
270
|
-
|
|
308
|
+
const leak =
|
|
309
|
+
assetUrlGuard.leak ??
|
|
310
|
+
leakGuard.leak ??
|
|
311
|
+
workerGuards.find((guard) => guard.leak !== undefined)?.leak
|
|
312
|
+
if (leak !== undefined) throw new Error(leak, { cause: error })
|
|
271
313
|
throw error
|
|
272
314
|
} finally {
|
|
273
315
|
rmSync(entryDir, { recursive: true, force: true })
|
|
@@ -336,6 +378,12 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
336
378
|
if (css.length > 0 && cssCodeSplit) {
|
|
337
379
|
for (const route of routeManifest.routes) routeStyles[route.id] = stylesFor(chainFiles(route))
|
|
338
380
|
if (routeManifest.notFound) routeStyles._404 = stylesFor([routeManifest.notFound.file])
|
|
381
|
+
for (const [id, page] of Object.entries(routeManifest.notFounds ?? {})) {
|
|
382
|
+
routeStyles[id] = stylesFor([
|
|
383
|
+
...page.layoutIds.map((layoutId) => routeManifest.layouts[layoutId]?.file ?? ""),
|
|
384
|
+
page.file,
|
|
385
|
+
])
|
|
386
|
+
}
|
|
339
387
|
}
|
|
340
388
|
|
|
341
389
|
// assets - every emitted file + stylesheet across the manifest (chunks, entries, css).
|
|
@@ -346,7 +394,6 @@ export async function buildClientVite(options: BuildClientViteOptions): Promise<
|
|
|
346
394
|
for (const asset of entry.assets ?? []) assets.add(url(asset))
|
|
347
395
|
}
|
|
348
396
|
|
|
349
|
-
const publicDir = options.publicDir === false ? undefined : (options.publicDir ?? "public")
|
|
350
397
|
const publicFiles =
|
|
351
398
|
publicDir !== undefined && existsSync(publicDir) ? await copyPublicDir(publicDir, outDir) : []
|
|
352
399
|
|
|
@@ -385,6 +432,10 @@ export interface BuildServerViteOptions {
|
|
|
385
432
|
readonly target?: "browser" | "node" | "bun"
|
|
386
433
|
/** Vite project root (default: the parent of `routesDir`). */
|
|
387
434
|
readonly root?: string
|
|
435
|
+
/** Modules the build generated besides the entry and manifest (a target's adapter import). */
|
|
436
|
+
readonly generatedFiles?: readonly string[]
|
|
437
|
+
/** The public-env prefix browser code may read (default `"PUBLIC_"`). */
|
|
438
|
+
readonly publicEnvPrefix?: string
|
|
388
439
|
}
|
|
389
440
|
|
|
390
441
|
interface EdgeBundleChunk {
|
|
@@ -431,12 +482,13 @@ function edgeBuiltinGuard(): EdgeGuardPlugin {
|
|
|
431
482
|
for (const output of Object.values(bundle)) {
|
|
432
483
|
if (output.type !== "chunk") continue
|
|
433
484
|
for (const specifier of [...(output.imports ?? []), ...(output.dynamicImports ?? [])]) {
|
|
434
|
-
if (specifier
|
|
485
|
+
if (unsupportedBuiltin(specifier, "browser")) builtins.add(specifier)
|
|
435
486
|
}
|
|
436
487
|
for (const id of output.moduleIds ?? []) {
|
|
437
488
|
const info = this.getModuleInfo(id)
|
|
438
489
|
const imports = [...(info?.importedIds ?? []), ...(info?.dynamicallyImportedIds ?? [])]
|
|
439
|
-
if (imports.some((specifier) => specifier
|
|
490
|
+
if (imports.some((specifier) => unsupportedBuiltin(specifier, "browser")))
|
|
491
|
+
importers.add(id)
|
|
440
492
|
}
|
|
441
493
|
}
|
|
442
494
|
if (builtins.size === 0) return
|
|
@@ -497,6 +549,16 @@ export async function buildServerVite(options: BuildServerViteOptions): Promise<
|
|
|
497
549
|
const mode = options.minify === false ? "development" : "production"
|
|
498
550
|
const vite = await loadVite()
|
|
499
551
|
const edgeGuard = edgeBuiltinGuard()
|
|
552
|
+
const zoneGuard = viteServerZoneGuard({
|
|
553
|
+
appRoot: root,
|
|
554
|
+
routesDir: resolvePath(routesDir),
|
|
555
|
+
generatedFiles: [
|
|
556
|
+
serverEntry,
|
|
557
|
+
join(entryDir, manifestFile),
|
|
558
|
+
...(options.generatedFiles ?? []),
|
|
559
|
+
].map((file) => resolvePath(file)),
|
|
560
|
+
...(options.publicEnvPrefix !== undefined ? { publicEnvPrefix: options.publicEnvPrefix } : {}),
|
|
561
|
+
})
|
|
500
562
|
try {
|
|
501
563
|
await withSerializedNodeEnv(mode, () =>
|
|
502
564
|
vite.build({
|
|
@@ -525,7 +587,7 @@ export async function buildServerVite(options: BuildServerViteOptions): Promise<
|
|
|
525
587
|
// Keep builtins external so Node/Bun use their native implementations. Edge builds add a
|
|
526
588
|
// generateBundle guard below, so an external specifier can never silently ship to workerd.
|
|
527
589
|
external: [/^node:/],
|
|
528
|
-
...(edge ?
|
|
590
|
+
plugins: [...(edge ? [edgeGuard] : []), zoneGuard],
|
|
529
591
|
// ONE self-contained `server.js`. `inlineDynamicImports` forces the ENTRY chunk to absorb
|
|
530
592
|
// every module - the app, the adapter, react/react-dom, @nifrajs/* - so no second chunk is
|
|
531
593
|
// emitted. It is NOT redundant with `ssr.noExternal`: `noExternal` decides what gets bundled,
|
|
@@ -550,7 +612,8 @@ export async function buildServerVite(options: BuildServerViteOptions): Promise<
|
|
|
550
612
|
} catch (error) {
|
|
551
613
|
// Re-raise the guard's own message from here, where no bundler error-reporting path can rewrite it
|
|
552
614
|
// (see the same handling in buildClientVite).
|
|
553
|
-
|
|
615
|
+
const leak = zoneGuard.leak ?? edgeGuard.leak
|
|
616
|
+
if (leak !== undefined) throw new Error(leak, { cause: error })
|
|
554
617
|
throw error
|
|
555
618
|
}
|
|
556
619
|
|
|
@@ -578,6 +641,7 @@ export const viteBundler: Bundler = {
|
|
|
578
641
|
...(input.cssLoading !== undefined ? { cssLoading: input.cssLoading } : {}),
|
|
579
642
|
...(input.publicDir !== undefined ? { publicDir: input.publicDir } : {}),
|
|
580
643
|
...(input.publicEnvPrefix !== undefined ? { publicEnvPrefix: input.publicEnvPrefix } : {}),
|
|
644
|
+
...(input.secretExemptions !== undefined ? { secretExemptions: input.secretExemptions } : {}),
|
|
581
645
|
...(input.root ? { root: input.root } : {}),
|
|
582
646
|
}),
|
|
583
647
|
buildServer: (input) =>
|
|
@@ -593,6 +657,8 @@ export const viteBundler: Bundler = {
|
|
|
593
657
|
...(input.define ? { define: input.define } : {}),
|
|
594
658
|
...(input.cssLoading !== undefined ? { cssLoading: input.cssLoading } : {}),
|
|
595
659
|
...(input.root ? { root: input.root } : {}),
|
|
660
|
+
...(input.generatedFiles !== undefined ? { generatedFiles: input.generatedFiles } : {}),
|
|
661
|
+
...(input.publicEnvPrefix !== undefined ? { publicEnvPrefix: input.publicEnvPrefix } : {}),
|
|
596
662
|
}),
|
|
597
663
|
}
|
|
598
664
|
|