vinext 1.4.1 → 1.4.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 +1 -1
- package/dist/build/action-owner-manifest.js +1 -0
- package/dist/check.js +1 -1
- package/dist/config/config-matchers.js +2 -2
- package/dist/config/destination-params.js +5 -2
- package/dist/config/next-config.d.ts +16 -1
- package/dist/config/next-config.js +31 -1
- package/dist/entries/app-rsc-entry.js +41 -18
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/pages-server-entry.js +2 -0
- package/dist/index.js +15 -12
- package/dist/init-cloudflare.js +18 -2
- package/dist/plugins/css-target.d.ts +18 -0
- package/dist/plugins/css-target.js +93 -0
- package/dist/routing/app-route-graph.d.ts +10 -0
- package/dist/routing/app-route-graph.js +15 -1
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +3 -5
- package/dist/server/app-action-forwarding.js +3 -1
- package/dist/server/app-browser-entry.js +21 -4
- package/dist/server/app-elements.d.ts +3 -0
- package/dist/server/app-elements.js +14 -1
- package/dist/server/app-fallback-renderer.js +2 -2
- package/dist/server/app-optimistic-routing.d.ts +12 -1
- package/dist/server/app-optimistic-routing.js +38 -16
- package/dist/server/app-page-boundary-render.js +2 -2
- package/dist/server/app-page-cache-render.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +73 -30
- package/dist/server/app-page-element-builder.d.ts +9 -20
- package/dist/server/app-page-element-builder.js +37 -49
- package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
- package/dist/server/app-page-intercept-segment-config.js +90 -0
- package/dist/server/app-page-navigation-params.d.ts +23 -0
- package/dist/server/app-page-navigation-params.js +49 -0
- package/dist/server/app-page-render.d.ts +5 -2
- package/dist/server/app-page-render.js +17 -3
- package/dist/server/app-page-request.d.ts +24 -2
- package/dist/server/app-page-request.js +10 -10
- package/dist/server/app-page-route-wiring.d.ts +10 -0
- package/dist/server/app-page-route-wiring.js +16 -12
- package/dist/server/app-page-segment-plan.js +9 -1
- package/dist/server/app-page-segment-state.d.ts +9 -0
- package/dist/server/app-page-segment-state.js +54 -1
- package/dist/server/app-response-stage-entry.js +1 -0
- 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-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +75 -43
- package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
- package/dist/server/app-rsc-response-finalizer.js +11 -1
- package/dist/server/app-rsc-route-matching.d.ts +14 -0
- package/dist/server/app-rsc-route-matching.js +42 -18
- package/dist/server/app-server-action-execution.js +16 -10
- package/dist/server/cache-control.d.ts +2 -0
- package/dist/server/cache-control.js +3 -1
- package/dist/server/image-local-patterns.d.ts +21 -0
- package/dist/server/image-local-patterns.js +59 -0
- package/dist/server/image-optimization.d.ts +23 -22
- package/dist/server/image-optimization.js +12 -2
- package/dist/server/metadata-route-response.js +24 -6
- package/dist/server/nitro-public-files-plugin.js +20 -8
- package/dist/server/pages-data-route.d.ts +5 -1
- package/dist/server/pages-data-route.js +14 -6
- package/dist/server/pages-request-pipeline.js +6 -5
- package/dist/server/pages-request-stage-entry.js +1 -0
- package/dist/server/prod-server.js +17 -9
- package/dist/server/request-pipeline.d.ts +5 -0
- package/dist/server/request-pipeline.js +11 -1
- package/dist/server/response-stage-cacheability.d.ts +7 -0
- package/dist/server/response-stage-cacheability.js +6 -5
- package/dist/server/worker-image-optimization.d.ts +2 -2
- package/dist/server/worker-image-optimization.js +18 -3
- package/dist/server/worker-utils.d.ts +8 -0
- package/dist/server/worker-utils.js +19 -2
- package/dist/shims/image-props.d.ts +6 -0
- package/dist/shims/image-props.js +39 -3
- package/dist/shims/image.js +3 -3
- package/dist/shims/slot.d.ts +3 -0
- package/dist/shims/slot.js +67 -9
- package/dist/utils/base-path.d.ts +7 -0
- package/dist/utils/base-path.js +11 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -687,7 +687,7 @@ Every `next/*` import is shimmed to a Vite-compatible implementation.
|
|
|
687
687
|
| `next.config.js` / `.ts` / `.mjs` | ✅ | Function configs, phase argument |
|
|
688
688
|
| `rewrites` / `redirects` / `headers` | ✅ | All phases, param interpolation. A source Next.js rejects fails config loading, as it fails the Next.js build: missing, not starting with `/`, over the 4,096-character built-regex limit, or rejected by path-to-regexp, such as a header glob `/api/*` |
|
|
689
689
|
| Environment variables (`.env*`, `NEXT_PUBLIC_*`) | ✅ | Auto-loads Next.js-style dotenv files; only public vars are inlined |
|
|
690
|
-
| `images` config | 🟡 | Parsed but not used for optimization
|
|
690
|
+
| `images` config | 🟡 | Parsed but not used for optimization; the production image endpoint enforces `localPatterns` (dev serves any local source) |
|
|
691
691
|
| `experimental.optimizePackageImports` | ✅ | Rewrites barrel imports to direct sub-module imports in RSC/SSR environments. A default set (lucide-react, date-fns, radix-ui, antd, MUI, and others) are always optimized. Add package names here to extend the list. |
|
|
692
692
|
| `vinext({ nextConfig })` | ✅ | Inline Next-style config from `vite.config.*`. Supports object-form and function-form config. When provided, this overrides root `next.config.*`. |
|
|
693
693
|
| `vinext({ react: { compiler: true } })` | ✅ | React Compiler auto memoization. Needs `@vitejs/plugin-react` 6.1+ and the optional `oxc-transform-react` package. |
|
package/dist/check.js
CHANGED
|
@@ -197,7 +197,7 @@ const CONFIG_SUPPORT = {
|
|
|
197
197
|
env: { status: "supported" },
|
|
198
198
|
images: {
|
|
199
199
|
status: "partial",
|
|
200
|
-
detail: "remotePatterns, deviceSizes/imageSizes, qualities and SVG/CSP options honoured; resizing needs an optimizer via vinext({ images: { optimizer } }), images are served as-is otherwise; loader/loaderFile are ignored"
|
|
200
|
+
detail: "remotePatterns, deviceSizes/imageSizes, qualities, localPatterns (production only) and SVG/CSP options honoured; resizing needs an optimizer via vinext({ images: { optimizer } }), images are served as-is otherwise; loader/loaderFile are ignored"
|
|
201
201
|
},
|
|
202
202
|
allowedDevOrigins: {
|
|
203
203
|
status: "supported",
|
|
@@ -719,7 +719,7 @@ function preserveRedirectDestinationQuery(destination, requestSearch, destinatio
|
|
|
719
719
|
}
|
|
720
720
|
const LOCATION_STRIPPED_RE = /^[\u0000- ]+|[\u0000- ]+$|[\t\n\r]/g;
|
|
721
721
|
const LOCATION_UNSAFE_RE = /[\u0000-\u0008\u000A-\u001F\u007F]|[^\u0000-\u007F]/gu;
|
|
722
|
-
const
|
|
722
|
+
const SURROGATE_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDFFF]/g;
|
|
723
723
|
/**
|
|
724
724
|
* Percent-encode what a config-redirect `Location` header cannot carry.
|
|
725
725
|
*
|
|
@@ -731,7 +731,7 @@ const LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF
|
|
|
731
731
|
* constructor throws the same way); vinext percent-encodes them instead.
|
|
732
732
|
*/
|
|
733
733
|
function encodeRedirectLocation(location) {
|
|
734
|
-
return location.replace(
|
|
734
|
+
return location.replace(SURROGATE_RE, (surrogate) => surrogate.length === 2 ? surrogate : "�").replace(LOCATION_UNSAFE_RE, encodeURIComponent);
|
|
735
735
|
}
|
|
736
736
|
function parseExternalRewriteUrl(externalUrl) {
|
|
737
737
|
try {
|
|
@@ -91,9 +91,12 @@ function substituteRewritePath(template, paramRe, params, absolute) {
|
|
|
91
91
|
const [path, hash] = substituted.split("#", 2);
|
|
92
92
|
const pathHash = hash === void 0 ? void 0 : hash ? `#${hash}` : "";
|
|
93
93
|
if (!absolute) return [path, pathHash];
|
|
94
|
-
return [path.replace(DOT_SEGMENT_RE, (
|
|
94
|
+
return [path.replace(DOT_SEGMENT_RE, (_match, separator, segment, offset) => {
|
|
95
|
+
const start = offset + separator.length;
|
|
96
|
+
return paramRanges.some(([paramStart, end]) => paramStart <= start + segment.length && end >= start) ? separator + segment.replace(/\.|%(?=2e)/gi, (char) => char === "." ? "%252E" : "%25") : separator + segment;
|
|
97
|
+
}), pathHash];
|
|
95
98
|
}
|
|
96
|
-
const DOT_SEGMENT_RE = /(
|
|
99
|
+
const DOT_SEGMENT_RE = /(^|[/\\])((?:\.|%2e){1,2})(?=[/\\]|$)/gi;
|
|
97
100
|
function encodePathQueryDelimiter(value) {
|
|
98
101
|
return value.replaceAll("?", "%3F");
|
|
99
102
|
}
|
|
@@ -183,12 +183,27 @@ export type NextConfig = {
|
|
|
183
183
|
search?: string;
|
|
184
184
|
}>;
|
|
185
185
|
domains?: string[];
|
|
186
|
+
/**
|
|
187
|
+
* Local sources the image optimization endpoint may serve. Statically
|
|
188
|
+
* imported images are allowed too, except under a basePath (the added
|
|
189
|
+
* pattern is unprefixed, as in Next.js). When unset, any local path
|
|
190
|
+
* without a query string is allowed (matches Next.js).
|
|
191
|
+
*/
|
|
192
|
+
localPatterns?: Array<{
|
|
193
|
+
pathname?: string;
|
|
194
|
+
search?: string;
|
|
195
|
+
}>;
|
|
186
196
|
unoptimized?: boolean;
|
|
187
197
|
/** Allowed device widths for image optimization. Defaults to Next.js defaults: [640, 750, 828, 1080, 1200, 1920, 2048, 3840] */
|
|
188
198
|
deviceSizes?: number[];
|
|
189
199
|
/** Allowed image sizes for fixed-width images. Defaults to Next.js defaults: [32, 48, 64, 96, 128, 256, 384] */
|
|
190
200
|
imageSizes?: number[];
|
|
191
|
-
/**
|
|
201
|
+
/**
|
|
202
|
+
* Allowed image qualities. When set, the endpoint accepts only these and the
|
|
203
|
+
* default loader rounds `quality` to the closest entry, as in Next.js. When
|
|
204
|
+
* unset, any quality from 1-100 is permitted: a deliberate divergence from
|
|
205
|
+
* Next.js 16's `[75]` default that keeps Next.js 14/15 apps working.
|
|
206
|
+
*/
|
|
192
207
|
qualities?: number[];
|
|
193
208
|
/** Allow SVG images through the image optimization endpoint. SVG can contain scripts, so only enable if you trust all image sources. */
|
|
194
209
|
dangerouslyAllowSVG?: boolean;
|
|
@@ -507,6 +507,35 @@ async function resolveBuildId(generate) {
|
|
|
507
507
|
return trimmed;
|
|
508
508
|
}
|
|
509
509
|
/**
|
|
510
|
+
* Mirror Next.js's config resolution of `images.localPatterns`: statically
|
|
511
|
+
* imported images (`/_next/static/media/**`) stay allowed whatever the app
|
|
512
|
+
* lists, though like Next.js the pattern is unprefixed, so it never matches
|
|
513
|
+
* under a basePath. An unset list stays unset; the image endpoint then applies the
|
|
514
|
+
* Next.js default.
|
|
515
|
+
*/
|
|
516
|
+
function resolveImageLocalPatterns(localPatterns) {
|
|
517
|
+
if (localPatterns === void 0) return void 0;
|
|
518
|
+
if (!Array.isArray(localPatterns)) throw new Error(`Specified images.localPatterns should be an Array received ${localPatterns === null ? "null" : typeof localPatterns}.\nSee more info here: https://nextjs.org/docs/messages/invalid-images-config`);
|
|
519
|
+
if (localPatterns.length > 25) throw new Error("Specified images.localPatterns can have at most 25 entries.");
|
|
520
|
+
const patterns = Array.from(localPatterns, (pattern, index) => {
|
|
521
|
+
const entry = pattern;
|
|
522
|
+
let valid = typeof pattern === "object" && pattern !== null && !Array.isArray(pattern) && !(pattern instanceof Date) && !(pattern instanceof Map) && !(pattern instanceof Set) && !(typeof entry.then === "function" && typeof pattern.catch === "function") && (entry.pathname === void 0 || typeof entry.pathname === "string") && (entry.search === void 0 || typeof entry.search === "string");
|
|
523
|
+
if (valid) {
|
|
524
|
+
for (const key in pattern) if (key !== "pathname" && key !== "search") valid = false;
|
|
525
|
+
}
|
|
526
|
+
if (!valid) throw new Error(`Specified images.localPatterns[${index}] should be an object with optional string \`pathname\` and \`search\` fields.`);
|
|
527
|
+
const resolved = {};
|
|
528
|
+
if (entry.pathname !== void 0) resolved.pathname = entry.pathname;
|
|
529
|
+
if (entry.search !== void 0) resolved.search = entry.search;
|
|
530
|
+
return resolved;
|
|
531
|
+
});
|
|
532
|
+
if (!patterns.some((pattern) => pattern.pathname === "/_next/static/media/**" && pattern.search === "")) patterns.push({
|
|
533
|
+
pathname: "/_next/static/media/**",
|
|
534
|
+
search: ""
|
|
535
|
+
});
|
|
536
|
+
return patterns;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
510
539
|
* Normalize the `assetPrefix` option from next.config.
|
|
511
540
|
*
|
|
512
541
|
* Accepts both absolute URLs (`https://cdn.example.com[/subpath]`) and
|
|
@@ -1094,7 +1123,8 @@ async function resolveNextConfig(config, root = toSlash(process.cwd()), options
|
|
|
1094
1123
|
port: pattern.port,
|
|
1095
1124
|
pathname: pattern.pathname,
|
|
1096
1125
|
search: pattern.search
|
|
1097
|
-
} : { ...pattern })
|
|
1126
|
+
} : { ...pattern }),
|
|
1127
|
+
localPatterns: resolveImageLocalPatterns(config.images.localPatterns)
|
|
1098
1128
|
} : void 0;
|
|
1099
1129
|
const resolved = {
|
|
1100
1130
|
env: config.env ?? {},
|
|
@@ -94,9 +94,10 @@ function appPageSegmentConfigPaths(route) {
|
|
|
94
94
|
];
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
|
-
* Patterns of the static App pages that answer a request whose raw
|
|
98
|
-
* reaches a dynamic sibling but whose segment-decoded pathname names
|
|
99
|
-
* `/%61` and `/caf%C3%A9` render `/a` and `/café` rather than
|
|
97
|
+
* Patterns of the static App pages that may answer a request whose raw
|
|
98
|
+
* pathname reaches a dynamic sibling but whose segment-decoded pathname names
|
|
99
|
+
* them, so `/%61` and `/caf%C3%A9` can render `/a` and `/café` rather than
|
|
100
|
+
* `/[slug]`.
|
|
100
101
|
*
|
|
101
102
|
* Next.js serves those requests from the response cached under the decoded
|
|
102
103
|
* pathname, which exists only for a page it prerendered. The prerender listing
|
|
@@ -105,7 +106,10 @@ function appPageSegmentConfigPaths(route) {
|
|
|
105
106
|
* runtime on any segment) and a Route Handler have no such entry, so the
|
|
106
107
|
* dynamic sibling renders. So does a page whose sources can't be read here;
|
|
107
108
|
* its sibling's render stays out of the shared caches. A cacheComponents
|
|
108
|
-
* build lists every page route, as the prerender listing does.
|
|
109
|
+
* build lists every page route, as the prerender listing does. Segment config
|
|
110
|
+
* can't tell a page that reads request data, so the matcher renders the page
|
|
111
|
+
* for another spelling (`/%61dmin`) only once the build recorded the decoded
|
|
112
|
+
* pathname's prerender; the browser's own spelling needs none.
|
|
109
113
|
*/
|
|
110
114
|
function buildAppDecodedPathnamePatterns(routes, config) {
|
|
111
115
|
const isPrerenderedPage = (route) => {
|
|
@@ -148,6 +152,10 @@ function buildAppRequestRouteMetadata(routes) {
|
|
|
148
152
|
slots: Object.fromEntries(route.parallelSlots.map((slot) => [slot.key, {
|
|
149
153
|
id: slot.id ?? null,
|
|
150
154
|
name: slot.name,
|
|
155
|
+
__loadPage: slot.pagePath ? true : null,
|
|
156
|
+
__loadDefault: slot.defaultPath ? true : null,
|
|
157
|
+
slotPatternParts: slot.slotPatternParts ?? null,
|
|
158
|
+
slotParamNames: slot.slotParamNames ?? null,
|
|
151
159
|
intercepts: slot.interceptingRoutes.map((intercept) => ({
|
|
152
160
|
id: intercept.id ?? null,
|
|
153
161
|
targetPattern: intercept.targetPattern,
|
|
@@ -244,6 +252,8 @@ import { dispatchAppRequestStage as __dispatchAppRequestStage } from ${JSON.stri
|
|
|
244
252
|
import { registerConfiguredCacheAdapters as __registerConfiguredCacheAdapters } from "virtual:vinext-cdn-cache-adapter";
|
|
245
253
|
import { clearAppRequestStageContext as __clearRequestContext, setAppRequestStageNavigationContext as setNavigationContext } from ${JSON.stringify(appRequestStageContextPath)};
|
|
246
254
|
import { matchRoutePattern as __matchRoutePattern } from ${JSON.stringify(routePatternPath)};
|
|
255
|
+
import { initPregeneratedPathsFromGlobals as __initPregeneratedPathsFromGlobals } from ${JSON.stringify(pregeneratedConcretePathsPath)};
|
|
256
|
+
import "virtual:vinext-pregenerated-concrete-paths";
|
|
247
257
|
import __pagesClientAssets from "virtual:vinext-pages-client-assets";
|
|
248
258
|
${middlewarePath ? `import { applyAppMiddleware as __applyAppMiddleware } from ${JSON.stringify(appMiddlewarePath)};` : ""}
|
|
249
259
|
${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(toSlash(instrumentationPath))};
|
|
@@ -278,12 +288,16 @@ export { __basePath };
|
|
|
278
288
|
export const __imageAllowedWidths = ${JSON.stringify([...config?.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...config?.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES])};
|
|
279
289
|
export const __imageConfig = ${JSON.stringify({
|
|
280
290
|
qualities: config?.imageConfig?.qualities,
|
|
291
|
+
localPatterns: config?.imageConfig?.localPatterns,
|
|
281
292
|
dangerouslyAllowSVG: config?.imageConfig?.dangerouslyAllowSVG,
|
|
282
293
|
dangerouslyAllowLocalIP: config?.imageConfig?.dangerouslyAllowLocalIP,
|
|
283
294
|
contentDispositionType: config?.imageConfig?.contentDispositionType,
|
|
284
295
|
contentSecurityPolicy: config?.imageConfig?.contentSecurityPolicy
|
|
285
296
|
})};
|
|
286
297
|
export const __clientBuildFiles = __pagesClientAssets.clientBuildFiles ?? [];
|
|
298
|
+
// The matcher reads recorded prerenders, and this stage can run without the
|
|
299
|
+
// response entry that also loads them.
|
|
300
|
+
__initPregeneratedPathsFromGlobals();
|
|
287
301
|
const __routes = ${JSON.stringify(requestRoutes)};
|
|
288
302
|
const __routeMatcher = __createAppRscRouteMatcher(__routes, ${JSON.stringify(buildAppDecodedPathnamePatterns(routes, config))});
|
|
289
303
|
const __metadataRouteMatchers = ${JSON.stringify(metadataRouteMatchers)};
|
|
@@ -354,17 +368,21 @@ const __requestHandler = createAppRscRequestHandler({
|
|
|
354
368
|
const intercept = __routeMatcher.findIntercept(pathname, sourcePathname, interceptionId);
|
|
355
369
|
if (!intercept) return null;
|
|
356
370
|
const route = __routes[intercept.sourceRouteIndex];
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
371
|
+
const authorizationRoute = __routes[intercept.authorizationSourceRouteIndex];
|
|
372
|
+
if (!route || !authorizationRoute) return null;
|
|
373
|
+
const pickParams = (targetRoute, source) => {
|
|
374
|
+
const params = Object.create(null);
|
|
375
|
+
for (const name of targetRoute.params) {
|
|
376
|
+
if (Object.prototype.hasOwnProperty.call(source, name)) params[name] = source[name];
|
|
362
377
|
}
|
|
363
|
-
|
|
378
|
+
return params;
|
|
379
|
+
};
|
|
364
380
|
return {
|
|
381
|
+
authorizationParams: pickParams(authorizationRoute, intercept.authorizationSourceParams),
|
|
382
|
+
authorizationRoute,
|
|
365
383
|
interceptionSourceIsConcrete: intercept.sourceRouteIsConcrete,
|
|
366
384
|
route,
|
|
367
|
-
params,
|
|
385
|
+
params: pickParams(route, intercept.sourceMatchedParams),
|
|
368
386
|
};
|
|
369
387
|
},
|
|
370
388
|
${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, validateExternalRewriteRequest }) {
|
|
@@ -482,6 +500,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
482
500
|
const imageAllowedWidths = [...config?.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...config?.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES];
|
|
483
501
|
const imageConfig = {
|
|
484
502
|
qualities: config?.imageConfig?.qualities,
|
|
503
|
+
localPatterns: config?.imageConfig?.localPatterns,
|
|
485
504
|
dangerouslyAllowSVG: config?.imageConfig?.dangerouslyAllowSVG,
|
|
486
505
|
dangerouslyAllowLocalIP: config?.imageConfig?.dangerouslyAllowLocalIP,
|
|
487
506
|
contentDispositionType: config?.imageConfig?.contentDispositionType,
|
|
@@ -1635,17 +1654,21 @@ ${responseStageOnly ? "const __responseStageOptions = {" : "const __appRscHandle
|
|
|
1635
1654
|
const intercept = findIntercept(pathname, sourcePathname, interceptionId);
|
|
1636
1655
|
if (!intercept) return null;
|
|
1637
1656
|
const route = routes[intercept.sourceRouteIndex];
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1657
|
+
const authorizationRoute = routes[intercept.authorizationSourceRouteIndex];
|
|
1658
|
+
if (!route || !authorizationRoute) return null;
|
|
1659
|
+
const pickParams = (targetRoute, source) => {
|
|
1660
|
+
const params = Object.create(null);
|
|
1661
|
+
for (const name of targetRoute.params) {
|
|
1662
|
+
if (Object.prototype.hasOwnProperty.call(source, name)) params[name] = source[name];
|
|
1643
1663
|
}
|
|
1644
|
-
|
|
1664
|
+
return params;
|
|
1665
|
+
};
|
|
1645
1666
|
return {
|
|
1667
|
+
authorizationParams: pickParams(authorizationRoute, intercept.authorizationSourceParams),
|
|
1668
|
+
authorizationRoute,
|
|
1646
1669
|
interceptionSourceIsConcrete: intercept.sourceRouteIsConcrete,
|
|
1647
1670
|
route,
|
|
1648
|
-
params,
|
|
1671
|
+
params: pickParams(route, intercept.sourceMatchedParams),
|
|
1649
1672
|
};
|
|
1650
1673
|
},
|
|
1651
1674
|
${middlewarePath ? `runMiddleware({ cleanPathname, context, externalRewriteRequest, hadBasePath, isDataRequest, middlewareRequest, request, validateExternalRewriteRequest }) {
|
|
@@ -108,6 +108,7 @@ function registerRouteModules(routes, imports) {
|
|
|
108
108
|
if (slot.loadingPath) imports.getLazyLoaderVar(slot.loadingPath);
|
|
109
109
|
for (const loadingPath of slot.loadingPaths ?? []) imports.getLazyLoaderVar(loadingPath);
|
|
110
110
|
if (slot.errorPath) imports.getLazyLoaderVar(slot.errorPath);
|
|
111
|
+
for (const errorPath of slot.errorPaths ?? []) imports.getLazyLoaderVar(errorPath);
|
|
111
112
|
if (slot.notFoundPath) imports.getLazyLoaderVar(slot.notFoundPath);
|
|
112
113
|
for (const notFoundPath of slot.notFoundPaths ?? []) imports.getLazyLoaderVar(notFoundPath);
|
|
113
114
|
for (const ir of slot.interceptingRoutes) {
|
|
@@ -240,6 +241,9 @@ function buildRouteEntries(routes, imports) {
|
|
|
240
241
|
loadingTreePositions: ${JSON.stringify(slot.loadingTreePositions ?? [])},
|
|
241
242
|
error: null,
|
|
242
243
|
__loadError: ${slot.errorPath ? imports.getLazyLoaderVar(slot.errorPath) : "null"},
|
|
244
|
+
errors: ${moduleArray(slot.errorPaths?.length ?? 0)},
|
|
245
|
+
__loadErrors: ${lazyLoaderArray(slot.errorPaths ?? [], imports)},
|
|
246
|
+
errorTreePositions: ${JSON.stringify(slot.errorTreePositions ?? [])},
|
|
243
247
|
notFound: null,
|
|
244
248
|
__loadNotFound: ${slot.notFoundPath ? imports.getLazyLoaderVar(slot.notFoundPath) : "null"},
|
|
245
249
|
notFoundTreePosition: ${slot.notFoundTreePosition ?? "null"},
|
|
@@ -104,6 +104,7 @@ async function generatePagesRequestEntry(pagesDir, nextConfig, fileMatcher, midd
|
|
|
104
104
|
deviceSizes: nextConfig?.images?.deviceSizes,
|
|
105
105
|
imageSizes: nextConfig?.images?.imageSizes,
|
|
106
106
|
qualities: nextConfig?.images?.qualities,
|
|
107
|
+
localPatterns: nextConfig?.images?.localPatterns,
|
|
107
108
|
dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
|
|
108
109
|
dangerouslyAllowLocalIP: nextConfig?.images?.dangerouslyAllowLocalIP,
|
|
109
110
|
contentDispositionType: nextConfig?.images?.contentDispositionType,
|
|
@@ -281,6 +282,7 @@ async function generateServerEntry(pagesDir, nextConfig, fileMatcher, middleware
|
|
|
281
282
|
deviceSizes: nextConfig?.images?.deviceSizes,
|
|
282
283
|
imageSizes: nextConfig?.images?.imageSizes,
|
|
283
284
|
qualities: nextConfig?.images?.qualities,
|
|
285
|
+
localPatterns: nextConfig?.images?.localPatterns,
|
|
284
286
|
dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
|
|
285
287
|
dangerouslyAllowLocalIP: nextConfig?.images?.dangerouslyAllowLocalIP,
|
|
286
288
|
contentDispositionType: nextConfig?.images?.contentDispositionType,
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from "./shims/consta
|
|
|
14
14
|
import { serializeCacheLifeProfiles } from "./utils/cache-life-profiles.js";
|
|
15
15
|
import { VINEXT_MW_CTX_HEADER } from "./utils/protocol-headers.js";
|
|
16
16
|
import { encodeMiddlewareRequestHeaders } from "./utils/middleware-request-headers.js";
|
|
17
|
-
import { hasBasePath, stripBasePath } from "./utils/base-path.js";
|
|
17
|
+
import { hasBasePath, restoreBasePath, stripBasePath } from "./utils/base-path.js";
|
|
18
18
|
import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_TIMING_HEADER } from "./server/headers.js";
|
|
19
19
|
import { methodNotAllowedResponse, notFoundStaticAssetResponse } from "./server/http-error-responses.js";
|
|
20
20
|
import { isOpenRedirectShaped, sendRepeatedSlashRedirect } from "./server/open-redirect.js";
|
|
@@ -89,6 +89,7 @@ import { createClientCompileHintsPlugin } from "./plugins/client-compile-hints.j
|
|
|
89
89
|
import { clientReferenceDedupPlugin } from "./plugins/client-reference-dedup.js";
|
|
90
90
|
import { dataUrlCssPlugin } from "./plugins/css-data-url.js";
|
|
91
91
|
import { createCssModuleImportCompatibilityPlugin } from "./plugins/css-module-imports.js";
|
|
92
|
+
import { createCssTargetPlugin } from "./plugins/css-target.js";
|
|
92
93
|
import { createWorkerImageImportsPlugin } from "./plugins/worker-image-imports.js";
|
|
93
94
|
import { assertClientOutDirIsSeparate, createClientAssetFileNames, createClientCodeSplittingConfig, createClientManualChunks, createClientOutputFileNameDefaults, createMultiStageChunkFileNames, createMultiStageCodeSplittingConfig, createRscFrameworkChunkOutputConfig, createWorkerFileNames, findUnsupportedClientOutputFileNames, getBuildBundlerOptions, getClientTreeshakeConfig, getOutputFileNames, withBuildBundlerOptions } from "./build/client-build-config.js";
|
|
94
95
|
import { createRouteClientReferencesFallbackPlugin, createRscClientReferenceLoadersPlugin } from "./plugins/rsc-client-reference-loaders.js";
|
|
@@ -1466,6 +1467,7 @@ function vinext(options = {}) {
|
|
|
1466
1467
|
}),
|
|
1467
1468
|
dataUrlCssPlugin(),
|
|
1468
1469
|
createCssModuleImportCompatibilityPlugin(),
|
|
1470
|
+
createCssTargetPlugin(),
|
|
1469
1471
|
createDevServerLifecyclePlugin({}, (config) => config[VINEXT_DEV_CLI_LIFECYCLE] === true),
|
|
1470
1472
|
{
|
|
1471
1473
|
name: "vinext:config",
|
|
@@ -1764,12 +1766,6 @@ function vinext(options = {}) {
|
|
|
1764
1766
|
} } : {},
|
|
1765
1767
|
build: {
|
|
1766
1768
|
ssrEmitAssets: true,
|
|
1767
|
-
cssTarget: [
|
|
1768
|
-
"chrome111",
|
|
1769
|
-
"edge111",
|
|
1770
|
-
"firefox114",
|
|
1771
|
-
"safari15"
|
|
1772
|
-
],
|
|
1773
1769
|
assetsDir: clientAssetsDir,
|
|
1774
1770
|
...!isSSR && !hasClientBuildEnvironment ? { assetsInlineLimit: clientAssetsInlineLimit } : {},
|
|
1775
1771
|
...withBuildBundlerOptions({
|
|
@@ -2453,6 +2449,7 @@ function vinext(options = {}) {
|
|
|
2453
2449
|
deviceSizes: nextConfig?.images?.deviceSizes,
|
|
2454
2450
|
imageSizes: nextConfig?.images?.imageSizes,
|
|
2455
2451
|
qualities: nextConfig?.images?.qualities,
|
|
2452
|
+
localPatterns: nextConfig?.images?.localPatterns,
|
|
2456
2453
|
dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
|
|
2457
2454
|
dangerouslyAllowLocalIP: nextConfig?.images?.dangerouslyAllowLocalIP,
|
|
2458
2455
|
contentDispositionType: nextConfig?.images?.contentDispositionType,
|
|
@@ -3378,14 +3375,17 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
3378
3375
|
const viteBase = server.config.base;
|
|
3379
3376
|
const viteBasePath = viteBase.startsWith("/") && viteBase !== "/" ? viteBase.replace(/\/+$/, "") : "";
|
|
3380
3377
|
const routingBasePath = bp || viteBasePath;
|
|
3378
|
+
const viteStrippedBasePath = originalRequestUrl !== originalEncodedUrl;
|
|
3379
|
+
let originalUrlHadBasePath = false;
|
|
3381
3380
|
if (routingBasePath) {
|
|
3382
|
-
if (hasBasePath(pathname, routingBasePath)) {
|
|
3381
|
+
if (!viteStrippedBasePath && hasBasePath(pathname, routingBasePath)) {
|
|
3383
3382
|
const stripped = stripBasePath(pathname, routingBasePath);
|
|
3384
3383
|
url = stripped + (url.includes("?") ? url.slice(url.indexOf("?")) : "");
|
|
3385
3384
|
pathname = stripped;
|
|
3386
3385
|
}
|
|
3387
3386
|
const middlewarePathname = middlewareUrl.split("?")[0];
|
|
3388
3387
|
if (hasBasePath(middlewarePathname, routingBasePath)) {
|
|
3388
|
+
originalUrlHadBasePath = true;
|
|
3389
3389
|
const middlewareQs = middlewareUrl.includes("?") ? middlewareUrl.slice(middlewareUrl.indexOf("?")) : "";
|
|
3390
3390
|
middlewareUrl = stripBasePath(middlewarePathname, routingBasePath) + middlewareQs;
|
|
3391
3391
|
}
|
|
@@ -3395,7 +3395,7 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
3395
3395
|
routeUrl = stripBasePath(routePathname, routingBasePath) + routeQs;
|
|
3396
3396
|
}
|
|
3397
3397
|
}
|
|
3398
|
-
let configMatchPathname =
|
|
3398
|
+
let configMatchPathname = middlewareUrl.split("?")[0];
|
|
3399
3399
|
if (nextConfig && !nextConfig.skipTrailingSlashRedirect) {
|
|
3400
3400
|
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
3401
3401
|
const trailingSlashRedirect = normalizeTrailingSlash(routeUrl.split("?")[0], bp, nextConfig.trailingSlash, qs);
|
|
@@ -3412,7 +3412,7 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
3412
3412
|
const rawRoutePathname = routeUrl.split("?")[0];
|
|
3413
3413
|
if (isNextDataPathname(rawRoutePathname)) {
|
|
3414
3414
|
const rawDataMatch = parseNextDataPathname(rawRoutePathname, devBuildId);
|
|
3415
|
-
const dataMatch = rawDataMatch ? parseNextDataPathname(pathname, devBuildId) : null;
|
|
3415
|
+
const dataMatch = rawDataMatch ? parseNextDataPathname(pathname, devBuildId, true) : null;
|
|
3416
3416
|
if (dataMatch && rawDataMatch) {
|
|
3417
3417
|
isDataReq = true;
|
|
3418
3418
|
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
@@ -3482,7 +3482,9 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
3482
3482
|
const devRunMiddlewareAdapter = capturedMiddlewarePath ? async (_request, _ctx, opts) => {
|
|
3483
3483
|
const rawProto = process.env.VINEXT_TRUST_PROXY === "1" || (process.env.VINEXT_TRUSTED_HOSTS ?? "").split(",").some((h) => h.trim()) ? String(req.headers["x-forwarded-proto"] || "").split(",")[0].trim() : "";
|
|
3484
3484
|
const mwOrigin = `${rawProto === "https" || rawProto === "http" ? rawProto : "http"}://${requestHost}`;
|
|
3485
|
-
const
|
|
3485
|
+
const middlewareRequestUrl = new URL(middlewareUrl, mwOrigin);
|
|
3486
|
+
if (originalUrlHadBasePath) middlewareRequestUrl.pathname = restoreBasePath(middlewareRequestUrl.pathname, bp);
|
|
3487
|
+
const middlewareRequest = new Request(middlewareRequestUrl, {
|
|
3486
3488
|
method: req.method,
|
|
3487
3489
|
headers: nodeRequestHeaders,
|
|
3488
3490
|
signal: webRequest.signal
|
|
@@ -3628,7 +3630,8 @@ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.
|
|
|
3628
3630
|
trustedRevalidateOrigin: getTrustedDevRevalidateOrigin(),
|
|
3629
3631
|
allowedRevalidateHeaderKeys: nextConfig?.allowedRevalidateHeaderKeys,
|
|
3630
3632
|
trailingSlash: nextConfig?.trailingSlash,
|
|
3631
|
-
skipTrailingSlashRedirect: nextConfig?.skipTrailingSlashRedirect
|
|
3633
|
+
skipTrailingSlashRedirect: nextConfig?.skipTrailingSlashRedirect,
|
|
3634
|
+
requestPathname: originalUrlHadBasePath ? restoreBasePath(routeUrl.split("?")[0], bp) : routeUrl.split("?")[0]
|
|
3632
3635
|
})) return;
|
|
3633
3636
|
if (hasAppDir) {
|
|
3634
3637
|
if (pipelineResult.configRewriteFired) forwardInternalApiRewriteToApp(pipelineResult.apiUrl);
|
package/dist/init-cloudflare.js
CHANGED
|
@@ -140,7 +140,7 @@ function setupCloudflarePlatform(context, cloudflare) {
|
|
|
140
140
|
generatedPlatformFiles.push(path.relative(context.root, responseStorePath) || RESPONSE_STORE_WRANGLER_CONFIG);
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
-
const nextSteps = [];
|
|
143
|
+
const nextSteps = !wranglerCode || !findTopLevelJsonProperty(wranglerCode, "main") ? workerEntryWarning(context.root, context.isStaticExport) : [];
|
|
144
144
|
if (cloudflare.cdnCache === "response-store" && (cloudflare.responseStoreMode ?? "service-binding") === "service-binding") nextSteps.push("Deploy Workers Response Store before deploying the application:", ` ${context.packageManager ?? "npm"} run deploy:response-store`);
|
|
145
145
|
if (cloudflare.prerender && cloudflare.cdnCache !== "static-assets") nextSteps.push("Pre-rendered routes are built, but Cloudflare deploys do not serve them.", " Use the Static Assets cache to serve them, or cache warming to fill another cache.");
|
|
146
146
|
return {
|
|
@@ -193,14 +193,15 @@ function setupCfPlatform(context, cloudflare) {
|
|
|
193
193
|
}
|
|
194
194
|
const configPath = path.join(context.root, "cloudflare.config.ts");
|
|
195
195
|
const generatedPlatformFiles = [];
|
|
196
|
+
const nextSteps = [];
|
|
196
197
|
if (!fs.existsSync(configPath)) {
|
|
197
198
|
fs.writeFileSync(configPath, generateTypedCloudflareConfig({
|
|
198
199
|
...projectInfo,
|
|
199
200
|
isStaticExport: context.isStaticExport
|
|
200
201
|
}, cloudflare, context.today));
|
|
201
202
|
generatedPlatformFiles.push("cloudflare.config.ts");
|
|
203
|
+
nextSteps.push(...workerEntryWarning(context.root, context.isStaticExport));
|
|
202
204
|
}
|
|
203
|
-
const nextSteps = [];
|
|
204
205
|
if (serviceBinding) nextSteps.push("After `vinext build`, deploy the Response Store Worker explicitly (and repeat when its code/config changes):", ` ${context.packageManager ?? "npm"} run deploy:response-store`, "vinext-cloudflare deploy only deploys the application Worker.");
|
|
205
206
|
if (cloudflare.prerender && cloudflare.cdnCache !== "static-assets") nextSteps.push("Pre-rendered routes are built, but Cloudflare deploys do not serve them.", " Use the Static Assets cache to serve them, or cache warming to fill another cache.");
|
|
206
207
|
nextSteps.push("For TypeScript, add \".cloudflare/types\" to the include list in tsconfig.json.", "Worker types are generated during dev/build; run `cf workers types` before standalone type-checks.");
|
|
@@ -280,6 +281,21 @@ function resolveWorkerEntry(root) {
|
|
|
280
281
|
return "vinext/server/fetch-handler";
|
|
281
282
|
}
|
|
282
283
|
/**
|
|
284
|
+
* A `worker/index.*` that never reaches vinext's handler (say, a migrated Vite
|
|
285
|
+
* SPA's API Worker) answers every page route itself, so each one 404s (#4460).
|
|
286
|
+
*/
|
|
287
|
+
function workerEntryWarning(root, isStaticExport) {
|
|
288
|
+
if (isStaticExport) return [];
|
|
289
|
+
const entry = resolveWorkerEntry(root);
|
|
290
|
+
if (entry === "vinext/server/fetch-handler") return [];
|
|
291
|
+
if (fs.readFileSync(path.join(root, entry), "utf-8").includes("vinext/server/fetch-handler")) return [];
|
|
292
|
+
return [
|
|
293
|
+
`Warning: ${entry.slice(2)} does not import vinext/server/fetch-handler. As the Worker entry`,
|
|
294
|
+
" it must hand requests to vinext, or every page 404s. Otherwise point the Worker entry",
|
|
295
|
+
" (entrypoint in cloudflare.config.ts, or main in wrangler.jsonc) at vinext/server/fetch-handler."
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
283
299
|
* Next.js runs no middleware for a static export, and an export with
|
|
284
300
|
* `trailingSlash` relies on the default html_handling to serve `/about/` from
|
|
285
301
|
* `about/index.html`, so export apps keep asset-first serving.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
//#region src/plugins/css-target.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Applies {@link DEFAULT_CSS_TARGET} only where nobody chose a target (#4413).
|
|
5
|
+
*
|
|
6
|
+
* Vite merges config by concatenating arrays, and the CSS minifier keeps the
|
|
7
|
+
* oldest version of each browser, so a pin merged onto a chosen target would
|
|
8
|
+
* stop an app from ever raising it. Instead nothing is set while config hooks
|
|
9
|
+
* run, so the app and every plugin hook see and merge plain Vite values. The
|
|
10
|
+
* post-ordered `config` and `configEnvironment` hooks only note where a target
|
|
11
|
+
* was set, and the pin is applied once config is resolved.
|
|
12
|
+
*
|
|
13
|
+
* Both the top-level `build`, which Vite's CSS plugin minifies with (a copy of
|
|
14
|
+
* the environment's in per-environment builds), and every environment's `build`
|
|
15
|
+
* are checked.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createCssTargetPlugin(): Plugin;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
//#region src/plugins/css-target.ts
|
|
2
|
+
/**
|
|
3
|
+
* CSS minification target. Vite defaults it to the same target as JS
|
|
4
|
+
* (modern evergreens), which lets the CSS minifier (Lightning CSS by
|
|
5
|
+
* default, or esbuild) rewrite
|
|
6
|
+
* `@media (max-width: 768px)` to the Media Queries Level 4 range
|
|
7
|
+
* syntax `@media (width <= 768px)`. Both forms are semantically
|
|
8
|
+
* equivalent in modern browsers, but the rewrite is observable to
|
|
9
|
+
* user code that inspects `cssText` of `CSSMediaRule`s and breaks
|
|
10
|
+
* tools that pattern-match the raw query string. Next.js does not
|
|
11
|
+
* perform this rewrite by default (its webpack/lightningcss CSS
|
|
12
|
+
* pipeline preserves the original syntax), so user code carried
|
|
13
|
+
* over from Next.js can break when migrating to vinext.
|
|
14
|
+
*
|
|
15
|
+
* The minifier lowers a CSS feature when ANY target in the list lacks
|
|
16
|
+
* support, so we only need to pin one engine below the range-syntax
|
|
17
|
+
* baseline. Range syntax shipped in Chrome 104, Edge 104, Firefox 63,
|
|
18
|
+
* and Safari 16.4 (per esbuild's `internal/compat/css_table.go`
|
|
19
|
+
* MediaRange entry — and caniuse). Of those, Safari is the latest:
|
|
20
|
+
* pinning `safari15` (semantically Safari 15.0, which predates
|
|
21
|
+
* Safari 16.4) is sufficient to suppress the rewrite on its own.
|
|
22
|
+
*
|
|
23
|
+
* The other three targets are pinned to ~2023 baselines instead of
|
|
24
|
+
* the absolute oldest supported version so the minifier does NOT
|
|
25
|
+
* collaterally downlevel unrelated modern CSS features. With
|
|
26
|
+
* chrome111/edge111/firefox114 we keep through:
|
|
27
|
+
* - `:is()` pseudo-class (Chrome 88, Firefox 78)
|
|
28
|
+
* - `hwb()` colors (Chrome 101, Firefox 96)
|
|
29
|
+
* - `lab()`, `oklch()`, `color()` (Chrome 111, Firefox 113)
|
|
30
|
+
* - gradient interpolation hints (Chrome 111)
|
|
31
|
+
* CSS Nesting (Chrome 120, Safari 17.2) and Firefox-137 gradient
|
|
32
|
+
* interpolation will still be lowered; that is an intentional
|
|
33
|
+
* trade-off — those features are newer than the baseline and
|
|
34
|
+
* lowering them is the correct behavior for our target audience.
|
|
35
|
+
*
|
|
36
|
+
* Mirrors the Next.js fixture
|
|
37
|
+
* test/e2e/app-dir/css-media-query/css-media-query.test.ts which
|
|
38
|
+
* asserts `cssText` preserves `max-width: 768px`.
|
|
39
|
+
*/
|
|
40
|
+
const DEFAULT_CSS_TARGET = [
|
|
41
|
+
"chrome111",
|
|
42
|
+
"edge111",
|
|
43
|
+
"firefox114",
|
|
44
|
+
"safari15"
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Applies {@link DEFAULT_CSS_TARGET} only where nobody chose a target (#4413).
|
|
48
|
+
*
|
|
49
|
+
* Vite merges config by concatenating arrays, and the CSS minifier keeps the
|
|
50
|
+
* oldest version of each browser, so a pin merged onto a chosen target would
|
|
51
|
+
* stop an app from ever raising it. Instead nothing is set while config hooks
|
|
52
|
+
* run, so the app and every plugin hook see and merge plain Vite values. The
|
|
53
|
+
* post-ordered `config` and `configEnvironment` hooks only note where a target
|
|
54
|
+
* was set, and the pin is applied once config is resolved.
|
|
55
|
+
*
|
|
56
|
+
* Both the top-level `build`, which Vite's CSS plugin minifies with (a copy of
|
|
57
|
+
* the environment's in per-environment builds), and every environment's `build`
|
|
58
|
+
* are checked.
|
|
59
|
+
*/
|
|
60
|
+
function createCssTargetPlugin() {
|
|
61
|
+
let topLevelConfigured = false;
|
|
62
|
+
const configuredEnvironments = /* @__PURE__ */ new Set();
|
|
63
|
+
return {
|
|
64
|
+
name: "vinext:css-target",
|
|
65
|
+
enforce: "post",
|
|
66
|
+
config: {
|
|
67
|
+
order: "post",
|
|
68
|
+
handler(config) {
|
|
69
|
+
topLevelConfigured = config.build?.cssTarget !== void 0;
|
|
70
|
+
configuredEnvironments.clear();
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
configEnvironment: {
|
|
74
|
+
order: "post",
|
|
75
|
+
handler(name, config) {
|
|
76
|
+
if (config.build?.cssTarget !== void 0) configuredEnvironments.add(name);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
configResolved: {
|
|
80
|
+
order: "pre",
|
|
81
|
+
handler(config) {
|
|
82
|
+
pinUnsetCssTarget(config.build, topLevelConfigured);
|
|
83
|
+
for (const [name, environment] of Object.entries(config.environments)) pinUnsetCssTarget(environment.build, configuredEnvironments.has(name));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function pinUnsetCssTarget(build, configured) {
|
|
89
|
+
if (configured || build.cssTarget !== build.target) return;
|
|
90
|
+
build.cssTarget = [...DEFAULT_CSS_TARGET];
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
export { createCssTargetPlugin };
|
|
@@ -109,6 +109,10 @@ type ParallelSlot = {
|
|
|
109
109
|
loadingTreePositions?: number[];
|
|
110
110
|
/** Absolute path to the slot's error component */
|
|
111
111
|
errorPath: string | null;
|
|
112
|
+
/** Every error convention from the slot root to its active page, outermost first. */
|
|
113
|
+
errorPaths?: string[];
|
|
114
|
+
/** Slot-root-relative tree positions aligned with errorPaths. */
|
|
115
|
+
errorTreePositions?: number[];
|
|
112
116
|
/** Nearest not-found convention for the slot's active branch. */
|
|
113
117
|
notFoundPath?: string | null;
|
|
114
118
|
/** Tree position of that convention relative to the slot root. */
|
|
@@ -167,6 +171,12 @@ export type AppRoute = {
|
|
|
167
171
|
id: string;
|
|
168
172
|
ownerTreePath: string;
|
|
169
173
|
state: "active" | "default" | "unmatched";
|
|
174
|
+
/**
|
|
175
|
+
* Set on a sub-route minted for a slot page with no children page of its
|
|
176
|
+
* own: its children render a default, a sibling catch-all, or nothing, so
|
|
177
|
+
* its route segments don't describe them.
|
|
178
|
+
*/
|
|
179
|
+
synthetic?: true;
|
|
170
180
|
};
|
|
171
181
|
/**
|
|
172
182
|
* Interception markers not wrapped in an `@slot` directory.
|
|
@@ -594,7 +594,8 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
594
594
|
childrenSlot: {
|
|
595
595
|
id: childrenSlotId,
|
|
596
596
|
ownerTreePath: childrenOwnerTreePath,
|
|
597
|
-
state: childrenDefault ? "default" : childrenCatchAll ? "active" : "unmatched"
|
|
597
|
+
state: childrenDefault ? "default" : childrenCatchAll ? "active" : "unmatched",
|
|
598
|
+
synthetic: true
|
|
598
599
|
},
|
|
599
600
|
loadingPath: null,
|
|
600
601
|
loadingPaths: parentRoute.loadingPaths,
|
|
@@ -742,10 +743,22 @@ function withSlotLoadingEntries(slot, pagePath, matcher) {
|
|
|
742
743
|
...slot,
|
|
743
744
|
loadingPaths: loadingEntries.map((entry) => entry.path),
|
|
744
745
|
loadingTreePositions: loadingEntries.map((entry) => entry.treePosition),
|
|
746
|
+
...findSlotErrorFields(slot.ownerDir, pagePath, matcher),
|
|
745
747
|
...findSlotNotFoundFields(slot.ownerDir, pagePath, matcher)
|
|
746
748
|
};
|
|
747
749
|
}
|
|
748
750
|
/**
|
|
751
|
+
* Every error convention on the slot's active branch. Each catches errors in
|
|
752
|
+
* its own segment, below that segment's layout.
|
|
753
|
+
*/
|
|
754
|
+
function findSlotErrorFields(slotDir, pagePath, matcher) {
|
|
755
|
+
const entries = findSlotSegmentFileEntries(slotDir, pagePath, "error", matcher);
|
|
756
|
+
return {
|
|
757
|
+
errorPaths: entries.map((entry) => entry.path),
|
|
758
|
+
errorTreePositions: entries.map((entry) => entry.treePosition)
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
749
762
|
* Every not-found convention on the slot's active branch, plus the nearest one,
|
|
750
763
|
* which supplies the slot's not-found metadata.
|
|
751
764
|
*/
|
|
@@ -1347,6 +1360,7 @@ function discoverParallelSlots(dir, appDir, matcher, includeNestedOnlySlots = fa
|
|
|
1347
1360
|
loadingPaths: loadingEntries.map((loading) => loading.path),
|
|
1348
1361
|
loadingTreePositions: loadingEntries.map((loading) => loading.treePosition),
|
|
1349
1362
|
errorPath: findFile(slotDir, "error", matcher),
|
|
1363
|
+
...findSlotErrorFields(slotDir, pagePath, matcher),
|
|
1350
1364
|
...findSlotNotFoundFields(slotDir, pagePath, matcher),
|
|
1351
1365
|
interceptingRoutes,
|
|
1352
1366
|
layoutIndex: -1,
|