@qzsy/vinext 0.1.12 → 0.1.123
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/check.d.ts +8 -0
- package/dist/check.js +20 -9
- package/dist/cli.js +2 -2
- package/dist/deploy.js +10 -11
- package/dist/entries/app-rsc-entry.js +37 -8
- package/dist/entries/app-rsc-manifest.js +8 -0
- package/dist/entries/pages-client-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +1 -0
- package/dist/index.js +12 -8
- package/dist/init.js +2 -1
- package/dist/plugins/middleware-server-only.d.ts +8 -6
- package/dist/plugins/middleware-server-only.js +8 -7
- package/dist/routing/app-route-graph.d.ts +6 -2
- package/dist/routing/app-route-graph.js +60 -12
- package/dist/routing/app-router.d.ts +5 -0
- package/dist/routing/app-router.js +5 -0
- package/dist/routing/file-matcher.d.ts +5 -0
- package/dist/routing/file-matcher.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +2 -1
- package/dist/server/app-browser-history-controller.js +6 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -1
- package/dist/server/app-fallback-renderer.js +2 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +12 -3
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +8 -2
- package/dist/server/app-page-dispatch.d.ts +11 -3
- package/dist/server/app-page-dispatch.js +54 -15
- package/dist/server/app-page-element-builder.d.ts +5 -1
- package/dist/server/app-page-element-builder.js +55 -19
- package/dist/server/app-page-head.d.ts +12 -0
- package/dist/server/app-page-head.js +42 -19
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +8 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +1 -1
- package/dist/server/app-page-render.d.ts +4 -1
- package/dist/server/app-page-render.js +8 -3
- package/dist/server/app-page-request.d.ts +8 -1
- package/dist/server/app-page-request.js +23 -11
- package/dist/server/app-page-route-wiring.d.ts +6 -1
- package/dist/server/app-page-route-wiring.js +30 -8
- package/dist/server/app-page-search-params-observation.d.ts +4 -2
- package/dist/server/app-page-search-params-observation.js +11 -7
- package/dist/server/app-route-handler-dispatch.js +1 -0
- package/dist/server/app-route-handler-execution.js +2 -1
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.d.ts +12 -0
- package/dist/server/app-router-entry.js +13 -6
- package/dist/server/app-router-image-optimization.d.ts +37 -0
- package/dist/server/app-router-image-optimization.js +40 -0
- package/dist/server/app-rsc-errors.js +7 -1
- package/dist/server/app-rsc-handler.js +5 -2
- package/dist/server/app-rsc-route-matching.d.ts +7 -0
- package/dist/server/app-rsc-route-matching.js +36 -3
- package/dist/server/app-segment-config.d.ts +1 -0
- package/dist/server/app-segment-config.js +32 -2
- package/dist/server/app-server-action-execution.d.ts +4 -0
- package/dist/server/app-server-action-execution.js +41 -10
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +1 -0
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/prod-server.js +15 -6
- package/dist/server/worker-utils.d.ts +2 -1
- package/dist/server/worker-utils.js +7 -1
- package/dist/shims/error-boundary.d.ts +19 -1
- package/dist/shims/error-boundary.js +11 -1
- package/dist/shims/headers.d.ts +3 -1
- package/dist/shims/headers.js +16 -5
- package/dist/shims/metadata.d.ts +3 -2
- package/dist/shims/metadata.js +8 -4
- package/dist/shims/router.js +13 -2
- package/dist/typegen.js +6 -5
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +1 -1
- package/dist/utils/project.d.ts +4 -0
- package/dist/utils/project.js +5 -1
- package/package.json +1 -1
package/dist/check.d.ts
CHANGED
|
@@ -59,6 +59,10 @@ type CheckResult = {
|
|
|
59
59
|
declare function hasFreeCjsGlobal(content: string): boolean;
|
|
60
60
|
/**
|
|
61
61
|
* Scan source files for `import ... from 'next/...'` statements.
|
|
62
|
+
*
|
|
63
|
+
* `root` must be forward-slash: it is passed to `findSourceFiles` (which
|
|
64
|
+
* requires it) and used as the base of `path.posix.relative`, which only yields
|
|
65
|
+
* a canonical relative path when both operands are forward-slash.
|
|
62
66
|
*/
|
|
63
67
|
declare function scanImports(root: string): CheckItem[];
|
|
64
68
|
/**
|
|
@@ -75,6 +79,10 @@ declare function checkLibraries(root: string): CheckItem[];
|
|
|
75
79
|
declare function checkConventions(root: string): CheckItem[];
|
|
76
80
|
/**
|
|
77
81
|
* Run the full compatibility check.
|
|
82
|
+
*
|
|
83
|
+
* `root` must be forward-slash — callers normalize it at the CLI entry, and it
|
|
84
|
+
* is forwarded to `scanImports` / `checkConventions` / `findDir`, which build
|
|
85
|
+
* paths with `path.posix.*`.
|
|
78
86
|
*/
|
|
79
87
|
declare function runCheck(root: string): CheckResult;
|
|
80
88
|
/**
|
package/dist/check.js
CHANGED
|
@@ -331,6 +331,11 @@ const LIBRARY_SUPPORT = {
|
|
|
331
331
|
};
|
|
332
332
|
/**
|
|
333
333
|
* Recursively find all source files in a directory.
|
|
334
|
+
*
|
|
335
|
+
* `dir` must be forward-slash, and the returned paths are forward-slash too:
|
|
336
|
+
* each entry is joined with `path.posix.join`, which only stays canonical when
|
|
337
|
+
* the base already is. This keeps downstream substring checks (e.g.
|
|
338
|
+
* `f.includes("/api/")`) and reported paths consistent across platforms.
|
|
334
339
|
*/
|
|
335
340
|
function findSourceFiles(dir, extensions = [
|
|
336
341
|
".ts",
|
|
@@ -343,7 +348,7 @@ function findSourceFiles(dir, extensions = [
|
|
|
343
348
|
if (!fs.existsSync(dir)) return results;
|
|
344
349
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
345
350
|
for (const entry of entries) {
|
|
346
|
-
const fullPath =
|
|
351
|
+
const fullPath = path.posix.join(dir, entry.name);
|
|
347
352
|
if (entry.isDirectory()) {
|
|
348
353
|
if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist" || entry.name === ".git") continue;
|
|
349
354
|
results.push(...findSourceFiles(fullPath, extensions));
|
|
@@ -547,6 +552,10 @@ function hasFreeCjsGlobal(content) {
|
|
|
547
552
|
}
|
|
548
553
|
/**
|
|
549
554
|
* Scan source files for `import ... from 'next/...'` statements.
|
|
555
|
+
*
|
|
556
|
+
* `root` must be forward-slash: it is passed to `findSourceFiles` (which
|
|
557
|
+
* requires it) and used as the base of `path.posix.relative`, which only yields
|
|
558
|
+
* a canonical relative path when both operands are forward-slash.
|
|
550
559
|
*/
|
|
551
560
|
function scanImports(root) {
|
|
552
561
|
const files = findSourceFiles(root);
|
|
@@ -564,7 +573,7 @@ function scanImports(root) {
|
|
|
564
573
|
if (mod.startsWith("next/") || mod === "next" || mod === "server-only" || mod === "client-only") {
|
|
565
574
|
const normalized = mod === "next" ? "next" : mod;
|
|
566
575
|
if (!importUsage.has(normalized)) importUsage.set(normalized, []);
|
|
567
|
-
const relFile =
|
|
576
|
+
const relFile = path.posix.relative(root, file);
|
|
568
577
|
const usedInFiles = importUsage.get(normalized) ?? [];
|
|
569
578
|
if (!usedInFiles.includes(relFile)) usedInFiles.push(relFile);
|
|
570
579
|
}
|
|
@@ -780,14 +789,12 @@ function checkLibraries(root) {
|
|
|
780
789
|
*/
|
|
781
790
|
function checkConventions(root) {
|
|
782
791
|
const items = [];
|
|
783
|
-
const pagesDir = findDir(root, "pages",
|
|
784
|
-
const appDirPath = findDir(root, "app",
|
|
785
|
-
const hasPages = pagesDir !== null;
|
|
786
|
-
const hasApp = appDirPath !== null;
|
|
792
|
+
const pagesDir = findDir(root, "pages", "src/pages");
|
|
793
|
+
const appDirPath = findDir(root, "app", "src/app");
|
|
787
794
|
const hasProxy = fs.existsSync(path.join(root, "proxy.ts")) || fs.existsSync(path.join(root, "proxy.js"));
|
|
788
795
|
const hasMiddleware = fs.existsSync(path.join(root, "middleware.ts")) || fs.existsSync(path.join(root, "middleware.js"));
|
|
789
796
|
if (pagesDir !== null) {
|
|
790
|
-
const isSrc = pagesDir.includes(
|
|
797
|
+
const isSrc = pagesDir.includes("src/pages");
|
|
791
798
|
items.push({
|
|
792
799
|
name: isSrc ? "Pages Router (src/pages/)" : "Pages Router (pages/)",
|
|
793
800
|
status: "supported"
|
|
@@ -813,7 +820,7 @@ function checkConventions(root) {
|
|
|
813
820
|
});
|
|
814
821
|
}
|
|
815
822
|
if (appDirPath !== null) {
|
|
816
|
-
const isSrc = appDirPath.includes(
|
|
823
|
+
const isSrc = appDirPath.includes("src/app");
|
|
817
824
|
items.push({
|
|
818
825
|
name: isSrc ? "App Router (src/app/)" : "App Router (app/)",
|
|
819
826
|
status: "supported"
|
|
@@ -858,7 +865,7 @@ function checkConventions(root) {
|
|
|
858
865
|
name: "middleware.ts (deprecated in Next.js 16)",
|
|
859
866
|
status: "supported"
|
|
860
867
|
});
|
|
861
|
-
if (
|
|
868
|
+
if (pagesDir === null && appDirPath === null) items.push({
|
|
862
869
|
name: "No pages/ or app/ directory found",
|
|
863
870
|
status: "unsupported",
|
|
864
871
|
detail: "vinext requires a pages/ or app/ directory"
|
|
@@ -913,6 +920,10 @@ function checkConventions(root) {
|
|
|
913
920
|
}
|
|
914
921
|
/**
|
|
915
922
|
* Run the full compatibility check.
|
|
923
|
+
*
|
|
924
|
+
* `root` must be forward-slash — callers normalize it at the CLI entry, and it
|
|
925
|
+
* is forwarded to `scanImports` / `checkConventions` / `findDir`, which build
|
|
926
|
+
* paths with `path.posix.*`.
|
|
916
927
|
*/
|
|
917
928
|
function runCheck(root) {
|
|
918
929
|
const imports = scanImports(root);
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { detectPackageManager, ensureViteConfigCompatibility, hasAppDir, hasViteConfig } from "./utils/project.js";
|
|
3
|
+
import { normalizePathSeparators } from "./utils/path.js";
|
|
3
4
|
import { formatReport, runCheck } from "./check.js";
|
|
4
5
|
import { parseArgs } from "./cli-args.js";
|
|
5
6
|
import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
|
|
@@ -440,10 +441,9 @@ async function deployCommand() {
|
|
|
440
441
|
}
|
|
441
442
|
async function check() {
|
|
442
443
|
if (parseArgs(rawArgs).help) return printHelp("check");
|
|
443
|
-
const root = process.cwd();
|
|
444
444
|
console.log(`\n vinext check\n`);
|
|
445
445
|
console.log(" Scanning project...\n");
|
|
446
|
-
const result = runCheck(
|
|
446
|
+
const result = runCheck(normalizePathSeparators(process.cwd()));
|
|
447
447
|
console.log(formatReport(result));
|
|
448
448
|
}
|
|
449
449
|
async function typegen() {
|
package/dist/deploy.js
CHANGED
|
@@ -380,6 +380,7 @@ import { handleImageOptimization, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isI
|
|
|
380
380
|
import type { ImageConfig } from "vinext/server/image-optimization";
|
|
381
381
|
import { bufferRequestBodyForHeaderClone, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, isOpenRedirectShaped } from "vinext/server/request-pipeline";
|
|
382
382
|
import { notFoundStaticAssetResponse } from "vinext/server/http-error-responses";
|
|
383
|
+
import { finalizeMissingStaticAssetResponse } from "vinext/server/worker-utils";
|
|
383
384
|
import { assetPrefixPathname, isNextStaticPath } from "vinext/utils/asset-prefix";
|
|
384
385
|
import { hasBasePath, stripBasePath } from "vinext/utils/base-path";
|
|
385
386
|
|
|
@@ -438,15 +439,11 @@ export default {
|
|
|
438
439
|
return new Response("This page could not be found", { status: 404 });
|
|
439
440
|
}
|
|
440
441
|
|
|
441
|
-
//
|
|
442
|
-
//
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
|
|
446
|
-
// packages/next/src/server/lib/router-server.ts
|
|
447
|
-
if (isNextStaticPath(pathname, basePath, assetPathPrefix)) {
|
|
448
|
-
return notFoundStaticAssetResponse();
|
|
449
|
-
}
|
|
442
|
+
// Valid assets are served by Cloudflare's ASSETS binding before the
|
|
443
|
+
// worker runs. Missing asset-shaped requests still need to reach
|
|
444
|
+
// middleware so it can rewrite or respond; a final 404 is converted
|
|
445
|
+
// back to Next.js's canonical plain-text static-file response below.
|
|
446
|
+
const missingBuildAsset = isNextStaticPath(pathname, basePath, assetPathPrefix);
|
|
450
447
|
|
|
451
448
|
// Strip internal headers from inbound requests so they cannot be
|
|
452
449
|
// forged to influence routing or impersonate internal state.
|
|
@@ -539,10 +536,12 @@ export default {
|
|
|
539
536
|
|
|
540
537
|
const result = await runPagesRequest(request, deps);
|
|
541
538
|
if (result.type === "response") {
|
|
542
|
-
return result.response;
|
|
539
|
+
return finalizeMissingStaticAssetResponse(result.response, missingBuildAsset);
|
|
543
540
|
}
|
|
544
541
|
// Should not reach here for prod/worker (all callbacks supplied).
|
|
545
|
-
return
|
|
542
|
+
return missingBuildAsset
|
|
543
|
+
? notFoundStaticAssetResponse()
|
|
544
|
+
: new Response("This page could not be found", { status: 404 });
|
|
546
545
|
|
|
547
546
|
} catch (error) {
|
|
548
547
|
console.error("[vinext] Worker error:", error);
|
|
@@ -245,6 +245,11 @@ function __resolveRouteFetchCacheMode(route) {
|
|
|
245
245
|
return __resolveAppPageFetchCacheMode({
|
|
246
246
|
layouts: route.layouts,
|
|
247
247
|
page: route.page,
|
|
248
|
+
parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
|
|
249
|
+
slot.layout,
|
|
250
|
+
...(slot.configLayouts ?? []),
|
|
251
|
+
slot.page ?? slot.default,
|
|
252
|
+
]),
|
|
248
253
|
});
|
|
249
254
|
}
|
|
250
255
|
|
|
@@ -252,6 +257,11 @@ function __resolveRouteDynamicConfig(route) {
|
|
|
252
257
|
return __resolveAppPageSegmentConfig({
|
|
253
258
|
layouts: route.layouts,
|
|
254
259
|
page: route.page,
|
|
260
|
+
parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
|
|
261
|
+
slot.layout,
|
|
262
|
+
...(slot.configLayouts ?? []),
|
|
263
|
+
slot.page ?? slot.default,
|
|
264
|
+
]),
|
|
255
265
|
}).dynamicConfig ?? null;
|
|
256
266
|
}
|
|
257
267
|
|
|
@@ -259,6 +269,11 @@ function __resolveRouteRuntime(route) {
|
|
|
259
269
|
return __resolveAppPageSegmentConfig({
|
|
260
270
|
layouts: route.layouts,
|
|
261
271
|
page: route.page,
|
|
272
|
+
parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
|
|
273
|
+
slot.layout,
|
|
274
|
+
...(slot.configLayouts ?? []),
|
|
275
|
+
slot.page ?? slot.default,
|
|
276
|
+
]),
|
|
262
277
|
}).runtime ?? null;
|
|
263
278
|
}
|
|
264
279
|
|
|
@@ -506,7 +521,12 @@ export default createAppRscHandler({
|
|
|
506
521
|
const __segmentConfig = __resolveAppPageSegmentConfig({
|
|
507
522
|
layouts: route.layouts,
|
|
508
523
|
page: route.page,
|
|
509
|
-
parallelPages: Object.values(route.slots ?? {}).map((slot) => slot.page),
|
|
524
|
+
parallelPages: Object.values(route.slots ?? {}).map((slot) => slot.page ?? slot.default),
|
|
525
|
+
parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
|
|
526
|
+
slot.layout,
|
|
527
|
+
...(slot.configLayouts ?? []),
|
|
528
|
+
slot.page ?? slot.default,
|
|
529
|
+
]),
|
|
510
530
|
});
|
|
511
531
|
const __generateStaticParams = __resolveAppPageGenerateStaticParamsSources({
|
|
512
532
|
layouts: route.layouts,
|
|
@@ -520,7 +540,7 @@ export default createAppRscHandler({
|
|
|
520
540
|
ensureRouteLoaded: __ensureRouteLoaded,
|
|
521
541
|
clientTraceMetadata: __clientTraceMetadata,
|
|
522
542
|
reactMaxHeadersLength: __reactMaxHeadersLength,
|
|
523
|
-
buildPageElement(targetRoute, targetParams, targetOpts, targetSearchParams, layoutParamAccess) {
|
|
543
|
+
buildPageElement(targetRoute, targetParams, targetOpts, targetSearchParams, layoutParamAccess, buildOptions) {
|
|
524
544
|
return buildPageElements(targetRoute, targetParams, cleanPathname, {
|
|
525
545
|
opts: targetOpts,
|
|
526
546
|
searchParams: targetSearchParams,
|
|
@@ -528,6 +548,8 @@ export default createAppRscHandler({
|
|
|
528
548
|
request,
|
|
529
549
|
mountedSlotsHeader,
|
|
530
550
|
renderMode,
|
|
551
|
+
observeMetadataSearchParamsAccess: buildOptions?.observeMetadataSearchParamsAccess === true,
|
|
552
|
+
observePageSearchParamsAccess: buildOptions?.observePageSearchParamsAccess === true,
|
|
531
553
|
}, layoutParamAccess, displayPathname);
|
|
532
554
|
},
|
|
533
555
|
clientReuseManifest,
|
|
@@ -598,7 +620,7 @@ export default createAppRscHandler({
|
|
|
598
620
|
route,
|
|
599
621
|
});
|
|
600
622
|
},
|
|
601
|
-
async probePage() {
|
|
623
|
+
async probePage(probeSearchParams = searchParams) {
|
|
602
624
|
const __probeIntercept = findIntercept(cleanPathname, interceptionContext);
|
|
603
625
|
// The intercepting-route page module is lazy (page: null + __pageLoader).
|
|
604
626
|
// Resolve it before probing so buildAppPageProbes inspects the real page
|
|
@@ -613,21 +635,21 @@ export default createAppRscHandler({
|
|
|
613
635
|
route,
|
|
614
636
|
pageComponent: PageComponent,
|
|
615
637
|
asyncRouteParams: _asyncRouteParams,
|
|
616
|
-
searchParams,
|
|
638
|
+
searchParams: probeSearchParams,
|
|
617
639
|
intercept: __probeIntercept,
|
|
618
640
|
isRscRequest,
|
|
619
641
|
matchedParams: params,
|
|
620
642
|
makeThenableParams,
|
|
621
643
|
}));
|
|
622
644
|
},
|
|
623
|
-
renderErrorBoundaryPage(renderErr) {
|
|
645
|
+
renderErrorBoundaryPage(renderErr, errorOrigin) {
|
|
624
646
|
const __activeIntercept = findIntercept(cleanPathname, interceptionContext);
|
|
625
647
|
return __fallbackRenderer.renderErrorBoundary(route, renderErr, isRscRequest, request, params, scriptNonce, middlewareContext, {
|
|
626
648
|
isEdgeRuntime: __isEdgeRuntime(__segmentConfig.runtime),
|
|
627
649
|
sourcePageSegments: __activeIntercept?.slotKey === __SIBLING_PAGE_INTERCEPT_SLOT_KEY
|
|
628
650
|
? __activeIntercept.sourcePageSegments
|
|
629
651
|
: null,
|
|
630
|
-
});
|
|
652
|
+
}, errorOrigin);
|
|
631
653
|
},
|
|
632
654
|
renderHttpAccessFallbackPage(statusCode, opts, currentMiddlewareContext) {
|
|
633
655
|
const __activeIntercept = findIntercept(cleanPathname, interceptionContext);
|
|
@@ -777,7 +799,7 @@ export default createAppRscHandler({
|
|
|
777
799
|
const __actionMatch = matchRoute(cleanPathname);
|
|
778
800
|
if (__actionMatch) await __ensureRouteLoaded(__actionMatch.route);
|
|
779
801
|
const __actionIsEdgeRuntime = __actionMatch
|
|
780
|
-
? __isEdgeRuntime(
|
|
802
|
+
? __isEdgeRuntime(__resolveRouteRuntime(__actionMatch.route))
|
|
781
803
|
: false;
|
|
782
804
|
return __handleServerActionRscRequest({
|
|
783
805
|
actionId,
|
|
@@ -795,6 +817,8 @@ export default createAppRscHandler({
|
|
|
795
817
|
request: actionRequest,
|
|
796
818
|
mountedSlotsHeader: actionMountedSlotsHeader,
|
|
797
819
|
renderMode: actionRenderMode,
|
|
820
|
+
observeMetadataSearchParamsAccess,
|
|
821
|
+
observePageSearchParamsAccess,
|
|
798
822
|
}) {
|
|
799
823
|
return buildPageElements(actionRoute, actionParams, actionCleanPathname, {
|
|
800
824
|
opts: interceptOpts,
|
|
@@ -803,6 +827,8 @@ export default createAppRscHandler({
|
|
|
803
827
|
request: actionRequest,
|
|
804
828
|
mountedSlotsHeader: actionMountedSlotsHeader,
|
|
805
829
|
renderMode: actionRenderMode,
|
|
830
|
+
observeMetadataSearchParamsAccess: observeMetadataSearchParamsAccess === true,
|
|
831
|
+
observePageSearchParamsAccess: observePageSearchParamsAccess === true,
|
|
806
832
|
});
|
|
807
833
|
},
|
|
808
834
|
cleanPathname,
|
|
@@ -828,6 +854,7 @@ export default createAppRscHandler({
|
|
|
828
854
|
},
|
|
829
855
|
createTemporaryReferenceSet,
|
|
830
856
|
decodeReply,
|
|
857
|
+
draftModeSecret: __draftModeSecret,
|
|
831
858
|
findIntercept(pathnameToMatch) {
|
|
832
859
|
return findIntercept(pathnameToMatch, interceptionContext);
|
|
833
860
|
},
|
|
@@ -871,6 +898,8 @@ export default createAppRscHandler({
|
|
|
871
898
|
return {
|
|
872
899
|
interceptionContext,
|
|
873
900
|
interceptLayouts: intercept.interceptLayouts,
|
|
901
|
+
interceptLayoutSegments: intercept.interceptLayoutSegments,
|
|
902
|
+
interceptBranchSegments: intercept.interceptBranchSegments,
|
|
874
903
|
interceptSlotId: intercept.slotId,
|
|
875
904
|
interceptSlotKey: intercept.slotKey,
|
|
876
905
|
interceptSourceMatchedUrl: interceptionContext,
|
|
@@ -910,7 +939,7 @@ export default createAppRscHandler({
|
|
|
910
939
|
},` : ""}
|
|
911
940
|
publicFiles: __publicFiles,
|
|
912
941
|
renderNotFound({ isRscRequest, matchedParams, middlewareContext, request, route, scriptNonce }) {
|
|
913
|
-
const __isEdge = route ? __isEdgeRuntime(
|
|
942
|
+
const __isEdge = route ? __isEdgeRuntime(__resolveRouteRuntime(route)) : false;
|
|
914
943
|
return __fallbackRenderer.renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, { isEdgeRuntime: __isEdge });
|
|
915
944
|
},
|
|
916
945
|
${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, url }) {
|
|
@@ -74,6 +74,7 @@ function registerRouteModules(routes, imports) {
|
|
|
74
74
|
if (slot.pagePath) imports.getLazyLoaderVar(slot.pagePath);
|
|
75
75
|
if (slot.defaultPath) imports.getLazyLoaderVar(slot.defaultPath);
|
|
76
76
|
if (slot.layoutPath) imports.getLazyLoaderVar(slot.layoutPath);
|
|
77
|
+
for (const layoutPath of slot.configLayoutPaths ?? []) imports.getLazyLoaderVar(layoutPath);
|
|
77
78
|
if (slot.loadingPath) imports.getLazyLoaderVar(slot.loadingPath);
|
|
78
79
|
if (slot.errorPath) imports.getLazyLoaderVar(slot.errorPath);
|
|
79
80
|
for (const ir of slot.interceptingRoutes) {
|
|
@@ -112,6 +113,8 @@ function buildRouteEntries(routes, imports) {
|
|
|
112
113
|
slotId: ${JSON.stringify(ir.slotId ?? null)},
|
|
113
114
|
interceptLayouts: ${moduleArray(ir.layoutPaths.length)},
|
|
114
115
|
__loadInterceptLayouts: ${lazyLoaderArray(ir.layoutPaths, imports)},
|
|
116
|
+
interceptLayoutSegments: ${JSON.stringify(ir.layoutSegments ?? [])},
|
|
117
|
+
interceptBranchSegments: ${JSON.stringify(ir.branchSegments ?? [])},
|
|
115
118
|
page: null,
|
|
116
119
|
__pageLoader: ${imports.getLazyLoaderVar(ir.pagePath)},
|
|
117
120
|
params: ${JSON.stringify(ir.params)},
|
|
@@ -124,6 +127,8 @@ function buildRouteEntries(routes, imports) {
|
|
|
124
127
|
sourcePageSegments: ${JSON.stringify(ir.sourcePageSegments)},
|
|
125
128
|
interceptLayouts: ${moduleArray(ir.layoutPaths.length)},
|
|
126
129
|
__loadInterceptLayouts: ${lazyLoaderArray(ir.layoutPaths, imports)},
|
|
130
|
+
interceptLayoutSegments: ${JSON.stringify(ir.layoutSegments ?? [])},
|
|
131
|
+
interceptBranchSegments: ${JSON.stringify(ir.branchSegments ?? [])},
|
|
127
132
|
page: null,
|
|
128
133
|
__pageLoader: ${imports.getLazyLoaderVar(ir.pagePath)},
|
|
129
134
|
params: ${JSON.stringify(ir.params)},
|
|
@@ -137,6 +142,9 @@ function buildRouteEntries(routes, imports) {
|
|
|
137
142
|
__loadDefault: ${slot.defaultPath ? imports.getLazyLoaderVar(slot.defaultPath) : "null"},
|
|
138
143
|
layout: null,
|
|
139
144
|
__loadLayout: ${slot.layoutPath ? imports.getLazyLoaderVar(slot.layoutPath) : "null"},
|
|
145
|
+
configLayouts: ${moduleArray(slot.configLayoutPaths?.length ?? 0)},
|
|
146
|
+
__loadConfigLayouts: ${lazyLoaderArray(slot.configLayoutPaths ?? [], imports)},
|
|
147
|
+
configLayoutTreePositions: ${JSON.stringify(slot.configLayoutTreePositions ?? [])},
|
|
140
148
|
loading: null,
|
|
141
149
|
__loadLoading: ${slot.loadingPath ? imports.getLazyLoaderVar(slot.loadingPath) : "null"},
|
|
142
150
|
error: null,
|
|
@@ -2,6 +2,7 @@ import { normalizePathSeparators } from "../utils/path.js";
|
|
|
2
2
|
import { findFileWithExts } from "../routing/file-matcher.js";
|
|
3
3
|
import { patternToNextFormat } from "../routing/route-validation.js";
|
|
4
4
|
import { apiRouter, pagesRouter } from "../routing/pages-router.js";
|
|
5
|
+
import "./pages-entry-helpers.js";
|
|
5
6
|
//#region src/entries/pages-client-entry.ts
|
|
6
7
|
/**
|
|
7
8
|
* Pages Router client hydration entry generator.
|
|
@@ -3,6 +3,7 @@ import { findFileWithExts } from "../routing/file-matcher.js";
|
|
|
3
3
|
import { apiRouter, pagesRouter } from "../routing/pages-router.js";
|
|
4
4
|
import { resolveEntryPath } from "./runtime-entry-module.js";
|
|
5
5
|
import { isProxyFile } from "../server/middleware.js";
|
|
6
|
+
import "./pages-entry-helpers.js";
|
|
6
7
|
//#region src/entries/pages-server-entry.ts
|
|
7
8
|
/**
|
|
8
9
|
* Pages Router server entry generator.
|
package/dist/index.js
CHANGED
|
@@ -636,6 +636,10 @@ function vinext(options = {}) {
|
|
|
636
636
|
createMiddlewareServerOnlyPlugin({
|
|
637
637
|
getMiddlewarePath: () => middlewarePath,
|
|
638
638
|
getCanonicalMiddlewarePath: () => middlewarePath ? tryRealpathSync(middlewarePath) ?? middlewarePath : null,
|
|
639
|
+
isNeutralServerModule: (id) => {
|
|
640
|
+
const canonicalId = canonicalizePageTransformPath(id);
|
|
641
|
+
return isWithinPagesDirectory(canonicalId) && isApiPage(canonicalId);
|
|
642
|
+
},
|
|
639
643
|
serverOnlyShimPath: resolveShimModulePath(shimsDir, "server-only")
|
|
640
644
|
}),
|
|
641
645
|
dataUrlCssPlugin(),
|
|
@@ -1146,7 +1150,7 @@ function vinext(options = {}) {
|
|
|
1146
1150
|
resolveId: {
|
|
1147
1151
|
filter: { id: /(?:next\/|vinext\/(?:shims\/|server\/app-rsc-handler)|virtual:vinext-|@vercel\/og(?:\.js)?$)/ },
|
|
1148
1152
|
handler(id, importer) {
|
|
1149
|
-
const cleanId = id.startsWith("\0") ? id.slice(1) : id;
|
|
1153
|
+
const cleanId = normalizePathSeparators(id.startsWith("\0") ? id.slice(1) : id);
|
|
1150
1154
|
if (cleanId === "vinext/server/app-rsc-handler") {
|
|
1151
1155
|
if (_canExternalizeAppRscHandler && this.environment?.name === "rsc" && this.environment.config?.command === "serve") return {
|
|
1152
1156
|
id: _appRscHandlerPath,
|
|
@@ -1158,19 +1162,19 @@ function vinext(options = {}) {
|
|
|
1158
1162
|
if (cleanId.startsWith("vinext/shims/")) return resolveShimModulePath(_shimsDir, stripJsExtension(stripViteModuleQuery(cleanId.slice(13))));
|
|
1159
1163
|
if (cleanId === VIRTUAL_SERVER_ENTRY) return RESOLVED_SERVER_ENTRY;
|
|
1160
1164
|
if (cleanId === VIRTUAL_CLIENT_ENTRY) return RESOLVED_CLIENT_ENTRY;
|
|
1161
|
-
if (cleanId.endsWith("/virtual:vinext-server-entry")
|
|
1162
|
-
if (cleanId.endsWith("/virtual:vinext-client-entry")
|
|
1165
|
+
if (cleanId.endsWith("/virtual:vinext-server-entry")) return RESOLVED_SERVER_ENTRY;
|
|
1166
|
+
if (cleanId.endsWith("/virtual:vinext-client-entry")) return RESOLVED_CLIENT_ENTRY;
|
|
1163
1167
|
if (cleanId === VIRTUAL_RSC_ENTRY) return RESOLVED_RSC_ENTRY;
|
|
1164
1168
|
if (cleanId === VIRTUAL_APP_SSR_ENTRY) return RESOLVED_APP_SSR_ENTRY;
|
|
1165
1169
|
if (cleanId === VIRTUAL_APP_BROWSER_ENTRY) return RESOLVED_APP_BROWSER_ENTRY;
|
|
1166
1170
|
if (cleanId === VIRTUAL_APP_CAPABILITIES) return RESOLVED_APP_CAPABILITIES;
|
|
1167
1171
|
if (cleanId === "next/root-params" || cleanId === "next/root-params.js") return RESOLVED_ROOT_PARAMS;
|
|
1168
|
-
if (cleanId === "virtual:vinext-cache-adapters" || cleanId.endsWith("/virtual:vinext-cache-adapters")
|
|
1172
|
+
if (cleanId === "virtual:vinext-cache-adapters" || cleanId.endsWith("/virtual:vinext-cache-adapters")) return RESOLVED_CACHE_ADAPTERS;
|
|
1169
1173
|
if (cleanId.startsWith("virtual:vinext-google-fonts?")) return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(VIRTUAL_GOOGLE_FONTS.length);
|
|
1170
|
-
if (cleanId.endsWith("/virtual:vinext-rsc-entry")
|
|
1171
|
-
if (cleanId.endsWith("/virtual:vinext-app-ssr-entry")
|
|
1172
|
-
if (cleanId.endsWith("/virtual:vinext-app-browser-entry")
|
|
1173
|
-
if (cleanId.includes("/virtual:vinext-google-fonts?")
|
|
1174
|
+
if (cleanId.endsWith("/virtual:vinext-rsc-entry")) return RESOLVED_RSC_ENTRY;
|
|
1175
|
+
if (cleanId.endsWith("/virtual:vinext-app-ssr-entry")) return RESOLVED_APP_SSR_ENTRY;
|
|
1176
|
+
if (cleanId.endsWith("/virtual:vinext-app-browser-entry")) return RESOLVED_APP_BROWSER_ENTRY;
|
|
1177
|
+
if (cleanId.includes("/virtual:vinext-google-fonts?")) {
|
|
1174
1178
|
const queryIndex = cleanId.indexOf(VIRTUAL_GOOGLE_FONTS + "?");
|
|
1175
1179
|
return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(queryIndex + VIRTUAL_GOOGLE_FONTS.length);
|
|
1176
1180
|
}
|
package/dist/init.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { detectPackageManager, detectPackageManagerName, ensureESModule, hasAppDir, hasViteConfig, renameCJSConfigs } from "./utils/project.js";
|
|
2
|
+
import { normalizePathSeparators } from "./utils/path.js";
|
|
2
3
|
import { formatReport, runCheck } from "./check.js";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import fs from "node:fs";
|
|
@@ -176,7 +177,7 @@ function updateGitignore(root) {
|
|
|
176
177
|
return true;
|
|
177
178
|
}
|
|
178
179
|
async function init(options) {
|
|
179
|
-
const root = path.resolve(options.root);
|
|
180
|
+
const root = normalizePathSeparators(path.resolve(options.root));
|
|
180
181
|
const port = options.port ?? 3001;
|
|
181
182
|
const exec = options._exec ?? ((cmd, opts) => {
|
|
182
183
|
const [program, ...args] = cmd.split(" ");
|
|
@@ -2,8 +2,8 @@ import { Plugin } from "vite";
|
|
|
2
2
|
|
|
3
3
|
//#region src/plugins/middleware-server-only.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Allow `import 'server-only'` from
|
|
6
|
-
* from
|
|
5
|
+
* Allow `import 'server-only'` from neutral server targets (and any module
|
|
6
|
+
* reachable from them) in the SSR environment.
|
|
7
7
|
*
|
|
8
8
|
* Background: middleware runs server-side, so importing `server-only` is
|
|
9
9
|
* semantically correct. However, vinext bundles middleware into the SSR
|
|
@@ -13,9 +13,9 @@ import { Plugin } from "vite";
|
|
|
13
13
|
*
|
|
14
14
|
* 'server-only' cannot be imported in client build ('ssr' environment)
|
|
15
15
|
*
|
|
16
|
-
* Next.js solves this with webpack `issuerLayer` rules: middleware
|
|
17
|
-
*
|
|
18
|
-
* is aliased to a no-op while `client-only` still errors. See
|
|
16
|
+
* Next.js solves this with webpack `issuerLayer` rules: middleware,
|
|
17
|
+
* instrumentation, and Pages API routes sit in server-only or neutral layers
|
|
18
|
+
* where `server-only` is aliased to a no-op while `client-only` still errors. See
|
|
19
19
|
* packages/next/src/build/webpack-config.ts ("Alias server-only and
|
|
20
20
|
* client-only to proper exports based on bundling layers")
|
|
21
21
|
*
|
|
@@ -23,7 +23,8 @@ import { Plugin } from "vite";
|
|
|
23
23
|
* the behavior with import-chain taint tracking:
|
|
24
24
|
*
|
|
25
25
|
* 1. Seed a `tainted` set with the middleware entry path (and its
|
|
26
|
-
* canonical realpath)
|
|
26
|
+
* canonical realpath), and recognize other neutral server entry modules
|
|
27
|
+
* such as Pages API routes through `isNeutralServerModule`.
|
|
27
28
|
* 2. For every resolveId call from a tainted importer, resolve the import
|
|
28
29
|
* via `this.resolve(..., { skipSelf: true })` and add the resolved id
|
|
29
30
|
* to the tainted set. This propagates the taint along the import graph
|
|
@@ -47,6 +48,7 @@ import { Plugin } from "vite";
|
|
|
47
48
|
declare function createMiddlewareServerOnlyPlugin(options: {
|
|
48
49
|
getMiddlewarePath: () => string | null;
|
|
49
50
|
getCanonicalMiddlewarePath: () => string | null;
|
|
51
|
+
isNeutralServerModule?: (id: string) => boolean;
|
|
50
52
|
serverOnlyShimPath: string;
|
|
51
53
|
}): Plugin;
|
|
52
54
|
//#endregion
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { normalizePathSeparators } from "../utils/path.js";
|
|
2
2
|
//#region src/plugins/middleware-server-only.ts
|
|
3
3
|
/**
|
|
4
|
-
* Allow `import 'server-only'` from
|
|
5
|
-
* from
|
|
4
|
+
* Allow `import 'server-only'` from neutral server targets (and any module
|
|
5
|
+
* reachable from them) in the SSR environment.
|
|
6
6
|
*
|
|
7
7
|
* Background: middleware runs server-side, so importing `server-only` is
|
|
8
8
|
* semantically correct. However, vinext bundles middleware into the SSR
|
|
@@ -12,9 +12,9 @@ import { normalizePathSeparators } from "../utils/path.js";
|
|
|
12
12
|
*
|
|
13
13
|
* 'server-only' cannot be imported in client build ('ssr' environment)
|
|
14
14
|
*
|
|
15
|
-
* Next.js solves this with webpack `issuerLayer` rules: middleware
|
|
16
|
-
*
|
|
17
|
-
* is aliased to a no-op while `client-only` still errors. See
|
|
15
|
+
* Next.js solves this with webpack `issuerLayer` rules: middleware,
|
|
16
|
+
* instrumentation, and Pages API routes sit in server-only or neutral layers
|
|
17
|
+
* where `server-only` is aliased to a no-op while `client-only` still errors. See
|
|
18
18
|
* packages/next/src/build/webpack-config.ts ("Alias server-only and
|
|
19
19
|
* client-only to proper exports based on bundling layers")
|
|
20
20
|
*
|
|
@@ -22,7 +22,8 @@ import { normalizePathSeparators } from "../utils/path.js";
|
|
|
22
22
|
* the behavior with import-chain taint tracking:
|
|
23
23
|
*
|
|
24
24
|
* 1. Seed a `tainted` set with the middleware entry path (and its
|
|
25
|
-
* canonical realpath)
|
|
25
|
+
* canonical realpath), and recognize other neutral server entry modules
|
|
26
|
+
* such as Pages API routes through `isNeutralServerModule`.
|
|
26
27
|
* 2. For every resolveId call from a tainted importer, resolve the import
|
|
27
28
|
* via `this.resolve(..., { skipSelf: true })` and add the resolved id
|
|
28
29
|
* to the tainted set. This propagates the taint along the import graph
|
|
@@ -72,7 +73,7 @@ function createMiddlewareServerOnlyPlugin(options) {
|
|
|
72
73
|
async handler(id, importer, opts) {
|
|
73
74
|
if (this.environment?.name === "rsc") return;
|
|
74
75
|
if (!importer) return;
|
|
75
|
-
if (!isTainted(importer)) return;
|
|
76
|
+
if (!isTainted(importer) && !options.isNeutralServerModule?.(canonicalizeId(importer))) return;
|
|
76
77
|
if (id === "server-only") return {
|
|
77
78
|
id: options.serverOnlyShimPath,
|
|
78
79
|
moduleSideEffects: false
|
|
@@ -23,7 +23,9 @@ type InterceptingRoute = {
|
|
|
23
23
|
sourceMatchPattern: string; /** Absolute path to the intercepting page component */
|
|
24
24
|
pagePath: string; /** Filesystem segments from app/ root to the intercepting page directory. */
|
|
25
25
|
sourcePageSegments?: string[]; /** Absolute layout paths inside the intercepting route tree, outermost to innermost */
|
|
26
|
-
layoutPaths: string[]; /**
|
|
26
|
+
layoutPaths: string[]; /** Normalized branch segments accumulated at each intercept layout. */
|
|
27
|
+
layoutSegments?: string[][]; /** Full normalized interception branch segments through the page. */
|
|
28
|
+
branchSegments?: string[]; /** Parameter names for dynamic segments */
|
|
27
29
|
params: string[];
|
|
28
30
|
/**
|
|
29
31
|
* Synthetic page-carrier slot id for sibling (slot-less) interception.
|
|
@@ -40,7 +42,9 @@ type ParallelSlot = {
|
|
|
40
42
|
hasPage: boolean; /** Absolute path to the slot's page component */
|
|
41
43
|
pagePath: string | null; /** Absolute path to the slot's default.tsx fallback */
|
|
42
44
|
defaultPath: string | null; /** Absolute path to the slot's layout component (wraps slot content) */
|
|
43
|
-
layoutPath: string | null; /**
|
|
45
|
+
layoutPath: string | null; /** Nested active-branch layouts whose exports contribute route config. */
|
|
46
|
+
configLayoutPaths?: string[]; /** Tree positions of configLayoutPaths relative to the slot root. */
|
|
47
|
+
configLayoutTreePositions?: number[]; /** Absolute path to the slot's loading component */
|
|
44
48
|
loadingPath: string | null; /** Absolute path to the slot's error component */
|
|
45
49
|
errorPath: string | null; /** Intercepting routes within this slot */
|
|
46
50
|
interceptingRoutes: InterceptingRoute[];
|