cloudflare-next-intl 0.9.46 → 0.9.47
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 +3 -1
- package/dist/src/vite/vinext_route_wiring_fix.js +31 -7
- package/llms.txt +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -266,6 +266,7 @@ export default defineConfig({
|
|
|
266
266
|
4. **User-Agent Stub (`userAgentStub`)**: Prevents Next.js `user-agent` from importing `node:fs` during workerd runtime execution (which otherwise causes runtime 404 / 500 crashes in Workers proxy/middleware).
|
|
267
267
|
5. **Cloudflare Workers Client Stub (`cfWorkersClientStub`)**: Stubs `cloudflare:workers` in client builds so shared modules can be referenced without client bundling errors.
|
|
268
268
|
6. **Build ID Asset Emission (`buildIdAsset`)**: Emits `BUILD_ID` static asset in the client build directory from `process.env.__VINEXT_SHARED_BUILD_ID` or `process.env.__VINEXT_BUILD_ID`.
|
|
269
|
+
7. **Vinext Route Wiring & Optimistic Prefetch Fix (`vinextRouteWiringFix`)**: Patches Vinext runtime route wiring, route matching, optimistic route template resolution, and prefetch learning so pending prefetches with already cached templates don't block navigation, and leading `:locale` segments route correctly.
|
|
269
270
|
|
|
270
271
|
##### Plugin Options
|
|
271
272
|
All features are enabled by default, and can be individually configured or toggled off:
|
|
@@ -297,13 +298,14 @@ export default defineConfig({
|
|
|
297
298
|
localeFiles: true, // Enable @locale-file & glob bundling (default: true)
|
|
298
299
|
userAgentStub: true, // Enable regex-based user-agent stub (default: true)
|
|
299
300
|
cfWorkersClientStub: true, // Enable client cloudflare:workers stub (default: true)
|
|
301
|
+
vinextRouteWiringFix: true, // Enable vinext route wiring, matching, and prefetch fixes (default: true, or options object)
|
|
300
302
|
}),
|
|
301
303
|
],
|
|
302
304
|
});
|
|
303
305
|
```
|
|
304
306
|
|
|
305
307
|
Individual standalone plugins are also exported if you only need a specific feature:
|
|
306
|
-
`imageOptimizerPlugin` (or `imageOptimizer`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`.
|
|
308
|
+
`imageOptimizerPlugin` (or `imageOptimizer`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`, `vinextRouteWiringFixPlugin`.
|
|
307
309
|
|
|
308
310
|
##### Per-Image Optimizer Settings
|
|
309
311
|
|
|
@@ -163,13 +163,31 @@ export function isPrefetchLearningFile(id) {
|
|
|
163
163
|
return cleanId.endsWith("/app-browser-entry.js") || cleanId.endsWith("/app-browser-entry.ts");
|
|
164
164
|
}
|
|
165
165
|
export function isPrefetchLearningAlreadyFixed(code) {
|
|
166
|
-
const hasFixedFunction = code.includes("
|
|
167
|
-
const hasFixedCallSite = code.includes("targetRscUrl: rscUrl,");
|
|
166
|
+
const hasFixedFunction = code.includes("stripRsc(parsePrefetchCacheKey(cacheKey).rscUrl)") && code.includes("hasOptimisticTemplate");
|
|
167
|
+
const hasFixedCallSite = code.includes("targetHref: currentHref,") && code.includes("targetRscUrl: rscUrl,") && !LEARN_TEMPLATES_CALL_RE.test(code);
|
|
168
168
|
return hasFixedFunction && hasFixedCallSite;
|
|
169
169
|
}
|
|
170
170
|
const LEARN_TEMPLATES_FN_RE = /async\s+function\s+learnOptimisticRouteTemplatesFromPrefetchCache\s*\(\s*options\s*\)\s*\{[\s\S]*?await\s+Promise\.allSettled\(\s*learning\s*\);\s*\}/;
|
|
171
171
|
const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFromPrefetchCache(options) {
|
|
172
172
|
if (options.routeManifest === null) return;
|
|
173
|
+
const hasOptimisticTemplate = options.targetHref !== void 0 && resolveOptimisticNavigationPayload({
|
|
174
|
+
basePath: __basePath,
|
|
175
|
+
href: options.targetHref,
|
|
176
|
+
interceptionContext: options.interceptionContext,
|
|
177
|
+
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
178
|
+
routeManifest: options.routeManifest,
|
|
179
|
+
templates: optimisticRouteTemplates
|
|
180
|
+
}) !== null;
|
|
181
|
+
const stripRsc = (u) => {
|
|
182
|
+
if (!u) return "";
|
|
183
|
+
const q = u.indexOf("?");
|
|
184
|
+
if (q === -1) return u;
|
|
185
|
+
const sp = new URLSearchParams(u.slice(q + 1));
|
|
186
|
+
sp.delete("_rsc");
|
|
187
|
+
sp.delete("%5Frsc");
|
|
188
|
+
const s = sp.toString();
|
|
189
|
+
return s ? \`\${u.slice(0, q)}?\${s}\` : u.slice(0, q);
|
|
190
|
+
};
|
|
173
191
|
const learning = [...optimisticRouteTemplateLearning.values()];
|
|
174
192
|
for (const [cacheKey, entry] of getPrefetchCache()) {
|
|
175
193
|
const sourceKey = getOptimisticPrefetchSourceKey({
|
|
@@ -180,7 +198,7 @@ const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFr
|
|
|
180
198
|
if (optimisticRouteTemplateSources.has(sourceKey)) continue;
|
|
181
199
|
if (optimisticRouteTemplateLearning.has(sourceKey)) continue;
|
|
182
200
|
if (entry.prefetchKind === "route-tree") continue;
|
|
183
|
-
const isPendingNavigationTarget = !isSettledPrefetchCacheEntry(entry) && entry.pending !== void 0 && options.targetRscUrl !== void 0 && parsePrefetchCacheKey(cacheKey).rscUrl === options.targetRscUrl;
|
|
201
|
+
const isPendingNavigationTarget = !hasOptimisticTemplate && !isSettledPrefetchCacheEntry(entry) && entry.pending !== void 0 && options.targetRscUrl !== void 0 && stripRsc(parsePrefetchCacheKey(cacheKey).rscUrl) === stripRsc(options.targetRscUrl);
|
|
184
202
|
if (!isSettledPrefetchCacheEntry(entry) && !isPendingNavigationTarget) continue;
|
|
185
203
|
const promise = (async () => {
|
|
186
204
|
let settledEntry = entry;
|
|
@@ -210,17 +228,23 @@ const FIXED_LEARN_TEMPLATES_FN = `async function learnOptimisticRouteTemplatesFr
|
|
|
210
228
|
if (learning.length === 0) return;
|
|
211
229
|
await Promise.allSettled(learning);
|
|
212
230
|
}`;
|
|
213
|
-
const LEARN_TEMPLATES_CALL_RE = /
|
|
214
|
-
const FIXED_LEARN_TEMPLATES_CALL =
|
|
231
|
+
const LEARN_TEMPLATES_CALL_RE = /await\s+learnOptimisticRouteTemplatesFromPrefetchCache\(\s*\{\s*interceptionContext:\s*requestInterceptionContext,\s*(targetRscUrl:\s*rscUrl,\s*)?mountedSlotsHeader,[\s\S]*?routeManifest\s*\n\s*\}\);/;
|
|
232
|
+
const FIXED_LEARN_TEMPLATES_CALL = `await learnOptimisticRouteTemplatesFromPrefetchCache({
|
|
233
|
+
interceptionContext: requestInterceptionContext,
|
|
234
|
+
targetHref: currentHref,
|
|
235
|
+
targetRscUrl: rscUrl,
|
|
236
|
+
mountedSlotsHeader,
|
|
237
|
+
routeManifest
|
|
238
|
+
});`;
|
|
215
239
|
export function patchPrefetchLearning(code) {
|
|
216
240
|
if (isPrefetchLearningAlreadyFixed(code)) {
|
|
217
241
|
return code;
|
|
218
242
|
}
|
|
219
243
|
let result = code;
|
|
220
|
-
if (!result.includes("
|
|
244
|
+
if (!result.includes("hasOptimisticTemplate") && LEARN_TEMPLATES_FN_RE.test(result)) {
|
|
221
245
|
result = result.replace(LEARN_TEMPLATES_FN_RE, FIXED_LEARN_TEMPLATES_FN);
|
|
222
246
|
}
|
|
223
|
-
if (
|
|
247
|
+
if (LEARN_TEMPLATES_CALL_RE.test(result)) {
|
|
224
248
|
result = result.replace(LEARN_TEMPLATES_CALL_RE, FIXED_LEARN_TEMPLATES_CALL);
|
|
225
249
|
}
|
|
226
250
|
return result;
|
package/llms.txt
CHANGED
|
@@ -27,7 +27,7 @@ other subpath can be used.
|
|
|
27
27
|
- `./db` — `withPublicDb(fn)` / `withUserDb(fn, uid?)` server-side Postgres/Drizzle context helpers (require `db` set on your `RoutingConfig`; direct Postgres or Supabase Data API with automatic PostgREST REST translation and `cfni_exec` fallback, see below).
|
|
28
28
|
- `./dbEslint` — flat-config ESLint fragment banning direct `@supabase/supabase-js`, `pg`, `postgres`, and deep `dist/` imports in application code.
|
|
29
29
|
- `./dbHelpers` — generic Drizzle SQL helper functions (`excluded`, `onConflictSet`, `ago`, `currentDate`, `windowCount`, `unnestLateral`, `ascNullsLast`, `alwaysTrue`, `lateral`, `aliasColumn`, `minOf`, `maxOf`, `roundReal`, `multiply`, `scalarFromCte`) for use with `./db`.
|
|
30
|
-
- `./vite` — `cloudflareNextIntl(options?)` / `cloudflareNextIntlPlugin`, `imageOptimizerPlugin(options?)` / `imageOptimizer`, `buildIdAsset(fileName?)`, `localeFilePlugin(options?)`, `userAgentStubPlugin()`, `cfWorkersClientStubPlugin()`: All-in-one Vite plugin required for Vinext/Cloudflare Workers environments (bundles `@locale-file/*` via eager glob, resolves `@intl-config`, stubs Node.js `user-agent` to prevent runtime `node:fs` errors, stubs `cloudflare:workers` for client builds, emits client `BUILD_ID`,
|
|
30
|
+
- `./vite` — `cloudflareNextIntl(options?)` / `cloudflareNextIntlPlugin`, `imageOptimizerPlugin(options?)` / `imageOptimizer`, `buildIdAsset(fileName?)`, `localeFilePlugin(options?)`, `userAgentStubPlugin()`, `cfWorkersClientStubPlugin()`, `vinextRouteWiringFixPlugin(options?)`: All-in-one Vite plugin required for Vinext/Cloudflare Workers environments (bundles `@locale-file/*` via eager glob, resolves `@intl-config`, stubs Node.js `user-agent` to prevent runtime `node:fs` errors, stubs `cloudflare:workers` for client builds, emits client `BUILD_ID`, runs build-time/dev Image Optimizer with Next.js blur placeholder shimming, and fixes vinext route wiring, matching, and non-blocking optimistic prefetch learning).
|
|
31
31
|
- `./image-optimizer` / `./imageOptimizer` — image optimization suite: `imageOptimizerPlugin`, `imageOptimizer`, `resolveOptions`, `resolveImageConfig`, `resolveBlurOptions`, `processImage`, `makeBlurDataURL`, `getImageBlurSvg`, `renderManifest`, `writeManifest`, `isFresh`, `loadCache`, `saveCache`, `collectImages`, `run`.
|
|
32
32
|
- `./errorHandling` — error reporting & stale deploy recovery barrel: `reportError`, `withErrorHandling`, `installConsoleErrorOverride`, `installGlobalErrorOverride`, `stringifyUnknown`, `formatErrorMessage`, `defaultIgnoredConsoleErrors`, `createServerErrorAction`, `isStaleDeployError`, `defaultStaleDeployPatterns`, `setStaleDeployPatterns`, `getStaleDeployPatterns`, `clearClientCache`, `useStaleDeployRecovery`, `shouldRecoverFromStaleDeploy`, `isRecentBuild`.
|
|
33
33
|
- `./isStaleDeployError` — `isStaleDeployError(error, patterns?)`, `setStaleDeployPatterns(patterns)`, `getStaleDeployPatterns()`: detector returning `true` for version skew / chunk load / dynamic import / server action 404 / hydration errors (ChunkLoadError, UnrecognizedActionError, server action not found, failed to fetch, dynamically imported module failure, loading CSS chunk, connection closed, RSC payload failure, minified error #412, or missing stream error `undefined`) with fast pre-lowercased pattern cache and intl-config integration (`errorHandling.staleDeployPatterns`).
|