cloudflare-next-intl 0.10.29 → 0.10.31

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 CHANGED
@@ -311,9 +311,11 @@ export default defineConfig({
311
311
  blur: { quality: 70, stdDeviation: 20 }, // Next.js blur placeholder options (or `false`)
312
312
  overrides: { // Per-image overrides keyed by public src path (wins over scanned <Image> props)
313
313
  "/images/hero.png": { maxWidth: false, formats: ["webp"], blur: { quality: 80 } },
314
- "/images/logo.png": { formats: false, blur: false },
315
314
  },
315
+ autoImageLoader: true, // Auto-detect custom image loader for standalone imageOptimizer usages (default: true, or false/options)
316
316
  },
317
+ autoImageLoader: true, // Auto-detect custom image loader (from next.config.* loaderFile or image-loader.ts; default: true, or options object)
318
+ autoClientMessages: true, // Auto-scan client useTranslations calls to trim client payload (default: true, or options object)
317
319
  autoLocaleParams: { // Auto-insert locale params/setLocale (or `false` to disable)
318
320
  mode: "fix", // "fix" | "report" | "off" (default: "fix")
319
321
  localeParam: "locale", // Route param name to read (default: "locale")
@@ -356,7 +358,7 @@ export default defineConfig({
356
358
  > **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.
357
359
 
358
360
  Individual standalone plugins are also exported if you only need a specific feature:
359
- `imageOptimizerPlugin` (or `imageOptimizer`), `autoLocaleParamsPlugin`, `layoutQueriesPlugin` (or `layoutQueriesCheck`), `firebaseAuthCheckPlugin` (or `firebaseAuthCheck`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`, `vinextRouteWiringFixPlugin`, `lucideOptimizerPlugin`.
361
+ `imageOptimizerPlugin` (or `imageOptimizer`), `autoImageLoaderPlugin`, `autoClientMessagesPlugin`, `autoLocaleParamsPlugin`, `layoutQueriesPlugin` (or `layoutQueriesCheck`), `firebaseAuthCheckPlugin` (or `firebaseAuthCheck`), `buildIdAsset`, `localeFilePlugin`, `userAgentStubPlugin`, `cfWorkersClientStubPlugin`, `vinextRouteWiringFixPlugin`, `lucideOptimizerPlugin`.
360
362
 
361
363
  ##### Per-Image Optimizer Settings
362
364
 
@@ -0,0 +1,20 @@
1
+ export declare const VIRTUAL_IMAGE_LOADER_ID = "virtual:cloudflare-next-intl-image-loader";
2
+ export declare const RESOLVED_IMAGE_LOADER_ID: string;
3
+ export declare const NEXT_CONFIG_CANDIDATES: readonly ["next.config.ts", "next.config.mts", "next.config.mjs", "next.config.js", "next.config.cjs"];
4
+ 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
+ export interface AutoImageLoaderOptions {
6
+ enabled?: boolean;
7
+ file?: string;
8
+ exportName?: string;
9
+ root?: string;
10
+ }
11
+ export declare function findLoaderFileFromNextConfig(root: string): string | null;
12
+ export interface DetectedImageLoader {
13
+ exists: boolean;
14
+ isEmpty: boolean;
15
+ loaderPath: string | null;
16
+ exportName: string | null;
17
+ }
18
+ export declare function findExportedLoaderName(code: string, preferredExportName?: string): string | null;
19
+ export declare function detectImageLoader(options?: AutoImageLoaderOptions): DetectedImageLoader;
20
+ export declare function generateLoaderVirtualModule(detected: DetectedImageLoader): string;
@@ -0,0 +1,150 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ export const VIRTUAL_IMAGE_LOADER_ID = "virtual:cloudflare-next-intl-image-loader";
4
+ export const RESOLVED_IMAGE_LOADER_ID = "\0" + VIRTUAL_IMAGE_LOADER_ID;
5
+ export const NEXT_CONFIG_CANDIDATES = [
6
+ "next.config.ts",
7
+ "next.config.mts",
8
+ "next.config.mjs",
9
+ "next.config.js",
10
+ "next.config.cjs",
11
+ ];
12
+ export const DEFAULT_LOADER_CANDIDATES = [
13
+ "image-loader.ts",
14
+ "image-loader.js",
15
+ "image-loader.mjs",
16
+ "image-loader.cjs",
17
+ "image-loader.tsx",
18
+ "image-loader.jsx",
19
+ "src/image-loader.ts",
20
+ "src/image-loader.js",
21
+ "src/image-loader.mjs",
22
+ "src/image-loader.cjs",
23
+ "src/image-loader.tsx",
24
+ "src/image-loader.jsx",
25
+ ];
26
+ export function findLoaderFileFromNextConfig(root) {
27
+ for (const name of NEXT_CONFIG_CANDIDATES) {
28
+ const configPath = path.resolve(root, name);
29
+ if (!existsSync(configPath))
30
+ continue;
31
+ const raw = readFileSync(configPath, "utf8");
32
+ const stripped = raw
33
+ .replace(/\/\*[\s\S]*?\*\//g, "")
34
+ .replace(/\/\/.*/g, "");
35
+ const match = stripped.match(/loaderFile\s*:\s*["'`]([^"'`]+)["'`]/);
36
+ if (match?.[1]) {
37
+ const candidate = match[1].trim();
38
+ const resolved = path.isAbsolute(candidate) ? candidate : path.resolve(root, candidate);
39
+ if (existsSync(resolved)) {
40
+ return resolved;
41
+ }
42
+ const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
43
+ for (const ext of extensions) {
44
+ if (existsSync(resolved + ext)) {
45
+ return resolved + ext;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return null;
51
+ }
52
+ export function findExportedLoaderName(code, preferredExportName) {
53
+ const stripped = code
54
+ .replace(/\/\*[\s\S]*?\*\//g, "")
55
+ .replace(/\/\/.*/g, "");
56
+ if (preferredExportName) {
57
+ if (preferredExportName === "default") {
58
+ if (/export\s+default\b/.test(stripped) || /export\s*\{[^}]*\bas\s+default\b[^}]*\}/.test(stripped)) {
59
+ return "default";
60
+ }
61
+ return null;
62
+ }
63
+ const fnRegex = new RegExp(`export\\s+(?:async\\s+)?function\\s+${preferredExportName}\\b`);
64
+ if (fnRegex.test(stripped))
65
+ return preferredExportName;
66
+ const constRegex = new RegExp(`export\\s+(?:const|let|var)\\s+${preferredExportName}\\b`);
67
+ if (constRegex.test(stripped))
68
+ return preferredExportName;
69
+ const reExportRegex = new RegExp(`export\\s*\\{[^}]*\\b(?:as\\s+)?${preferredExportName}\\b[^}]*\\}`);
70
+ if (reExportRegex.test(stripped))
71
+ return preferredExportName;
72
+ return null;
73
+ }
74
+ if (/export\s+default\b/.test(stripped) || /export\s*\{[^}]*\bas\s+default\b[^}]*\}/.test(stripped)) {
75
+ return "default";
76
+ }
77
+ const fnMatch = stripped.match(/export\s+(?:async\s+)?function\s+([a-zA-Z0-9_$]+)/);
78
+ if (fnMatch?.[1]) {
79
+ return fnMatch[1];
80
+ }
81
+ const varMatch = stripped.match(/export\s+(?:const|let|var)\s+([a-zA-Z0-9_$]+)/);
82
+ if (varMatch?.[1]) {
83
+ return varMatch[1];
84
+ }
85
+ const exportBlockMatch = stripped.match(/export\s*\{([^}]+)\}/);
86
+ if (exportBlockMatch?.[1]) {
87
+ const entries = exportBlockMatch[1].split(",");
88
+ for (const entry of entries) {
89
+ const parts = entry.trim().split(/\s+as\s+/);
90
+ const exportedName = parts[parts.length - 1]?.trim();
91
+ if (exportedName) {
92
+ return exportedName;
93
+ }
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+ export function detectImageLoader(options) {
99
+ const root = options?.root ? path.resolve(options.root) : process.cwd();
100
+ let targetPath = null;
101
+ if (options?.file) {
102
+ const customPath = path.isAbsolute(options.file) ? options.file : path.resolve(root, options.file);
103
+ if (existsSync(customPath)) {
104
+ targetPath = customPath;
105
+ }
106
+ else {
107
+ return { exists: false, isEmpty: false, loaderPath: null, exportName: null };
108
+ }
109
+ }
110
+ else {
111
+ const configLoader = findLoaderFileFromNextConfig(root);
112
+ if (configLoader) {
113
+ targetPath = configLoader;
114
+ }
115
+ else {
116
+ for (const candidate of DEFAULT_LOADER_CANDIDATES) {
117
+ const candidatePath = path.resolve(root, candidate);
118
+ if (existsSync(candidatePath)) {
119
+ targetPath = candidatePath;
120
+ break;
121
+ }
122
+ }
123
+ }
124
+ }
125
+ if (!targetPath) {
126
+ return { exists: false, isEmpty: false, loaderPath: null, exportName: null };
127
+ }
128
+ const content = readFileSync(targetPath, "utf8");
129
+ const stripped = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*/g, "").trim();
130
+ if (!stripped) {
131
+ return { exists: true, isEmpty: true, loaderPath: targetPath, exportName: null };
132
+ }
133
+ const exportName = findExportedLoaderName(content, options?.exportName);
134
+ return {
135
+ exists: true,
136
+ isEmpty: false,
137
+ loaderPath: targetPath,
138
+ exportName,
139
+ };
140
+ }
141
+ export function generateLoaderVirtualModule(detected) {
142
+ if (!detected.exists || detected.isEmpty || !detected.loaderPath || !detected.exportName) {
143
+ return `export const defaultLoader = undefined;\nexport const hasCustomLoader = false;\nexport default undefined;\n`;
144
+ }
145
+ const normalizedPath = detected.loaderPath.replace(/\\/g, "/");
146
+ if (detected.exportName === "default") {
147
+ return `import loader from ${JSON.stringify(normalizedPath)};\nexport const defaultLoader = loader;\nexport const hasCustomLoader = true;\nexport default loader;\n`;
148
+ }
149
+ return `import { ${detected.exportName} as loader } from ${JSON.stringify(normalizedPath)};\nexport const defaultLoader = loader;\nexport const hasCustomLoader = true;\nexport default loader;\n`;
150
+ }
@@ -1,4 +1,4 @@
1
- export { imageOptimizerPlugin, imageOptimizer, VIRTUAL_IMAGE_SHIM_ID, default, } from "./plugin.js";
1
+ export { imageOptimizerPlugin, imageOptimizer, VIRTUAL_IMAGE_SHIM_ID, VIRTUAL_MANIFEST_ID, getShimPath, default, } from "./plugin.js";
2
2
  export { resolveOptions, resolveImageConfig, resolveBlurOptions, DEFAULT_OPTIONS, DEFAULT_BLUR_OPTIONS, SUPPORTED_EXTENSIONS, type ImageFormat, type ImageBlurOptions, type ImageOverrideOptions, type ImageOptimizerPluginOptions, type ResolvedBlurOptions, type ResolvedOptions, type ResolvedImageConfig, type OptimizedImage, type ManifestData, } from "./types.js";
3
3
  export { processImage, makeBlurDataURL, toGeneratedPath, toPublicSrc, } from "./process_image.js";
4
4
  export { renderManifest, writeManifest, } from "./manifest.js";
@@ -7,3 +7,4 @@ export { collectImages, run, } from "./run.js";
7
7
  export { collectUsedImages, findCodeFiles, extractImageReferences, CODE_EXTENSIONS, IGNORED_DIRS, } from "./scan_used.js";
8
8
  export { getImageBlurSvg, } from "./blur_svg.js";
9
9
  export { type ManifestEntry, } from "./next_image_shim.js";
10
+ export { VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, type AutoImageLoaderOptions, type DetectedImageLoader, findLoaderFileFromNextConfig, findExportedLoaderName, detectImageLoader, generateLoaderVirtualModule, } from "./detect_loader.js";
@@ -1,4 +1,4 @@
1
- export { imageOptimizerPlugin, imageOptimizer, VIRTUAL_IMAGE_SHIM_ID, default, } from "./plugin.js";
1
+ export { imageOptimizerPlugin, imageOptimizer, VIRTUAL_IMAGE_SHIM_ID, VIRTUAL_MANIFEST_ID, getShimPath, default, } from "./plugin.js";
2
2
  export { resolveOptions, resolveImageConfig, resolveBlurOptions, DEFAULT_OPTIONS, DEFAULT_BLUR_OPTIONS, SUPPORTED_EXTENSIONS, } from "./types.js";
3
3
  export { processImage, makeBlurDataURL, toGeneratedPath, toPublicSrc, } from "./process_image.js";
4
4
  export { renderManifest, writeManifest, } from "./manifest.js";
@@ -6,3 +6,4 @@ export { isFresh, loadCache, saveCache, } from "./cache.js";
6
6
  export { collectImages, run, } from "./run.js";
7
7
  export { collectUsedImages, findCodeFiles, extractImageReferences, CODE_EXTENSIONS, IGNORED_DIRS, } from "./scan_used.js";
8
8
  export { getImageBlurSvg, } from "./blur_svg.js";
9
+ export { VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, findLoaderFileFromNextConfig, findExportedLoaderName, detectImageLoader, generateLoaderVirtualModule, } from "./detect_loader.js";
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { run } from "./run.js";
5
5
  import { resolveOptions } from "./types.js";
6
+ import { VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, detectImageLoader, generateLoaderVirtualModule, } from "./detect_loader.js";
6
7
  export const VIRTUAL_IMAGE_SHIM_ID = "virtual:cloudflare-next-intl-image";
7
8
  export const VIRTUAL_MANIFEST_ID = "virtual:cloudflare-next-intl-images-manifest";
8
9
  const RESOLVED_MANIFEST_ID = "\0" + VIRTUAL_MANIFEST_ID;
@@ -28,6 +29,9 @@ export function imageOptimizerPlugin(options) {
28
29
  if (id === VIRTUAL_MANIFEST_ID) {
29
30
  return RESOLVED_MANIFEST_ID;
30
31
  }
32
+ if (id === VIRTUAL_IMAGE_LOADER_ID) {
33
+ return RESOLVED_IMAGE_LOADER_ID;
34
+ }
31
35
  return undefined;
32
36
  },
33
37
  load(id) {
@@ -39,6 +43,14 @@ export function imageOptimizerPlugin(options) {
39
43
  }
40
44
  return `export default { images: {} };`;
41
45
  }
46
+ if (id === RESOLVED_IMAGE_LOADER_ID) {
47
+ if (resolved.autoImageLoader === false) {
48
+ return `export const defaultLoader = undefined;\nexport const hasCustomLoader = false;\nexport default undefined;\n`;
49
+ }
50
+ const loaderOptions = typeof resolved.autoImageLoader === "object" ? resolved.autoImageLoader : undefined;
51
+ const detected = detectImageLoader(loaderOptions);
52
+ return generateLoaderVirtualModule(detected);
53
+ }
42
54
  return undefined;
43
55
  },
44
56
  transform(code, id) {
@@ -1,3 +1,4 @@
1
+ import type { AutoImageLoaderOptions } from "./detect_loader.js";
1
2
  export type ImageFormat = "avif" | "webp" | "png" | "jpeg" | "gif" | "tiff" | "heif" | "jp2" | "jxl";
2
3
  export interface ImageBlurOptions {
3
4
  enabled?: boolean;
@@ -28,6 +29,7 @@ export interface ImageOptimizerPluginOptions {
28
29
  overrides?: Record<string, ImageOverrideOptions>;
29
30
  concurrency?: number;
30
31
  effort?: number;
32
+ autoImageLoader?: boolean | AutoImageLoaderOptions;
31
33
  }
32
34
  export interface ResolvedBlurOptions {
33
35
  enabled: boolean;
@@ -50,6 +52,7 @@ export interface ResolvedOptions {
50
52
  overrides: Record<string, ImageOverrideOptions>;
51
53
  concurrency: number;
52
54
  effort: number | undefined;
55
+ autoImageLoader: boolean | AutoImageLoaderOptions;
53
56
  }
54
57
  export interface ResolvedImageConfig {
55
58
  maxWidth: number | false;
@@ -21,6 +21,7 @@ export const DEFAULT_OPTIONS = {
21
21
  overrides: {},
22
22
  concurrency: Math.max(1, Math.min(cpus().length, 8)),
23
23
  effort: undefined,
24
+ autoImageLoader: true,
24
25
  };
25
26
  export function resolveBlurOptions(blur, parentDefault = DEFAULT_BLUR_OPTIONS) {
26
27
  if (blur === false) {
@@ -59,6 +60,7 @@ export function resolveOptions(options) {
59
60
  overrides: raw.overrides ? { ...raw.overrides } : {},
60
61
  concurrency: Math.max(1, raw.concurrency ?? DEFAULT_OPTIONS.concurrency),
61
62
  effort: raw.effort,
63
+ autoImageLoader: raw.autoImageLoader ?? DEFAULT_OPTIONS.autoImageLoader,
62
64
  };
63
65
  }
64
66
  export function resolveImageConfig(publicSrc, options) {
@@ -1,21 +1,5 @@
1
1
  import type { Plugin } from "vite";
2
- export declare const VIRTUAL_IMAGE_LOADER_ID = "virtual:cloudflare-next-intl-image-loader";
3
- export declare const RESOLVED_IMAGE_LOADER_ID: string;
4
- 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
- export interface AutoImageLoaderOptions {
6
- enabled?: boolean;
7
- file?: string;
8
- exportName?: string;
9
- root?: string;
10
- }
11
- export interface DetectedImageLoader {
12
- exists: boolean;
13
- isEmpty: boolean;
14
- loaderPath: string | null;
15
- exportName: string | null;
16
- }
17
- export declare function findExportedLoaderName(code: string, preferredExportName?: string): string | null;
18
- export declare function detectImageLoader(options?: AutoImageLoaderOptions): DetectedImageLoader;
19
- export declare function generateLoaderVirtualModule(detected: DetectedImageLoader): string;
2
+ import { NEXT_CONFIG_CANDIDATES, DEFAULT_LOADER_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, type AutoImageLoaderOptions, type DetectedImageLoader, findLoaderFileFromNextConfig, findExportedLoaderName, detectImageLoader, generateLoaderVirtualModule } from "../image_optimizer/detect_loader.js";
3
+ export { NEXT_CONFIG_CANDIDATES, DEFAULT_LOADER_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, type AutoImageLoaderOptions, type DetectedImageLoader, findLoaderFileFromNextConfig, findExportedLoaderName, detectImageLoader, generateLoaderVirtualModule, };
20
4
  export declare function autoImageLoaderPlugin(options?: AutoImageLoaderOptions): Plugin;
21
5
  export default autoImageLoaderPlugin;
@@ -1,115 +1,6 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import path from "node:path";
3
1
  import { getShimPath, VIRTUAL_IMAGE_SHIM_ID } from "../image_optimizer/plugin.js";
4
- export const VIRTUAL_IMAGE_LOADER_ID = "virtual:cloudflare-next-intl-image-loader";
5
- export const RESOLVED_IMAGE_LOADER_ID = "\0" + VIRTUAL_IMAGE_LOADER_ID;
6
- export const DEFAULT_LOADER_CANDIDATES = [
7
- "image-loader.ts",
8
- "image-loader.js",
9
- "image-loader.mjs",
10
- "image-loader.cjs",
11
- "image-loader.tsx",
12
- "image-loader.jsx",
13
- "src/image-loader.ts",
14
- "src/image-loader.js",
15
- "src/image-loader.mjs",
16
- "src/image-loader.cjs",
17
- "src/image-loader.tsx",
18
- "src/image-loader.jsx",
19
- ];
20
- export function findExportedLoaderName(code, preferredExportName) {
21
- const stripped = code
22
- .replace(/\/\*[\s\S]*?\*\//g, "")
23
- .replace(/\/\/.*/g, "");
24
- if (preferredExportName) {
25
- if (preferredExportName === "default") {
26
- if (/export\s+default\b/.test(stripped) || /export\s*\{[^}]*\bas\s+default\b[^}]*\}/.test(stripped)) {
27
- return "default";
28
- }
29
- return null;
30
- }
31
- const fnRegex = new RegExp(`export\\s+(?:async\\s+)?function\\s+${preferredExportName}\\b`);
32
- if (fnRegex.test(stripped))
33
- return preferredExportName;
34
- const constRegex = new RegExp(`export\\s+(?:const|let|var)\\s+${preferredExportName}\\b`);
35
- if (constRegex.test(stripped))
36
- return preferredExportName;
37
- const reExportRegex = new RegExp(`export\\s*\\{[^}]*\\b(?:as\\s+)?${preferredExportName}\\b[^}]*\\}`);
38
- if (reExportRegex.test(stripped))
39
- return preferredExportName;
40
- return null;
41
- }
42
- if (/export\s+default\b/.test(stripped) || /export\s*\{[^}]*\bas\s+default\b[^}]*\}/.test(stripped)) {
43
- return "default";
44
- }
45
- const fnMatch = stripped.match(/export\s+(?:async\s+)?function\s+([a-zA-Z0-9_$]+)/);
46
- if (fnMatch?.[1]) {
47
- return fnMatch[1];
48
- }
49
- const varMatch = stripped.match(/export\s+(?:const|let|var)\s+([a-zA-Z0-9_$]+)/);
50
- if (varMatch?.[1]) {
51
- return varMatch[1];
52
- }
53
- const exportBlockMatch = stripped.match(/export\s*\{([^}]+)\}/);
54
- if (exportBlockMatch?.[1]) {
55
- const entries = exportBlockMatch[1].split(",");
56
- for (const entry of entries) {
57
- const parts = entry.trim().split(/\s+as\s+/);
58
- const exportedName = parts[parts.length - 1]?.trim();
59
- if (exportedName) {
60
- return exportedName;
61
- }
62
- }
63
- }
64
- return null;
65
- }
66
- export function detectImageLoader(options) {
67
- const root = options?.root ? path.resolve(options.root) : process.cwd();
68
- let targetPath = null;
69
- if (options?.file) {
70
- const customPath = path.isAbsolute(options.file) ? options.file : path.resolve(root, options.file);
71
- if (existsSync(customPath)) {
72
- targetPath = customPath;
73
- }
74
- else {
75
- return { exists: false, isEmpty: false, loaderPath: null, exportName: null };
76
- }
77
- }
78
- else {
79
- for (const candidate of DEFAULT_LOADER_CANDIDATES) {
80
- const candidatePath = path.resolve(root, candidate);
81
- if (existsSync(candidatePath)) {
82
- targetPath = candidatePath;
83
- break;
84
- }
85
- }
86
- }
87
- if (!targetPath) {
88
- return { exists: false, isEmpty: false, loaderPath: null, exportName: null };
89
- }
90
- const content = readFileSync(targetPath, "utf8");
91
- const stripped = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*/g, "").trim();
92
- if (!stripped) {
93
- return { exists: true, isEmpty: true, loaderPath: targetPath, exportName: null };
94
- }
95
- const exportName = findExportedLoaderName(content, options?.exportName);
96
- return {
97
- exists: true,
98
- isEmpty: false,
99
- loaderPath: targetPath,
100
- exportName,
101
- };
102
- }
103
- export function generateLoaderVirtualModule(detected) {
104
- if (!detected.exists || detected.isEmpty || !detected.loaderPath || !detected.exportName) {
105
- return `export const defaultLoader = undefined;\nexport const hasCustomLoader = false;\nexport default undefined;\n`;
106
- }
107
- const normalizedPath = detected.loaderPath.replace(/\\/g, "/");
108
- if (detected.exportName === "default") {
109
- return `import loader from ${JSON.stringify(normalizedPath)};\nexport const defaultLoader = loader;\nexport const hasCustomLoader = true;\nexport default loader;\n`;
110
- }
111
- return `import { ${detected.exportName} as loader } from ${JSON.stringify(normalizedPath)};\nexport const defaultLoader = loader;\nexport const hasCustomLoader = true;\nexport default loader;\n`;
112
- }
2
+ import { NEXT_CONFIG_CANDIDATES, DEFAULT_LOADER_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, findLoaderFileFromNextConfig, findExportedLoaderName, detectImageLoader, generateLoaderVirtualModule, } from "../image_optimizer/detect_loader.js";
3
+ export { NEXT_CONFIG_CANDIDATES, DEFAULT_LOADER_CANDIDATES, VIRTUAL_IMAGE_LOADER_ID, RESOLVED_IMAGE_LOADER_ID, findLoaderFileFromNextConfig, findExportedLoaderName, detectImageLoader, generateLoaderVirtualModule, };
113
4
  export function autoImageLoaderPlugin(options) {
114
5
  const isEnabled = options?.enabled !== false;
115
6
  return {
@@ -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";
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-next-intl",
3
- "version": "0.10.29",
3
+ "version": "0.10.31",
4
4
  "description": "Optimized Next Intl Package Special for App Router and Cloudflare",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",