cloudflare-next-intl 0.10.28 → 0.10.30
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 +12 -9
- package/dist/src/client_messages_scan/scan_project.js +1 -1
- package/dist/src/general/pick_client_messages.d.ts +1 -1
- package/dist/src/general/pick_client_messages.js +2 -2
- package/dist/src/vite/auto_client_messages_plugin.js +7 -2
- package/dist/src/vite/auto_image_loader_plugin.d.ts +2 -0
- package/dist/src/vite/auto_image_loader_plugin.js +44 -5
- package/dist/src/vite/index.d.ts +1 -1
- package/dist/src/vite/index.js +1 -1
- package/dist/src/vite/plugin.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -167,17 +167,19 @@ export function Navigation() {
|
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
`IntlProvider` sends the locale's messages to the client for `useTranslations`
|
|
170
|
-
in client components.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
in client components. By default, `clientMessages: "auto"` and `autoClientMessages`
|
|
171
|
+
Vite plugin are **enabled by default** with `{ onDynamic: "fallback", fallbackNamespaces: [] }`
|
|
172
|
+
to automatically scan and ship only the namespaces your client components use.
|
|
173
|
+
|
|
174
|
+
You can customize or disable either side:
|
|
175
|
+
- Set `clientMessages: false` (server-only messages), `true` (all messages), or `["Auth", "Common", "Categories*"]` in intl config.
|
|
176
|
+
- In `vite.config.ts`, pass `autoClientMessages: false` to disable scanning, or customize options:
|
|
174
177
|
|
|
175
178
|
```ts
|
|
176
|
-
// vite.config.ts
|
|
179
|
+
// vite.config.ts (optional customization — enabled by default)
|
|
177
180
|
cloudflareNextIntl({
|
|
178
|
-
autoClientMessages: { fallbackNamespaces: ["Common"],
|
|
181
|
+
autoClientMessages: { fallbackNamespaces: ["Common"], packages: ["@my/ui"] }
|
|
179
182
|
})
|
|
180
|
-
// intl.config.ts -> setIntlConfig({ clientMessages: "auto", ... })
|
|
181
183
|
```
|
|
182
184
|
|
|
183
185
|
> UI library packages can declare `"i18n": { "namespaces": ["Buttons"] }` in `package.json` for automatic inclusion.
|
|
@@ -309,9 +311,10 @@ export default defineConfig({
|
|
|
309
311
|
blur: { quality: 70, stdDeviation: 20 }, // Next.js blur placeholder options (or `false`)
|
|
310
312
|
overrides: { // Per-image overrides keyed by public src path (wins over scanned <Image> props)
|
|
311
313
|
"/images/hero.png": { maxWidth: false, formats: ["webp"], blur: { quality: 80 } },
|
|
312
|
-
"/images/logo.png": { formats: false, blur: false },
|
|
313
314
|
},
|
|
314
315
|
},
|
|
316
|
+
autoImageLoader: true, // Auto-detect custom image loader (from next.config.* loaderFile or image-loader.ts; default: true, or options object)
|
|
317
|
+
autoClientMessages: true, // Auto-scan client useTranslations calls to trim client payload (default: true, or options object)
|
|
315
318
|
autoLocaleParams: { // Auto-insert locale params/setLocale (or `false` to disable)
|
|
316
319
|
mode: "fix", // "fix" | "report" | "off" (default: "fix")
|
|
317
320
|
localeParam: "locale", // Route param name to read (default: "locale")
|
|
@@ -354,7 +357,7 @@ export default defineConfig({
|
|
|
354
357
|
> **Note:** `unblockPageElementDependencies: true` was measured, in a real app, to make page-to-page navigation noticeably slower rather than faster — it strips ordering vinext's own page-element wiring relies on. Leave it off unless you've verified otherwise for your app.
|
|
355
358
|
|
|
356
359
|
Individual standalone plugins are also exported if you only need a specific feature:
|
|
357
|
-
`imageOptimizerPlugin` (or `imageOptimizer`), `autoLocaleParamsPlugin`, `layoutQueriesPlugin` (or `layoutQueriesCheck`), `firebaseAuthCheckPlugin` (or `firebaseAuthCheck`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`, `vinextRouteWiringFixPlugin`, `lucideOptimizerPlugin`.
|
|
360
|
+
`imageOptimizerPlugin` (or `imageOptimizer`), `autoImageLoaderPlugin`, `autoClientMessagesPlugin`, `autoLocaleParamsPlugin`, `layoutQueriesPlugin` (or `layoutQueriesCheck`), `firebaseAuthCheckPlugin` (or `firebaseAuthCheck`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`, `vinextRouteWiringFixPlugin`, `lucideOptimizerPlugin`.
|
|
358
361
|
|
|
359
362
|
##### Per-Image Optimizer Settings
|
|
360
363
|
|
|
@@ -19,7 +19,7 @@ function walk(dir, out, skipNodeModules) {
|
|
|
19
19
|
}
|
|
20
20
|
export function scanProject(opts) {
|
|
21
21
|
const files = [];
|
|
22
|
-
for (const d of opts.dirs ?? ["src", "app", "components"]) {
|
|
22
|
+
for (const d of opts.dirs ?? ["src", "app", "components", "pages", "shared", "modules", "lib"]) {
|
|
23
23
|
const full = join(opts.root, d);
|
|
24
24
|
if (existsSync(full))
|
|
25
25
|
walk(full, files, true);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { TranslationObject } from "../types/types.js";
|
|
2
|
-
export default function pickClientMessages(messages: TranslationObject, clientMessages
|
|
2
|
+
export default function pickClientMessages(messages: TranslationObject, clientMessages?: boolean | "auto" | readonly string[] | undefined, autoManifest?: string[] | true | undefined): TranslationObject;
|
|
@@ -2,9 +2,9 @@ import { matchesNamespacePattern } from "../client_messages_scan/match_namespace
|
|
|
2
2
|
function readAutoManifest() {
|
|
3
3
|
return typeof __CFNI_CLIENT_MESSAGES__ === "undefined" ? undefined : __CFNI_CLIENT_MESSAGES__;
|
|
4
4
|
}
|
|
5
|
-
export default function pickClientMessages(messages, clientMessages, autoManifest = readAutoManifest()) {
|
|
5
|
+
export default function pickClientMessages(messages, clientMessages = "auto", autoManifest = readAutoManifest()) {
|
|
6
6
|
const list = clientMessages === "auto" ? autoManifest ?? true : clientMessages;
|
|
7
|
-
if (list ===
|
|
7
|
+
if (list === true)
|
|
8
8
|
return messages;
|
|
9
9
|
const picked = {};
|
|
10
10
|
if (list === false)
|
|
@@ -2,12 +2,17 @@ import { scanProject } from "../client_messages_scan/scan_project.js";
|
|
|
2
2
|
const KEY = "__CFNI_CLIENT_MESSAGES__";
|
|
3
3
|
const SOURCE = /\.(tsx?|jsx?|mjs)$/;
|
|
4
4
|
export function autoClientMessagesPlugin(options = {}) {
|
|
5
|
+
const opts = {
|
|
6
|
+
onDynamic: "fallback",
|
|
7
|
+
fallbackNamespaces: [],
|
|
8
|
+
...options,
|
|
9
|
+
};
|
|
5
10
|
let last = "";
|
|
6
11
|
const run = () => {
|
|
7
|
-
const manifest = scanProject({ ...
|
|
12
|
+
const manifest = scanProject({ ...opts, root: opts.root ?? process.cwd() });
|
|
8
13
|
for (const d of manifest.dynamicCalls)
|
|
9
14
|
console.warn(`[cloudflare-next-intl] dynamic useTranslations: ${d.file}:${d.line} ${d.text}`);
|
|
10
|
-
if (
|
|
15
|
+
if (opts.strict && manifest.dynamicCalls.length > 0)
|
|
11
16
|
throw new Error("[cloudflare-next-intl] Dynamic useTranslations namespaces found. Use literals, union types, or fallbackNamespaces with onDynamic: \"fallback\".");
|
|
12
17
|
console.log(manifest.namespaces === true
|
|
13
18
|
? `[cloudflare-next-intl] client messages: sending all (root or dynamic access) from ${manifest.scannedFiles} files`
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
export declare const VIRTUAL_IMAGE_LOADER_ID = "virtual:cloudflare-next-intl-image-loader";
|
|
3
3
|
export declare const RESOLVED_IMAGE_LOADER_ID: string;
|
|
4
|
+
export declare const NEXT_CONFIG_CANDIDATES: readonly ["next.config.ts", "next.config.mts", "next.config.mjs", "next.config.js", "next.config.cjs"];
|
|
4
5
|
export declare const DEFAULT_LOADER_CANDIDATES: readonly ["image-loader.ts", "image-loader.js", "image-loader.mjs", "image-loader.cjs", "image-loader.tsx", "image-loader.jsx", "src/image-loader.ts", "src/image-loader.js", "src/image-loader.mjs", "src/image-loader.cjs", "src/image-loader.tsx", "src/image-loader.jsx"];
|
|
5
6
|
export interface AutoImageLoaderOptions {
|
|
6
7
|
enabled?: boolean;
|
|
@@ -8,6 +9,7 @@ export interface AutoImageLoaderOptions {
|
|
|
8
9
|
exportName?: string;
|
|
9
10
|
root?: string;
|
|
10
11
|
}
|
|
12
|
+
export declare function findLoaderFileFromNextConfig(root: string): string | null;
|
|
11
13
|
export interface DetectedImageLoader {
|
|
12
14
|
exists: boolean;
|
|
13
15
|
isEmpty: boolean;
|
|
@@ -3,6 +3,13 @@ import path from "node:path";
|
|
|
3
3
|
import { getShimPath, VIRTUAL_IMAGE_SHIM_ID } from "../image_optimizer/plugin.js";
|
|
4
4
|
export const VIRTUAL_IMAGE_LOADER_ID = "virtual:cloudflare-next-intl-image-loader";
|
|
5
5
|
export const RESOLVED_IMAGE_LOADER_ID = "\0" + VIRTUAL_IMAGE_LOADER_ID;
|
|
6
|
+
export const NEXT_CONFIG_CANDIDATES = [
|
|
7
|
+
"next.config.ts",
|
|
8
|
+
"next.config.mts",
|
|
9
|
+
"next.config.mjs",
|
|
10
|
+
"next.config.js",
|
|
11
|
+
"next.config.cjs",
|
|
12
|
+
];
|
|
6
13
|
export const DEFAULT_LOADER_CANDIDATES = [
|
|
7
14
|
"image-loader.ts",
|
|
8
15
|
"image-loader.js",
|
|
@@ -17,6 +24,32 @@ export const DEFAULT_LOADER_CANDIDATES = [
|
|
|
17
24
|
"src/image-loader.tsx",
|
|
18
25
|
"src/image-loader.jsx",
|
|
19
26
|
];
|
|
27
|
+
export function findLoaderFileFromNextConfig(root) {
|
|
28
|
+
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
29
|
+
const configPath = path.resolve(root, name);
|
|
30
|
+
if (!existsSync(configPath))
|
|
31
|
+
continue;
|
|
32
|
+
const raw = readFileSync(configPath, "utf8");
|
|
33
|
+
const stripped = raw
|
|
34
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
35
|
+
.replace(/\/\/.*/g, "");
|
|
36
|
+
const match = stripped.match(/loaderFile\s*:\s*["'`]([^"'`]+)["'`]/);
|
|
37
|
+
if (match?.[1]) {
|
|
38
|
+
const candidate = match[1].trim();
|
|
39
|
+
const resolved = path.isAbsolute(candidate) ? candidate : path.resolve(root, candidate);
|
|
40
|
+
if (existsSync(resolved)) {
|
|
41
|
+
return resolved;
|
|
42
|
+
}
|
|
43
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
44
|
+
for (const ext of extensions) {
|
|
45
|
+
if (existsSync(resolved + ext)) {
|
|
46
|
+
return resolved + ext;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
20
53
|
export function findExportedLoaderName(code, preferredExportName) {
|
|
21
54
|
const stripped = code
|
|
22
55
|
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
@@ -76,11 +109,17 @@ export function detectImageLoader(options) {
|
|
|
76
109
|
}
|
|
77
110
|
}
|
|
78
111
|
else {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
112
|
+
const configLoader = findLoaderFileFromNextConfig(root);
|
|
113
|
+
if (configLoader) {
|
|
114
|
+
targetPath = configLoader;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
for (const candidate of DEFAULT_LOADER_CANDIDATES) {
|
|
118
|
+
const candidatePath = path.resolve(root, candidate);
|
|
119
|
+
if (existsSync(candidatePath)) {
|
|
120
|
+
targetPath = candidatePath;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
84
123
|
}
|
|
85
124
|
}
|
|
86
125
|
}
|
package/dist/src/vite/index.d.ts
CHANGED
|
@@ -12,6 +12,6 @@ export { reactEvalStubPlugin, reactEvalEsbuildPlugin, transformReactEval, EVAL_W
|
|
|
12
12
|
export { vinextRouteWiringFixPlugin, patchAppPageRouteWiring, isAppPageRouteWiringFile, isAppPageRouteWiringAlreadyFixed, isVinextAppPageRouteWiringSafeOnDisk, patchAppPageProbe, isAppPageProbeFile, isAppPageProbeAlreadyFixed, isVinextAppPageProbeSafeOnDisk, type VinextRouteWiringFixPluginOptions, } from "./vinext_route_wiring_fix.js";
|
|
13
13
|
export { localeFilePlugin, resolveDefaultIntlConfigPath, type LocaleFilePluginOptions } from "./locale_file_plugin.js";
|
|
14
14
|
export { lucideOptimizerPlugin, detectLucideReact, resolveLucideEsmEntry, parseLucideIconMap, transformLucideImports, transformNextJsImports, type LucideOptimizerPluginOptions, } from "./lucide_optimizer_plugin.js";
|
|
15
|
-
export { autoImageLoaderPlugin, detectImageLoader, findExportedLoaderName, generateLoaderVirtualModule, DEFAULT_LOADER_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, type AutoImageLoaderOptions, type DetectedImageLoader, } from "./auto_image_loader_plugin.js";
|
|
15
|
+
export { autoImageLoaderPlugin, detectImageLoader, findExportedLoaderName, findLoaderFileFromNextConfig, generateLoaderVirtualModule, DEFAULT_LOADER_CANDIDATES, NEXT_CONFIG_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, type AutoImageLoaderOptions, type DetectedImageLoader, } from "./auto_image_loader_plugin.js";
|
|
16
16
|
export { cloudflareNextIntl, cloudflareNextIntlPlugin, type CloudflareNextIntlOptions, default } from "./plugin.js";
|
|
17
17
|
export { imageOptimizer, imageOptimizerPlugin, VIRTUAL_IMAGE_SHIM_ID, type ImageFormat, type ImageBlurOptions, type ImageOverrideOptions, type ImageOptimizerPluginOptions, type ResolvedBlurOptions, type ResolvedOptions, type ResolvedImageConfig, type OptimizedImage, type ManifestData, type ManifestEntry, } from "../image_optimizer/index.js";
|
package/dist/src/vite/index.js
CHANGED
|
@@ -12,6 +12,6 @@ export { reactEvalStubPlugin, reactEvalEsbuildPlugin, transformReactEval, EVAL_W
|
|
|
12
12
|
export { vinextRouteWiringFixPlugin, patchAppPageRouteWiring, isAppPageRouteWiringFile, isAppPageRouteWiringAlreadyFixed, isVinextAppPageRouteWiringSafeOnDisk, patchAppPageProbe, isAppPageProbeFile, isAppPageProbeAlreadyFixed, isVinextAppPageProbeSafeOnDisk, } from "./vinext_route_wiring_fix.js";
|
|
13
13
|
export { localeFilePlugin, resolveDefaultIntlConfigPath } from "./locale_file_plugin.js";
|
|
14
14
|
export { lucideOptimizerPlugin, detectLucideReact, resolveLucideEsmEntry, parseLucideIconMap, transformLucideImports, transformNextJsImports, } from "./lucide_optimizer_plugin.js";
|
|
15
|
-
export { autoImageLoaderPlugin, detectImageLoader, findExportedLoaderName, generateLoaderVirtualModule, DEFAULT_LOADER_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, } from "./auto_image_loader_plugin.js";
|
|
15
|
+
export { autoImageLoaderPlugin, detectImageLoader, findExportedLoaderName, findLoaderFileFromNextConfig, generateLoaderVirtualModule, DEFAULT_LOADER_CANDIDATES, NEXT_CONFIG_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, } from "./auto_image_loader_plugin.js";
|
|
16
16
|
export { cloudflareNextIntl, cloudflareNextIntlPlugin, default } from "./plugin.js";
|
|
17
17
|
export { imageOptimizer, imageOptimizerPlugin, VIRTUAL_IMAGE_SHIM_ID, } from "../image_optimizer/index.js";
|
package/dist/src/vite/plugin.js
CHANGED
|
@@ -55,7 +55,7 @@ export function cloudflareNextIntl(options = {}) {
|
|
|
55
55
|
? { root: options.root, ...options.autoImageLoader }
|
|
56
56
|
: { root: options.root }));
|
|
57
57
|
}
|
|
58
|
-
if (options.autoClientMessages) {
|
|
58
|
+
if (options.autoClientMessages !== false) {
|
|
59
59
|
plugins.push(autoClientMessagesPlugin(typeof options.autoClientMessages === "object"
|
|
60
60
|
? { root: options.root, ...options.autoClientMessages }
|
|
61
61
|
: { root: options.root }));
|