@edgeone/opennextjs-pages 0.2.2 → 0.2.4

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.
@@ -86,7 +86,11 @@ var copyNextServerCode = async (ctx) => {
86
86
  [`*`, `server/*`, `server/**/*`, `server/edge-chunks/*`, `server/+(app|pages)/**/*.js`],
87
87
  {
88
88
  cwd: srcDir,
89
- extglob: true
89
+ extglob: true,
90
+ // Exclude files that are not needed at runtime to reduce package size:
91
+ // - *.map: source maps, only useful for debugging (~40MB+ on large apps)
92
+ // - *.nft.json: Next.js file-tracing metadata, only used at build time (~13MB+)
93
+ ignore: ["**/*.map", "**/*.nft.json"]
90
94
  }
91
95
  );
92
96
  await Promise.all(
@@ -2384,35 +2384,55 @@ function transformForEdgeOneRuntime(code) {
2384
2384
  }
2385
2385
  function fixWebpackConfigExport(code) {
2386
2386
  let transformed = code;
2387
- const configDefPatterns = [
2388
- // 字符串 matcher: let be={matcher:"/normal/test"}
2389
- /(?:let|var|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\{\s*matcher\s*:\s*"([^"]+)"\s*\}/,
2390
- // 压缩格式: ;be={matcher:"/normal/test"} 或 ,be={matcher:"..."}
2391
- /[;,]([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\{\s*matcher\s*:\s*"([^"]+)"\s*\}/,
2392
- // 数组 matcher: let be={matcher:["/api/:path*", "/dashboard/:path*"]}
2393
- /(?:let|var|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\{\s*matcher\s*:\s*(\[[^\]]+\])\s*\}/,
2394
- // 压缩格式数组: ;be={matcher:[...]}
2395
- /[;,]([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\{\s*matcher\s*:\s*(\[[^\]]+\])\s*\}/
2396
- ];
2397
2387
  let configVarName = null;
2398
2388
  let configValue = null;
2399
- for (const pattern of configDefPatterns) {
2400
- const match = pattern.exec(code);
2401
- if (match) {
2402
- configVarName = match[1];
2403
- if (match[2].startsWith("[")) {
2404
- configValue = `{matcher:${match[2]}}`;
2405
- } else {
2406
- configValue = `{matcher:"${match[2]}"}`;
2389
+ const exportPattern = /c\.d\s*\(\s*\w+\s*,\s*\{[^}]*config\s*:\s*\(\s*\)\s*=>\s*([a-zA-Z_$][a-zA-Z0-9_$]*)/s;
2390
+ const exportMatch = code.match(exportPattern);
2391
+ if (exportMatch) {
2392
+ configVarName = exportMatch[1];
2393
+ }
2394
+ if (configVarName) {
2395
+ const escapedVarName = configVarName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2396
+ const defPattern = new RegExp(
2397
+ `(?:let|var|const|[;,])\\s*${escapedVarName}\\s*=\\s*\\{\\s*matcher\\s*:`
2398
+ );
2399
+ const defMatch = defPattern.exec(code);
2400
+ if (defMatch) {
2401
+ const matchStr = defMatch[0];
2402
+ const openBraceOffset = matchStr.indexOf("{");
2403
+ const assignStart = defMatch.index + openBraceOffset;
2404
+ let depth = 0;
2405
+ let endIdx = -1;
2406
+ for (let i = assignStart; i < code.length; i++) {
2407
+ if (code[i] === "{") {
2408
+ depth++;
2409
+ } else if (code[i] === "}") {
2410
+ depth--;
2411
+ if (depth === 0) {
2412
+ endIdx = i + 1;
2413
+ break;
2414
+ }
2415
+ }
2416
+ }
2417
+ if (endIdx !== -1) {
2418
+ configValue = code.slice(assignStart, endIdx);
2407
2419
  }
2408
- break;
2409
2420
  }
2410
2421
  }
2411
- if (!configVarName) {
2412
- const exportPattern = /c\.d\s*\(\s*\w+\s*,\s*\{[^}]*config\s*:\s*\(\s*\)\s*=>\s*([a-zA-Z_$][a-zA-Z0-9_$]*)[^}]*\}/;
2413
- const exportMatch = code.match(exportPattern);
2414
- if (exportMatch) {
2415
- configVarName = exportMatch[1];
2422
+ if (!configVarName || !configValue) {
2423
+ const simplePatterns = [
2424
+ // 字符串 matcher(简单路径,不含特殊字符)
2425
+ /(?:let|var|const)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\{\s*matcher\s*:\s*"([^"]+)"\s*\}/,
2426
+ // 压缩格式字符串
2427
+ /[;,]([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\{\s*matcher\s*:\s*"([^"]+)"\s*\}/
2428
+ ];
2429
+ for (const pattern of simplePatterns) {
2430
+ const match = pattern.exec(code);
2431
+ if (match) {
2432
+ configVarName = match[1];
2433
+ configValue = `{matcher:"${match[2]}"}`;
2434
+ break;
2435
+ }
2416
2436
  }
2417
2437
  }
2418
2438
  if (configVarName && configValue) {
@@ -2429,8 +2449,7 @@ function fixWebpackConfigExport(code) {
2429
2449
  if (match.includes("config:")) {
2430
2450
  return match;
2431
2451
  }
2432
- const configRef = configValue;
2433
- const replacement = `${prefix}Object.assign({},${varName},{config:${configRef}})`;
2452
+ const replacement = `${prefix}Object.assign({},${varName},{config:${configValue}})`;
2434
2453
  return replacement;
2435
2454
  });
2436
2455
  }
@@ -2935,6 +2954,43 @@ function getExternalMock(id) {
2935
2954
  return result;
2936
2955
  }
2937
2956
 
2957
+ // shared-cache-controls mock - must be matched before the general incremental-cache mock
2958
+ // Next.js 16+ uses SharedCacheControls from this module in IncrementalCache constructor
2959
+ if (id.includes('shared-cache-controls')) {
2960
+ class SharedCacheControls {
2961
+ constructor(prerenderManifest) {
2962
+ this.prerenderManifest = prerenderManifest;
2963
+ this.controls = new Map();
2964
+ }
2965
+ get(key) { return this.controls.get(key); }
2966
+ set(key, value) { this.controls.set(key, value); }
2967
+ }
2968
+ const result = {
2969
+ SharedCacheControls,
2970
+ default: { SharedCacheControls }
2971
+ };
2972
+ Object.defineProperty(result, '__esModule', { value: true });
2973
+ return result;
2974
+ }
2975
+
2976
+ // shared-revalidate-timings mock - similarly used by IncrementalCache in older versions
2977
+ if (id.includes('shared-revalidate-timings')) {
2978
+ class SharedRevalidateTimings {
2979
+ constructor(prerenderManifest) {
2980
+ this.prerenderManifest = prerenderManifest;
2981
+ this.timings = new Map();
2982
+ }
2983
+ get(key) { return this.timings.get(key); }
2984
+ set(key, value) { this.timings.set(key, value); }
2985
+ }
2986
+ const result = {
2987
+ SharedRevalidateTimings,
2988
+ default: { SharedRevalidateTimings }
2989
+ };
2990
+ Object.defineProperty(result, '__esModule', { value: true });
2991
+ return result;
2992
+ }
2993
+
2938
2994
  // incremental-cache/tags-manifest mock
2939
2995
  if (id.includes('incremental-cache') || id.includes('tags-manifest')) {
2940
2996
  const result = {
@@ -16,6 +16,7 @@ import {
16
16
  } from "../../esm-chunks/chunk-6BT4RYQJ.js";
17
17
 
18
18
  // src/build/functions/server.ts
19
+ import { existsSync, readFileSync } from "node:fs";
19
20
  import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
20
21
  import { join, relative } from "node:path";
21
22
  import { join as posixJoin } from "node:path/posix";
@@ -26,9 +27,63 @@ import {
26
27
  verifyHandlerDirStructure
27
28
  } from "../content/server.js";
28
29
  var tracer = wrapTracer(trace.getTracer("Next runtime"));
30
+ function getOutputFileTracingIncludes(appDir) {
31
+ const configFiles = [
32
+ "next.config.original.ts",
33
+ "next.config.original.mjs",
34
+ "next.config.original.js",
35
+ "next.config.original.cjs",
36
+ "next.config.ts",
37
+ "next.config.mjs",
38
+ "next.config.js",
39
+ "next.config.cjs"
40
+ ];
41
+ for (const configFile of configFiles) {
42
+ const configPath = join(appDir, configFile);
43
+ if (!existsSync(configPath)) continue;
44
+ try {
45
+ const content = readFileSync(configPath, "utf-8");
46
+ const match = content.match(
47
+ /outputFileTracingIncludes\s*:\s*\{([\s\S]*?)(?=\n\s*\}[,;\s]*\n|\n\s*\}\s*[,\n])/
48
+ );
49
+ if (!match) continue;
50
+ const body = match[1];
51
+ const result = {};
52
+ const pairPattern = /['"]([^'"]+)['"]\s*:\s*\[([\s\S]*?)\]/g;
53
+ let pairMatch;
54
+ while ((pairMatch = pairPattern.exec(body)) !== null) {
55
+ const key = pairMatch[1];
56
+ const arrayBody = pairMatch[2];
57
+ const patterns = [];
58
+ const strPattern = /['"]([^'"]+)['"]/g;
59
+ let strMatch;
60
+ while ((strMatch = strPattern.exec(arrayBody)) !== null) {
61
+ patterns.push(strMatch[1]);
62
+ }
63
+ if (patterns.length > 0) {
64
+ result[key] = patterns;
65
+ }
66
+ }
67
+ if (Object.keys(result).length > 0) {
68
+ return result;
69
+ }
70
+ } catch {
71
+ }
72
+ }
73
+ return {};
74
+ }
29
75
  var copyHandlerDependencies = async (ctx) => {
30
76
  const promises = [];
31
- const { included_files: includedFiles = [] } = {};
77
+ const includedFiles = [];
78
+ const appDir = ctx.requiredServerFiles?.appDir || process.cwd();
79
+ const outputFileTracingIncludes = getOutputFileTracingIncludes(appDir);
80
+ for (const patterns of Object.values(outputFileTracingIncludes)) {
81
+ for (const pattern of patterns) {
82
+ includedFiles.push(
83
+ ctx.relativeAppDir ? posixJoin(ctx.relativeAppDir, pattern) : pattern
84
+ );
85
+ }
86
+ }
32
87
  includedFiles.push(
33
88
  posixJoin(ctx.relativeAppDir, ".env"),
34
89
  posixJoin(ctx.relativeAppDir, ".env.production"),
@@ -51,47 +51,81 @@ function generateWrapperConfig(ext, importPath) {
51
51
  const isTS = ext.includes("ts");
52
52
  const isMJS = ext.includes("mjs") || ext.includes("mts");
53
53
  if (isTS) {
54
- return `import originalConfig from '${importPath}'
54
+ return `import originalExport from '${importPath}'
55
55
  import type { NextConfig } from 'next'
56
56
 
57
- const config: NextConfig = {
58
- ...originalConfig as any,
59
- images: {
60
- ...(originalConfig as any)?.images,
61
- loader: 'custom',
62
- loaderFile: './.edgeone/image-loader.mjs',
63
- },
64
- };
57
+ let config: NextConfig;
58
+ if (typeof originalExport === 'function') {
59
+ // Function-style config: (phase, context) => NextConfig
60
+ // Wrap it to inject images config after resolution
61
+ const origFn = originalExport as any;
62
+ config = ((...args: any[]) => {
63
+ const resolved = origFn(...args);
64
+ if (resolved && typeof resolved.then === 'function') {
65
+ return (resolved as Promise<NextConfig>).then((c: any) => {
66
+ c.images = { ...c.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
67
+ return c;
68
+ });
69
+ }
70
+ (resolved as any).images = { ...(resolved as any).images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
71
+ return resolved;
72
+ }) as any;
73
+ } else {
74
+ config = { ...(originalExport as any) };
75
+ config.images = { ...config.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
76
+ }
65
77
 
66
78
  export default config;
67
79
  `;
68
80
  }
69
81
  if (isMJS) {
70
- return `import originalConfig from '${importPath}';
82
+ return `import originalExport from '${importPath}';
71
83
 
72
- const config = {
73
- ...originalConfig,
74
- images: {
75
- ...originalConfig?.images,
76
- loader: 'custom',
77
- loaderFile: './.edgeone/image-loader.mjs',
78
- },
79
- };
84
+ let config;
85
+ if (typeof originalExport === 'function') {
86
+ const origFn = originalExport;
87
+ config = (...args) => {
88
+ const resolved = origFn(...args);
89
+ if (resolved && typeof resolved.then === 'function') {
90
+ return resolved.then((c) => {
91
+ c.images = { ...c.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
92
+ return c;
93
+ });
94
+ }
95
+ resolved.images = { ...resolved.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
96
+ return resolved;
97
+ };
98
+ } else {
99
+ config = { ...originalExport };
100
+ config.images = { ...config.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
101
+ }
80
102
 
81
103
  export default config;
82
104
  `;
83
105
  }
84
- return `const originalConfig = require('${importPath}');
85
- const resolved = originalConfig.default || originalConfig;
106
+ return `const originalExport = require('${importPath}');
107
+ const resolved = originalExport.default || originalExport;
86
108
 
87
- module.exports = {
88
- ...resolved,
89
- images: {
90
- ...resolved?.images,
91
- loader: 'custom',
92
- loaderFile: './.edgeone/image-loader.mjs',
93
- },
94
- };
109
+ let config;
110
+ if (typeof resolved === 'function') {
111
+ const origFn = resolved;
112
+ config = (...args) => {
113
+ const result = origFn(...args);
114
+ if (result && typeof result.then === 'function') {
115
+ return result.then((c) => {
116
+ c.images = { ...c.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
117
+ return c;
118
+ });
119
+ }
120
+ result.images = { ...result.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
121
+ return result;
122
+ };
123
+ } else {
124
+ config = { ...resolved };
125
+ config.images = { ...config.images, loader: 'custom', loaderFile: './.edgeone/image-loader.mjs' };
126
+ }
127
+
128
+ module.exports = config;
95
129
  `;
96
130
  }
97
131
  function injectImageLoader(cwd) {
@@ -141,21 +141,32 @@ var EdgeoneCacheHandler = class {
141
141
  const prerenderManifest = await this.getPrerenderManifest(this.options.serverDistDir);
142
142
  if (typeof cacheControl !== "undefined") {
143
143
  try {
144
- const { SharedCacheControls } = await import(
144
+ const sharedCacheControlsModule = await import(
145
145
  // @ts-expect-error supporting multiple next version, this module is not resolvable with currently used dev dependency
146
146
  // eslint-disable-next-line import/no-unresolved, n/no-missing-import
147
147
  "next/dist/server/lib/incremental-cache/shared-cache-controls.external.js"
148
148
  );
149
+ const SharedCacheControls = sharedCacheControlsModule.SharedCacheControls || sharedCacheControlsModule.default?.SharedCacheControls || sharedCacheControlsModule.default;
150
+ if (typeof SharedCacheControls !== "function") {
151
+ throw new Error("SharedCacheControls is not a constructor in .external.js module");
152
+ }
149
153
  const sharedCacheControls = new SharedCacheControls(prerenderManifest);
150
154
  sharedCacheControls.set(key, cacheControl);
151
155
  } catch {
152
- const { SharedCacheControls } = await import(
153
- // @ts-expect-error supporting multiple next version, this module is not resolvable with currently used dev dependency
154
- // eslint-disable-next-line import/no-unresolved, n/no-missing-import
155
- "next/dist/server/lib/incremental-cache/shared-cache-controls.js"
156
- );
157
- const sharedCacheControls = new SharedCacheControls(prerenderManifest);
158
- sharedCacheControls.set(key, cacheControl);
156
+ try {
157
+ const sharedCacheControlsModule = await import(
158
+ // @ts-expect-error supporting multiple next version, this module is not resolvable with currently used dev dependency
159
+ // eslint-disable-next-line import/no-unresolved, n/no-missing-import
160
+ "next/dist/server/lib/incremental-cache/shared-cache-controls.js"
161
+ );
162
+ const SharedCacheControls = sharedCacheControlsModule.SharedCacheControls || sharedCacheControlsModule.default?.SharedCacheControls || sharedCacheControlsModule.default;
163
+ if (typeof SharedCacheControls !== "function") {
164
+ throw new Error("SharedCacheControls is not a constructor in .js module");
165
+ }
166
+ const sharedCacheControls = new SharedCacheControls(prerenderManifest);
167
+ sharedCacheControls.set(key, cacheControl);
168
+ } catch {
169
+ }
159
170
  }
160
171
  } else if (typeof revalidate === "number" || revalidate === false) {
161
172
  try {
@@ -3124,6 +3124,18 @@ var disableFaultyTransferEncodingHandling = (res) => {
3124
3124
  return originalStoreHeader.call(this, firstLine, headers);
3125
3125
  };
3126
3126
  };
3127
+ function getRealHostInfo(headers) {
3128
+ const get = (key) => {
3129
+ if (typeof headers.get === "function") {
3130
+ return headers.get(key) || "";
3131
+ }
3132
+ return headers[key] || "";
3133
+ };
3134
+ const host = get("eo-pages-host") || get("host") || "localhost";
3135
+ const protocol = get("x-forwarded-proto") || "https";
3136
+ return { host, protocol };
3137
+ }
3138
+ var NEXT_REQUEST_META = Symbol.for("NextInternalRequestMeta");
3127
3139
  var server_default = async (request, _context, topLevelSpan, requestContext) => {
3128
3140
  const tracer = getTracer();
3129
3141
  if (!nextHandler) {
@@ -3139,9 +3151,14 @@ var server_default = async (request, _context, topLevelSpan, requestContext) =>
3139
3151
  });
3140
3152
  }
3141
3153
  return await tracer.withActiveSpan("generate response", async (span) => {
3154
+ const { host: realHost, protocol: realProtocol } = getRealHostInfo(request.headers);
3142
3155
  const headersList = [];
3143
3156
  for (var key in request.headers) {
3144
- headersList.push([key, request.headers[key]]);
3157
+ if (key === "host") {
3158
+ headersList.push([key, realHost]);
3159
+ } else {
3160
+ headersList.push([key, request.headers[key]]);
3161
+ }
3145
3162
  }
3146
3163
  let bodyStream = request.body;
3147
3164
  if (typeof bodyStream === "undefined" && request.method !== "GET" && request.method !== "HEAD") {
@@ -3166,7 +3183,7 @@ var server_default = async (request, _context, topLevelSpan, requestContext) =>
3166
3183
  const { req, res } = toReqRes({
3167
3184
  ...request,
3168
3185
  body: bodyStream,
3169
- url: "http://localhost:9000" + request.url,
3186
+ url: `${realProtocol}://${realHost}${request.url}`,
3170
3187
  headers: headersList
3171
3188
  });
3172
3189
  Object.defineProperty(req, "connection", {
@@ -3180,6 +3197,21 @@ var server_default = async (request, _context, topLevelSpan, requestContext) =>
3180
3197
  }
3181
3198
  });
3182
3199
  disableFaultyTransferEncodingHandling(res);
3200
+ const realOrigin = `${realProtocol}://${realHost}`;
3201
+ const metaProxy = new Proxy({}, {
3202
+ set(target, prop, value) {
3203
+ if (prop === "initURL" && typeof value === "string") {
3204
+ target[prop] = value.replace(/^https?:\/\/localhost(:\d+)?/, realOrigin);
3205
+ } else {
3206
+ target[prop] = value;
3207
+ }
3208
+ return true;
3209
+ },
3210
+ get(target, prop) {
3211
+ return target[prop];
3212
+ }
3213
+ });
3214
+ req[NEXT_REQUEST_META] = metaProxy;
3183
3215
  const resProxy = nextResponseProxy(res, requestContext);
3184
3216
  const nextHandlerPromise = nextHandler(req, resProxy).catch((error) => {
3185
3217
  getLogger().withError(error).error("next handler error");
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(tags_handler_exports);
28
28
 
29
29
  // package.json
30
30
  var name = "@edgeone/opennextjs-pages";
31
- var version = "0.2.2";
31
+ var version = "0.2.4";
32
32
 
33
33
  // src/run/handlers/tags-handler.cts
34
34
  var import_request_context = require("./request-context.cjs");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgeone/opennextjs-pages",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",