vinext 0.1.0 → 0.1.2
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 +2 -5
- package/dist/build/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +33 -1
- package/dist/build/client-build-config.js +66 -1
- package/dist/check.js +4 -3
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +11 -2
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +31 -5
- package/dist/config/config-matchers.js +50 -3
- package/dist/config/next-config.d.ts +29 -3
- package/dist/config/next-config.js +32 -2
- package/dist/deploy.js +47 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +61 -5
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +16 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +233 -280
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +8 -4
- package/dist/plugins/optimize-imports.js +16 -12
- package/dist/plugins/postcss.js +18 -14
- package/dist/plugins/require-context.d.ts +6 -0
- package/dist/plugins/require-context.js +184 -0
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +35 -2
- package/dist/routing/app-route-graph.js +179 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +16 -1
- package/dist/server/api-handler.js +4 -0
- package/dist/server/app-browser-entry.js +155 -215
- package/dist/server/app-browser-error.d.ts +4 -1
- package/dist/server/app-browser-error.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-interception-context.d.ts +2 -1
- package/dist/server/app-browser-interception-context.js +15 -2
- package/dist/server/app-browser-navigation-controller.d.ts +13 -2
- package/dist/server/app-browser-navigation-controller.js +83 -4
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-state.d.ts +3 -0
- package/dist/server/app-browser-state.js +10 -10
- package/dist/server/app-browser-visible-commit.js +10 -8
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -1
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +22 -1
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +45 -21
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +14 -0
- package/dist/server/app-page-dispatch.js +21 -6
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +58 -17
- package/dist/server/app-page-execution.d.ts +1 -1
- package/dist/server/app-page-execution.js +32 -17
- package/dist/server/app-page-render.d.ts +7 -1
- package/dist/server/app-page-render.js +11 -16
- package/dist/server/app-page-request.d.ts +9 -6
- package/dist/server/app-page-request.js +14 -10
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +10 -8
- package/dist/server/app-page-stream.d.ts +37 -7
- package/dist/server/app-page-stream.js +36 -6
- package/dist/server/app-pages-bridge.d.ts +16 -0
- package/dist/server/app-pages-bridge.js +23 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +15 -3
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +5 -4
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +20 -1
- package/dist/server/app-rsc-route-matching.js +29 -4
- package/dist/server/app-server-action-execution.d.ts +22 -1
- package/dist/server/app-server-action-execution.js +73 -12
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +19 -3
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +97 -43
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +62 -1
- package/dist/server/navigation-planner.js +193 -3
- package/dist/server/navigation-trace.d.ts +12 -2
- package/dist/server/navigation-trace.js +11 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +14 -3
- package/dist/server/pages-api-route.js +6 -1
- package/dist/server/pages-asset-tags.d.ts +15 -4
- package/dist/server/pages-asset-tags.js +18 -12
- package/dist/server/pages-data-route.js +5 -1
- package/dist/server/pages-node-compat.d.ts +5 -11
- package/dist/server/pages-node-compat.js +175 -118
- package/dist/server/pages-page-data.d.ts +38 -7
- package/dist/server/pages-page-data.js +64 -18
- package/dist/server/pages-page-handler.d.ts +10 -2
- package/dist/server/pages-page-handler.js +49 -20
- package/dist/server/pages-page-response.d.ts +55 -2
- package/dist/server/pages-page-response.js +74 -6
- package/dist/server/pages-readiness.d.ts +36 -0
- package/dist/server/pages-readiness.js +21 -0
- package/dist/server/pages-request-pipeline.d.ts +113 -0
- package/dist/server/pages-request-pipeline.js +230 -0
- package/dist/server/pages-revalidate.d.ts +15 -0
- package/dist/server/pages-revalidate.js +19 -0
- package/dist/server/prod-server.d.ts +45 -3
- package/dist/server/prod-server.js +182 -234
- package/dist/server/socket-error-backstop.d.ts +19 -1
- package/dist/server/socket-error-backstop.js +77 -4
- package/dist/shims/app-router-scroll.js +22 -4
- package/dist/shims/cache-runtime.js +39 -2
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +77 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +17 -7
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +22 -1
- package/dist/shims/fetch-cache.js +28 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +37 -1
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +10 -6
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/link-status-registry.d.ts +43 -0
- package/dist/shims/internal/link-status-registry.js +42 -0
- package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
- package/dist/shims/internal/route-pattern-for-warning.js +40 -0
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/link.js +20 -6
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +9 -18
- package/dist/shims/navigation.js +96 -23
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +2 -0
- package/dist/shims/router.d.ts +6 -3
- package/dist/shims/router.js +156 -22
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +17 -1
- package/dist/shims/server.js +31 -6
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/client-build-manifest.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +41 -6
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +5 -1
- package/package.json +6 -2
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { resolveAssetsDir } from "./asset-prefix.js";
|
|
2
|
+
import { manifestFileWithAssetPrefix, manifestFileWithBase } from "./manifest-paths.js";
|
|
3
|
+
import { findClientEntryFile, findPagesClientEntryFile, readClientBuildManifest } from "./client-build-manifest.js";
|
|
4
|
+
import { findClientEntryFileFromVinextManifest, findPagesClientEntryFileFromVinextManifest, readClientEntryManifest } from "./client-entry-manifest.js";
|
|
5
|
+
import { computeDynamicImportPreloads, computeLazyChunks, dynamicImportPreloadsWithBase } from "./lazy-chunks.js";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
//#region src/utils/client-runtime-metadata.ts
|
|
8
|
+
/**
|
|
9
|
+
* Read the client build manifest and compute runtime metadata used by
|
|
10
|
+
* Cloudflare worker entry injection and Node production server startup.
|
|
11
|
+
*
|
|
12
|
+
* - `lazyChunks` — chunks only reachable through dynamic `import()`, excluded
|
|
13
|
+
* from modulepreload hints.
|
|
14
|
+
* - `dynamicPreloads` — per-module JS/CSS files for rendered `next/dynamic()`
|
|
15
|
+
* boundaries, injected as preload links during SSR.
|
|
16
|
+
* - `clientEntryFile` — the client entry chunk filename (optional, only
|
|
17
|
+
* needed for Pages Router).
|
|
18
|
+
*
|
|
19
|
+
* All file paths are normalised with the configured `assetBase` (basePath)
|
|
20
|
+
* and `assetPrefix`.
|
|
21
|
+
*/
|
|
22
|
+
function computeClientRuntimeMetadata(opts) {
|
|
23
|
+
const buildManifest = readClientBuildManifest(path.join(opts.clientDir, ".vite", "manifest.json"));
|
|
24
|
+
const metadata = {};
|
|
25
|
+
if (opts.includeClientEntry) {
|
|
26
|
+
const clientEntryManifest = readClientEntryManifest(opts.clientDir);
|
|
27
|
+
const entryOptions = {
|
|
28
|
+
buildManifest,
|
|
29
|
+
clientDir: opts.clientDir,
|
|
30
|
+
assetsSubdir: resolveAssetsDir(opts.assetPrefix),
|
|
31
|
+
assetBase: opts.assetBase
|
|
32
|
+
};
|
|
33
|
+
const entry = opts.includeClientEntry === "pages-client-entry" ? findPagesClientEntryFileFromVinextManifest(clientEntryManifest, opts.assetBase) ?? findPagesClientEntryFile(entryOptions) : findClientEntryFileFromVinextManifest(clientEntryManifest, opts.assetBase) ?? findClientEntryFile(entryOptions);
|
|
34
|
+
if (entry) metadata.clientEntryFile = entry;
|
|
35
|
+
}
|
|
36
|
+
if (!buildManifest) return metadata;
|
|
37
|
+
const lazyChunks = computeLazyChunks(buildManifest).map((file) => manifestFileWithBase(file, opts.assetBase));
|
|
38
|
+
if (lazyChunks.length > 0) metadata.lazyChunks = lazyChunks;
|
|
39
|
+
const dynamicPreloads = dynamicImportPreloadsWithBase(computeDynamicImportPreloads(buildManifest), (file) => manifestFileWithAssetPrefix(file, opts.assetBase, opts.assetPrefix));
|
|
40
|
+
if (Object.keys(dynamicPreloads).length > 0) metadata.dynamicPreloads = dynamicPreloads;
|
|
41
|
+
return metadata;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Serialize runtime metadata into the `globalThis.__VINEXT_*` assignment script
|
|
45
|
+
* that the Cloudflare `closeBundle` hook prepends to the worker entry. Returns
|
|
46
|
+
* `""` when there is nothing to inject.
|
|
47
|
+
*
|
|
48
|
+
* Both the App Router and Pages Router closeBundle paths call this (and the
|
|
49
|
+
* deploy tests mirror it), so the injection shape stays in one place. The caller
|
|
50
|
+
* decides which fields to pass — e.g. App Router only forwards `clientEntryFile`
|
|
51
|
+
* for mixed app+pages builds (where `computeClientRuntimeMetadata` was asked for
|
|
52
|
+
* the Pages client entry); pure App Router leaves it undefined.
|
|
53
|
+
*/
|
|
54
|
+
function buildRuntimeGlobalsScript(input) {
|
|
55
|
+
const globals = [];
|
|
56
|
+
if (input.clientEntryFile) globals.push(`globalThis.__VINEXT_CLIENT_ENTRY__ = ${JSON.stringify(input.clientEntryFile)};`);
|
|
57
|
+
if (input.ssrManifest && Object.keys(input.ssrManifest).length > 0) globals.push(`globalThis.__VINEXT_SSR_MANIFEST__ = ${JSON.stringify(input.ssrManifest)};`);
|
|
58
|
+
if (input.lazyChunks && input.lazyChunks.length > 0) globals.push(`globalThis.__VINEXT_LAZY_CHUNKS__ = ${JSON.stringify(input.lazyChunks)};`);
|
|
59
|
+
if (input.dynamicPreloads && Object.keys(input.dynamicPreloads).length > 0) globals.push(`globalThis.__VINEXT_DYNAMIC_PRELOADS__ = ${JSON.stringify(input.dynamicPreloads)};`);
|
|
60
|
+
return globals.join("\n");
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { buildRuntimeGlobalsScript, computeClientRuntimeMetadata };
|
package/dist/utils/hash.d.ts
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* FNV-1a hash producing a 64-bit result (two 32-bit rounds with different seeds).
|
|
4
4
|
* Used for deterministic key generation where collisions must be rare.
|
|
5
|
+
*
|
|
6
|
+
* This is a vinext-internal format: nothing outside vinext ever compares
|
|
7
|
+
* these values, so the algorithm only needs to be deterministic. For values
|
|
8
|
+
* that must be byte-for-byte identical to what Next.js emits (ETags), use
|
|
9
|
+
* `fnv1a52` below instead — the two are NOT interchangeable.
|
|
5
10
|
*/
|
|
6
11
|
declare function fnv1a64(input: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* FNV-1a hash producing a 52-bit result, a byte-for-byte port of Next.js's
|
|
14
|
+
* `fnv1a52` in packages/next/src/server/lib/etag.ts (itself derived from
|
|
15
|
+
* fnv-plus). Used for ETag generation, where matching Next.js's exact output
|
|
16
|
+
* matters: clients and CDNs holding `If-None-Match` values from a Next.js
|
|
17
|
+
* deployment keep revalidating (304) against vinext for unchanged payloads.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately separate from `fnv1a64` above — that one is a vinext-internal
|
|
20
|
+
* key format and produces different values. Do not swap one for the other.
|
|
21
|
+
*/
|
|
22
|
+
declare function fnv1a52(str: string): number;
|
|
7
23
|
//#endregion
|
|
8
|
-
export { fnv1a64 };
|
|
24
|
+
export { fnv1a52, fnv1a64 };
|
package/dist/utils/hash.js
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* FNV-1a hash producing a 64-bit result (two 32-bit rounds with different seeds).
|
|
4
4
|
* Used for deterministic key generation where collisions must be rare.
|
|
5
|
+
*
|
|
6
|
+
* This is a vinext-internal format: nothing outside vinext ever compares
|
|
7
|
+
* these values, so the algorithm only needs to be deterministic. For values
|
|
8
|
+
* that must be byte-for-byte identical to what Next.js emits (ETags), use
|
|
9
|
+
* `fnv1a52` below instead — the two are NOT interchangeable.
|
|
5
10
|
*/
|
|
6
11
|
function fnv1a64(input) {
|
|
7
12
|
let h1 = 2166136261;
|
|
@@ -16,5 +21,35 @@ function fnv1a64(input) {
|
|
|
16
21
|
}
|
|
17
22
|
return h1.toString(16).padStart(8, "0") + h2.toString(16).padStart(8, "0");
|
|
18
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* FNV-1a hash producing a 52-bit result, a byte-for-byte port of Next.js's
|
|
26
|
+
* `fnv1a52` in packages/next/src/server/lib/etag.ts (itself derived from
|
|
27
|
+
* fnv-plus). Used for ETag generation, where matching Next.js's exact output
|
|
28
|
+
* matters: clients and CDNs holding `If-None-Match` values from a Next.js
|
|
29
|
+
* deployment keep revalidating (304) against vinext for unchanged payloads.
|
|
30
|
+
*
|
|
31
|
+
* Deliberately separate from `fnv1a64` above — that one is a vinext-internal
|
|
32
|
+
* key format and produces different values. Do not swap one for the other.
|
|
33
|
+
*/
|
|
34
|
+
function fnv1a52(str) {
|
|
35
|
+
const len = str.length;
|
|
36
|
+
let i = 0, t0 = 0, v0 = 8997, t1 = 0, v1 = 33826, t2 = 0, v2 = 40164, t3 = 0, v3 = 52210;
|
|
37
|
+
while (i < len) {
|
|
38
|
+
v0 ^= str.charCodeAt(i++);
|
|
39
|
+
t0 = v0 * 435;
|
|
40
|
+
t1 = v1 * 435;
|
|
41
|
+
t2 = v2 * 435;
|
|
42
|
+
t3 = v3 * 435;
|
|
43
|
+
t2 += v0 << 8;
|
|
44
|
+
t3 += v1 << 8;
|
|
45
|
+
t1 += t0 >>> 16;
|
|
46
|
+
v0 = t0 & 65535;
|
|
47
|
+
t2 += t1 >>> 16;
|
|
48
|
+
v1 = t1 & 65535;
|
|
49
|
+
v3 = t3 + (t2 >>> 16) & 65535;
|
|
50
|
+
v2 = t2 & 65535;
|
|
51
|
+
}
|
|
52
|
+
return (v3 & 15) * 281474976710656 + v2 * 4294967296 + v1 * 65536 + (v0 ^ v3 >> 4);
|
|
53
|
+
}
|
|
19
54
|
//#endregion
|
|
20
|
-
export { fnv1a64 };
|
|
55
|
+
export { fnv1a52, fnv1a64 };
|
|
@@ -29,5 +29,31 @@ type BuildManifestChunk = {
|
|
|
29
29
|
* should be excluded from modulepreload hints.
|
|
30
30
|
*/
|
|
31
31
|
declare function computeLazyChunks(buildManifest: Record<string, BuildManifestChunk>): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Compute the production preload files for each module referenced by a
|
|
34
|
+
* `next/dynamic()` boundary.
|
|
35
|
+
*
|
|
36
|
+
* Next.js records module IDs during compilation, then resolves those IDs
|
|
37
|
+
* against its react-loadable manifest at render time. Vinext's equivalent
|
|
38
|
+
* source of truth is Vite's build manifest: each chunk lists the modules it
|
|
39
|
+
* reaches through `dynamicImports`, and each dynamic entry lists the JS/CSS
|
|
40
|
+
* files required to evaluate it.
|
|
41
|
+
*
|
|
42
|
+
* Note on shared chunks: a boundary's static-import tree (`collectStaticChunkFiles`)
|
|
43
|
+
* can include chunks that the page entry ALSO loads eagerly (a shared vendor
|
|
44
|
+
* chunk imported by both). Those files are intentionally NOT subtracted here, so
|
|
45
|
+
* a rendered boundary may emit a `<link rel="preload">` / `<link rel="stylesheet">`
|
|
46
|
+
* for a chunk the page already `<link rel="modulepreload">`s. This is harmless —
|
|
47
|
+
* the browser dedupes preloads by URL, `ReactDOM.preload()` dedupes script hints,
|
|
48
|
+
* and React's stylesheet resource model dedupes by href + precedence — and it
|
|
49
|
+
* mirrors Next.js listing a module's full file set in its react-loadable
|
|
50
|
+
* manifest. Subtracting the eager set would couple this to the entry's import
|
|
51
|
+
* closure for no correctness gain.
|
|
52
|
+
*
|
|
53
|
+
* @returns A map keyed by root-relative module ID, with JS/CSS files that
|
|
54
|
+
* should be preloaded when that dynamic boundary is rendered.
|
|
55
|
+
*/
|
|
56
|
+
declare function computeDynamicImportPreloads(buildManifest: Record<string, BuildManifestChunk>): Record<string, string[]>;
|
|
57
|
+
declare function dynamicImportPreloadsWithBase(preloads: Record<string, string[]>, applyBase: (file: string) => string): Record<string, string[]>;
|
|
32
58
|
//#endregion
|
|
33
|
-
export { BuildManifestChunk, computeLazyChunks };
|
|
59
|
+
export { BuildManifestChunk, computeDynamicImportPreloads, computeLazyChunks, dynamicImportPreloadsWithBase };
|
|
@@ -44,5 +44,69 @@ function computeLazyChunks(buildManifest) {
|
|
|
44
44
|
}
|
|
45
45
|
return lazyChunks;
|
|
46
46
|
}
|
|
47
|
+
function normalizeManifestKey(key) {
|
|
48
|
+
return key.split("?")[0].replace(/\\/g, "/").replace(/^\/+/, "");
|
|
49
|
+
}
|
|
50
|
+
function addFile(files, seen, file) {
|
|
51
|
+
if (!file || seen.has(file)) return;
|
|
52
|
+
seen.add(file);
|
|
53
|
+
files.push(file);
|
|
54
|
+
}
|
|
55
|
+
function collectStaticChunkFiles(buildManifest, key, files, seenFiles, visitedChunks) {
|
|
56
|
+
if (visitedChunks.has(key)) return;
|
|
57
|
+
visitedChunks.add(key);
|
|
58
|
+
const chunk = buildManifest[key];
|
|
59
|
+
if (!chunk) return;
|
|
60
|
+
if (chunk.file.endsWith(".js")) addFile(files, seenFiles, chunk.file);
|
|
61
|
+
for (const cssFile of chunk.css ?? []) addFile(files, seenFiles, cssFile);
|
|
62
|
+
for (const importedKey of chunk.imports ?? []) collectStaticChunkFiles(buildManifest, importedKey, files, seenFiles, visitedChunks);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compute the production preload files for each module referenced by a
|
|
66
|
+
* `next/dynamic()` boundary.
|
|
67
|
+
*
|
|
68
|
+
* Next.js records module IDs during compilation, then resolves those IDs
|
|
69
|
+
* against its react-loadable manifest at render time. Vinext's equivalent
|
|
70
|
+
* source of truth is Vite's build manifest: each chunk lists the modules it
|
|
71
|
+
* reaches through `dynamicImports`, and each dynamic entry lists the JS/CSS
|
|
72
|
+
* files required to evaluate it.
|
|
73
|
+
*
|
|
74
|
+
* Note on shared chunks: a boundary's static-import tree (`collectStaticChunkFiles`)
|
|
75
|
+
* can include chunks that the page entry ALSO loads eagerly (a shared vendor
|
|
76
|
+
* chunk imported by both). Those files are intentionally NOT subtracted here, so
|
|
77
|
+
* a rendered boundary may emit a `<link rel="preload">` / `<link rel="stylesheet">`
|
|
78
|
+
* for a chunk the page already `<link rel="modulepreload">`s. This is harmless —
|
|
79
|
+
* the browser dedupes preloads by URL, `ReactDOM.preload()` dedupes script hints,
|
|
80
|
+
* and React's stylesheet resource model dedupes by href + precedence — and it
|
|
81
|
+
* mirrors Next.js listing a module's full file set in its react-loadable
|
|
82
|
+
* manifest. Subtracting the eager set would couple this to the entry's import
|
|
83
|
+
* closure for no correctness gain.
|
|
84
|
+
*
|
|
85
|
+
* @returns A map keyed by root-relative module ID, with JS/CSS files that
|
|
86
|
+
* should be preloaded when that dynamic boundary is rendered.
|
|
87
|
+
*/
|
|
88
|
+
function computeDynamicImportPreloads(buildManifest) {
|
|
89
|
+
const preloads = {};
|
|
90
|
+
for (const chunk of Object.values(buildManifest)) for (const dynamicKey of chunk.dynamicImports ?? []) {
|
|
91
|
+
const files = [];
|
|
92
|
+
collectStaticChunkFiles(buildManifest, dynamicKey, files, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
|
|
93
|
+
if (files.length === 0) continue;
|
|
94
|
+
const normalizedKey = normalizeManifestKey(dynamicKey);
|
|
95
|
+
const existing = preloads[normalizedKey] ?? [];
|
|
96
|
+
const merged = new Set(existing);
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
if (merged.has(file)) continue;
|
|
99
|
+
merged.add(file);
|
|
100
|
+
existing.push(file);
|
|
101
|
+
}
|
|
102
|
+
preloads[normalizedKey] = existing;
|
|
103
|
+
}
|
|
104
|
+
return preloads;
|
|
105
|
+
}
|
|
106
|
+
function dynamicImportPreloadsWithBase(preloads, applyBase) {
|
|
107
|
+
const withBase = {};
|
|
108
|
+
for (const [key, files] of Object.entries(preloads)) withBase[key] = files.map(applyBase);
|
|
109
|
+
return withBase;
|
|
110
|
+
}
|
|
47
111
|
//#endregion
|
|
48
|
-
export { computeLazyChunks };
|
|
112
|
+
export { computeDynamicImportPreloads, computeLazyChunks, dynamicImportPreloadsWithBase };
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
//#region src/utils/manifest-paths.d.ts
|
|
2
2
|
declare function manifestFileWithBase(file: string, base: string): string;
|
|
3
|
-
declare function
|
|
3
|
+
declare function manifestFileWithAssetPrefix(file: string, base: string, assetPrefix: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the URL a client asset is actually SERVED from, starting from a
|
|
6
|
+
* base-anchored manifest / SSR-manifest value (no leading slash), e.g.
|
|
7
|
+
* `"docs/cdn/_next/static/x.js"`.
|
|
8
|
+
*
|
|
9
|
+
* Next.js semantics: `assetPrefix` REPLACES `basePath` for asset URLs (they do
|
|
10
|
+
* not stack). So when an `assetPrefix` is configured we strip the basePath
|
|
11
|
+
* segment and re-anchor under the assetPrefix — matching how `next/dynamic`
|
|
12
|
+
* preloads are computed (`manifestFileWithAssetPrefix`) and what the prod server
|
|
13
|
+
* / Cloudflare ASSETS binding actually serve. Without this, a `basePath` +
|
|
14
|
+
* path-style `assetPrefix` build emits `/<basePath>/<assetPrefix>/_next/...`
|
|
15
|
+
* which 404s. When no `assetPrefix` is set, the base-anchored value is already
|
|
16
|
+
* the served URL and is returned unchanged (just root-anchored).
|
|
17
|
+
*
|
|
18
|
+
* Returns an absolute URL for an absolute `assetPrefix`, otherwise a
|
|
19
|
+
* root-relative URL beginning with `/`.
|
|
20
|
+
*/
|
|
21
|
+
declare function assetServingUrlFromBaseAnchored(value: string, basePath: string, assetPrefix: string): string;
|
|
4
22
|
/**
|
|
5
23
|
* Strip a `base` prefix that Vite applied twice: it bakes `base` into the
|
|
6
24
|
* on-disk chunk fileName and then prepends it again in `ssr-manifest.json`,
|
|
@@ -9,4 +27,4 @@ declare function manifestFilesWithBase(files: string[], base: string): string[];
|
|
|
9
27
|
*/
|
|
10
28
|
declare function collapseDuplicateBase(file: string, base: string): string;
|
|
11
29
|
//#endregion
|
|
12
|
-
export { collapseDuplicateBase,
|
|
30
|
+
export { assetServingUrlFromBaseAnchored, collapseDuplicateBase, manifestFileWithAssetPrefix, manifestFileWithBase };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ASSET_PREFIX_URL_DIR, isAbsoluteAssetPrefix, resolveAssetUrlPrefix, resolveAssetsDir } from "./asset-prefix.js";
|
|
1
2
|
//#region src/utils/manifest-paths.ts
|
|
2
3
|
function normalizeManifestFile(file) {
|
|
3
4
|
return file.startsWith("/") ? file.slice(1) : file;
|
|
@@ -10,8 +11,42 @@ function manifestFileWithBase(file, base) {
|
|
|
10
11
|
if (normalizedFile.startsWith(normalizedBase + "/")) return normalizedFile;
|
|
11
12
|
return normalizedBase + "/" + normalizedFile;
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
-
|
|
14
|
+
function manifestFileWithAssetPrefix(file, base, assetPrefix) {
|
|
15
|
+
if (!assetPrefix) return manifestFileWithBase(file, base);
|
|
16
|
+
const normalizedFile = normalizeManifestFile(file);
|
|
17
|
+
const onDiskDirPrefix = normalizeManifestFile(resolveAssetsDir(assetPrefix)) + "/";
|
|
18
|
+
const staticDirPrefix = ASSET_PREFIX_URL_DIR + "/";
|
|
19
|
+
const stripped = normalizedFile.startsWith(onDiskDirPrefix) ? normalizedFile.slice(onDiskDirPrefix.length) : normalizedFile.startsWith(staticDirPrefix) ? normalizedFile.slice(staticDirPrefix.length) : normalizedFile;
|
|
20
|
+
const urlPrefix = resolveAssetUrlPrefix(assetPrefix);
|
|
21
|
+
return (isAbsoluteAssetPrefix(assetPrefix) ? urlPrefix : normalizeManifestFile(urlPrefix)) + stripped;
|
|
22
|
+
}
|
|
23
|
+
function stripBasePathSegment(file, basePath) {
|
|
24
|
+
const normalizedBase = normalizeManifestFile(basePath).replace(/\/+$/, "");
|
|
25
|
+
if (!normalizedBase) return file;
|
|
26
|
+
return file.startsWith(normalizedBase + "/") ? file.slice(normalizedBase.length + 1) : file;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the URL a client asset is actually SERVED from, starting from a
|
|
30
|
+
* base-anchored manifest / SSR-manifest value (no leading slash), e.g.
|
|
31
|
+
* `"docs/cdn/_next/static/x.js"`.
|
|
32
|
+
*
|
|
33
|
+
* Next.js semantics: `assetPrefix` REPLACES `basePath` for asset URLs (they do
|
|
34
|
+
* not stack). So when an `assetPrefix` is configured we strip the basePath
|
|
35
|
+
* segment and re-anchor under the assetPrefix — matching how `next/dynamic`
|
|
36
|
+
* preloads are computed (`manifestFileWithAssetPrefix`) and what the prod server
|
|
37
|
+
* / Cloudflare ASSETS binding actually serve. Without this, a `basePath` +
|
|
38
|
+
* path-style `assetPrefix` build emits `/<basePath>/<assetPrefix>/_next/...`
|
|
39
|
+
* which 404s. When no `assetPrefix` is set, the base-anchored value is already
|
|
40
|
+
* the served URL and is returned unchanged (just root-anchored).
|
|
41
|
+
*
|
|
42
|
+
* Returns an absolute URL for an absolute `assetPrefix`, otherwise a
|
|
43
|
+
* root-relative URL beginning with `/`.
|
|
44
|
+
*/
|
|
45
|
+
function assetServingUrlFromBaseAnchored(value, basePath, assetPrefix) {
|
|
46
|
+
const normalized = normalizeManifestFile(value);
|
|
47
|
+
if (!assetPrefix) return "/" + normalized;
|
|
48
|
+
const anchored = manifestFileWithAssetPrefix(stripBasePathSegment(normalized, basePath), "/", assetPrefix);
|
|
49
|
+
return isAbsoluteAssetPrefix(assetPrefix) ? anchored : "/" + anchored;
|
|
15
50
|
}
|
|
16
51
|
/**
|
|
17
52
|
* Strip a `base` prefix that Vite applied twice: it bakes `base` into the
|
|
@@ -28,4 +63,4 @@ function collapseDuplicateBase(file, base) {
|
|
|
28
63
|
return normalizedFile.startsWith(doubledPrefix) ? normalizedFile.slice(normalizedBase.length + 1) : normalizedFile;
|
|
29
64
|
}
|
|
30
65
|
//#endregion
|
|
31
|
-
export { collapseDuplicateBase,
|
|
66
|
+
export { assetServingUrlFromBaseAnchored, collapseDuplicateBase, manifestFileWithAssetPrefix, manifestFileWithBase };
|
package/dist/utils/path.d.ts
CHANGED
|
@@ -11,5 +11,6 @@
|
|
|
11
11
|
* appear in filesystem paths on Linux/macOS.
|
|
12
12
|
*/
|
|
13
13
|
declare function normalizePathSeparators(p: string): string;
|
|
14
|
+
declare function stripViteModuleQuery(id: string): string;
|
|
14
15
|
//#endregion
|
|
15
|
-
export { normalizePathSeparators };
|
|
16
|
+
export { normalizePathSeparators, stripViteModuleQuery };
|
package/dist/utils/path.js
CHANGED
|
@@ -14,5 +14,9 @@ const isWindows = process.platform === "win32";
|
|
|
14
14
|
function normalizePathSeparators(p) {
|
|
15
15
|
return isWindows ? p.replace(/\\/g, "/") : p;
|
|
16
16
|
}
|
|
17
|
+
function stripViteModuleQuery(id) {
|
|
18
|
+
const queryIndex = id.search(/[?#]/);
|
|
19
|
+
return queryIndex === -1 ? id : id.slice(0, queryIndex);
|
|
20
|
+
}
|
|
17
21
|
//#endregion
|
|
18
|
-
export { normalizePathSeparators };
|
|
22
|
+
export { normalizePathSeparators, stripViteModuleQuery };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vinext",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Run Next.js apps on Vite. Drop-in replacement for the next CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"types": "./dist/server/request-pipeline.d.ts",
|
|
50
50
|
"import": "./dist/server/request-pipeline.js"
|
|
51
51
|
},
|
|
52
|
+
"./server/pages-request-pipeline": {
|
|
53
|
+
"types": "./dist/server/pages-request-pipeline.d.ts",
|
|
54
|
+
"import": "./dist/server/pages-request-pipeline.js"
|
|
55
|
+
},
|
|
52
56
|
"./server/app-router-entry": {
|
|
53
57
|
"types": "./dist/server/app-router-entry.d.ts",
|
|
54
58
|
"import": "./dist/server/app-router-entry.js"
|
|
@@ -97,7 +101,7 @@
|
|
|
97
101
|
"react-server-dom-webpack": "^19.2.7",
|
|
98
102
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.1.24",
|
|
99
103
|
"vite-plus": "0.1.24",
|
|
100
|
-
"@vinext/cloudflare": "0.1.
|
|
104
|
+
"@vinext/cloudflare": "0.1.1"
|
|
101
105
|
},
|
|
102
106
|
"peerDependencies": {
|
|
103
107
|
"@mdx-js/rollup": "^3.0.0",
|