next-bun-compile 0.11.0 → 0.11.1
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/dist/adapter.js
CHANGED
|
@@ -567,6 +567,47 @@ function computeStaticTiersFromSnapshot(snapshot, args) {
|
|
|
567
567
|
tags
|
|
568
568
|
});
|
|
569
569
|
}
|
|
570
|
+
const claimed = new Set(staticPages.map((s) => s.path));
|
|
571
|
+
for (const f of snapshot.staticFiles ?? []) {
|
|
572
|
+
if (f.pathname.startsWith("/_"))
|
|
573
|
+
continue;
|
|
574
|
+
if (f.pathname === "/404" || f.pathname === "/500")
|
|
575
|
+
continue;
|
|
576
|
+
if (claimed.has(f.pathname) || covered(f.pathname))
|
|
577
|
+
continue;
|
|
578
|
+
const file = f.file.replace(/\\/g, "/");
|
|
579
|
+
let meta = {};
|
|
580
|
+
const suffix = [".html", ".body"].find((s) => file.endsWith(s));
|
|
581
|
+
if (suffix) {
|
|
582
|
+
try {
|
|
583
|
+
meta = JSON.parse(readFileSync(join(args.distDir, file.slice(0, -suffix.length) + ".meta"), "utf-8"));
|
|
584
|
+
} catch {}
|
|
585
|
+
}
|
|
586
|
+
const isHtml = file.endsWith(".html");
|
|
587
|
+
const contentType = meta.headers?.["content-type"];
|
|
588
|
+
if (!isHtml && !contentType)
|
|
589
|
+
continue;
|
|
590
|
+
const headers = {};
|
|
591
|
+
let tags = [];
|
|
592
|
+
for (const [k, v] of Object.entries(meta.headers ?? {})) {
|
|
593
|
+
const lc = k.toLowerCase();
|
|
594
|
+
if (lc === "x-next-cache-tags") {
|
|
595
|
+
tags = v.split(",").map((t) => t.trim()).filter(Boolean);
|
|
596
|
+
} else if (lc !== "vary" && lc !== "content-type") {
|
|
597
|
+
headers[k] = v;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
claimed.add(f.pathname);
|
|
601
|
+
staticPages.push({
|
|
602
|
+
path: f.pathname,
|
|
603
|
+
htmlKey: `__runtime/.next/${file}`,
|
|
604
|
+
rscKey: null,
|
|
605
|
+
headers,
|
|
606
|
+
status: meta.status ?? 200,
|
|
607
|
+
tags,
|
|
608
|
+
...isHtml ? {} : { contentType }
|
|
609
|
+
});
|
|
610
|
+
}
|
|
570
611
|
return {
|
|
571
612
|
tier1,
|
|
572
613
|
staticPages,
|
|
@@ -581,6 +622,7 @@ function computeStaticTiers(args) {
|
|
|
581
622
|
throw new Error('next-bun-compile: adapter outputs not found for this build. Build through the adapter: set `adapterPath: "next-bun-compile/adapter"` in next.config (or NEXT_ADAPTER_PATH=next-bun-compile/adapter) and run `next build`.');
|
|
582
623
|
}
|
|
583
624
|
return computeStaticTiersFromSnapshot(snapshot, {
|
|
625
|
+
distDir,
|
|
584
626
|
staticFiles,
|
|
585
627
|
publicFiles,
|
|
586
628
|
assetPrefix
|
|
@@ -1116,15 +1158,35 @@ async function assembleStandalone(ctx) {
|
|
|
1116
1158
|
}
|
|
1117
1159
|
} catch {}
|
|
1118
1160
|
}
|
|
1119
|
-
|
|
1120
|
-
const file = p.fallback?.filePath;
|
|
1121
|
-
if (!file)
|
|
1122
|
-
continue;
|
|
1161
|
+
const copySeed = (file) => {
|
|
1123
1162
|
copyTo(relative2(ctx.repoRoot, file), file);
|
|
1124
|
-
|
|
1125
|
-
|
|
1163
|
+
const suffix = [".html", ".body"].find((s) => file.endsWith(s));
|
|
1164
|
+
if (suffix) {
|
|
1165
|
+
const meta = file.slice(0, -suffix.length) + ".meta";
|
|
1126
1166
|
copyTo(relative2(ctx.repoRoot, meta), meta);
|
|
1127
1167
|
}
|
|
1168
|
+
};
|
|
1169
|
+
for (const p of outputs.prerenders ?? []) {
|
|
1170
|
+
if (p.fallback?.filePath)
|
|
1171
|
+
copySeed(p.fallback.filePath);
|
|
1172
|
+
}
|
|
1173
|
+
for (const f of outputs.staticFiles ?? []) {
|
|
1174
|
+
if (!f.filePath || f.pathname?.startsWith("/_next/"))
|
|
1175
|
+
continue;
|
|
1176
|
+
copySeed(f.filePath);
|
|
1177
|
+
if (f.filePath.endsWith(".body")) {
|
|
1178
|
+
const routeJs = join4(f.filePath.slice(0, -".body".length), "route.js");
|
|
1179
|
+
if (existsSync3(routeJs)) {
|
|
1180
|
+
copyTo(relative2(ctx.repoRoot, routeJs), routeJs);
|
|
1181
|
+
try {
|
|
1182
|
+
const { files } = JSON.parse(readFileSync2(routeJs + ".nft.json", "utf-8"));
|
|
1183
|
+
for (const dep of files) {
|
|
1184
|
+
const src = resolve(dirname2(routeJs), dep);
|
|
1185
|
+
copyTo(relative2(ctx.repoRoot, src), src);
|
|
1186
|
+
}
|
|
1187
|
+
} catch {}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1128
1190
|
}
|
|
1129
1191
|
for (const extra of ["BUILD_ID", "required-server-files.json"]) {
|
|
1130
1192
|
const src = join4(ctx.distDir, extra);
|
|
@@ -1153,7 +1215,9 @@ var adapter = {
|
|
|
1153
1215
|
if (!Array.isArray(list))
|
|
1154
1216
|
continue;
|
|
1155
1217
|
for (const route of list) {
|
|
1156
|
-
|
|
1218
|
+
const headerKeys = Object.keys(route.headers ?? {});
|
|
1219
|
+
const isDeploymentIdRule = headerKeys.length === 1 && headerKeys[0] === "x-nextjs-deployment-id";
|
|
1220
|
+
if (route.sourceRegex && typeof route.source === "string" && !route.priority && !isDeploymentIdRule && (headerKeys.length > 0 || route.destination || route.status)) {
|
|
1157
1221
|
routingRules.push(route.sourceRegex);
|
|
1158
1222
|
}
|
|
1159
1223
|
}
|
|
@@ -1172,6 +1236,18 @@ var adapter = {
|
|
|
1172
1236
|
}
|
|
1173
1237
|
];
|
|
1174
1238
|
});
|
|
1239
|
+
const staticFiles = (ctx.outputs?.staticFiles ?? []).flatMap((f) => {
|
|
1240
|
+
if (!f.pathname || !f.filePath)
|
|
1241
|
+
return [];
|
|
1242
|
+
if (f.pathname.startsWith("/_next/"))
|
|
1243
|
+
return [];
|
|
1244
|
+
return [
|
|
1245
|
+
{
|
|
1246
|
+
pathname: f.pathname,
|
|
1247
|
+
file: relative2(ctx.distDir, f.filePath)
|
|
1248
|
+
}
|
|
1249
|
+
];
|
|
1250
|
+
});
|
|
1175
1251
|
const snapshot = {
|
|
1176
1252
|
version: 1,
|
|
1177
1253
|
buildId: ctx.buildId,
|
|
@@ -1181,7 +1257,8 @@ var adapter = {
|
|
|
1181
1257
|
hasCustomCacheHandler: !!ctx.config.cacheHandler,
|
|
1182
1258
|
middlewareMatchers: (ctx.outputs?.middleware?.config?.matchers ?? []).map((m) => m.sourceRegex).filter((r) => !!r),
|
|
1183
1259
|
routingRules,
|
|
1184
|
-
prerenders
|
|
1260
|
+
prerenders,
|
|
1261
|
+
staticFiles
|
|
1185
1262
|
};
|
|
1186
1263
|
writeFileSync2(join4(ctx.distDir, ADAPTER_OUTPUTS_FILE), JSON.stringify(snapshot, null, 2));
|
|
1187
1264
|
console.log(`next-bun-compile: adapter outputs written (${prerenders.length} prerender entries)`);
|
package/dist/index.js
CHANGED
package/dist/runtime/serve.js
CHANGED
|
@@ -355,7 +355,8 @@ async function buildTier1Routes(tier1, assetMap, bridge) {
|
|
|
355
355
|
|
|
356
356
|
/** Tier 2: prerendered page with RSC negotiation + ETag/304. */
|
|
357
357
|
function makePageHandler(page, bridge) {
|
|
358
|
-
const { html, rsc, headers: metaHeaders, status } =
|
|
358
|
+
const { html, rsc, headers: metaHeaders, status, contentType, deploymentId } =
|
|
359
|
+
page;
|
|
359
360
|
const htmlEtag = `"${Bun.hash(html).toString(36)}"`;
|
|
360
361
|
const rscEtag = rsc ? `"${Bun.hash(rsc).toString(36)}"` : null;
|
|
361
362
|
const htmlGz = html.byteLength >= GZIP_MIN_BYTES ? Bun.gzipSync(html) : null;
|
|
@@ -363,9 +364,16 @@ function makePageHandler(page, bridge) {
|
|
|
363
364
|
rsc && rsc.byteLength >= GZIP_MIN_BYTES ? Bun.gzipSync(rsc) : null;
|
|
364
365
|
|
|
365
366
|
const base = {};
|
|
366
|
-
|
|
367
|
+
let hasCacheControl = false;
|
|
368
|
+
for (const [k, v] of Object.entries(metaHeaders || {})) {
|
|
369
|
+
base[k] = v;
|
|
370
|
+
if (k.toLowerCase() === "cache-control") hasCacheControl = true;
|
|
371
|
+
}
|
|
367
372
|
base["Vary"] = PAGE_VARY;
|
|
368
|
-
|
|
373
|
+
// Seeds that recorded an explicit cache-control (static metadata routes:
|
|
374
|
+
// public, max-age=0, must-revalidate) keep it — pages get the frozen-
|
|
375
|
+
// prerender policy.
|
|
376
|
+
if (!hasCacheControl) base["Cache-Control"] = "s-maxage=31536000";
|
|
369
377
|
base["x-nextjs-cache"] = "HIT";
|
|
370
378
|
|
|
371
379
|
return (req, server) => {
|
|
@@ -391,12 +399,16 @@ function makePageHandler(page, bridge) {
|
|
|
391
399
|
...base,
|
|
392
400
|
"Content-Type": wantsRsc
|
|
393
401
|
? "text/x-component"
|
|
394
|
-
: "text/html; charset=utf-8",
|
|
402
|
+
: contentType || "text/html; charset=utf-8",
|
|
395
403
|
...(useGzip && { "Content-Encoding": "gzip" }),
|
|
396
404
|
"Content-Length": String(payload.byteLength),
|
|
397
405
|
ETag: etag,
|
|
398
406
|
// Baseline sends X-Powered-By on documents but not RSC payloads.
|
|
399
407
|
...(!wantsRsc && { "X-Powered-By": "Next.js" }),
|
|
408
|
+
// With a deploymentId configured, Next stamps RSC responses so the
|
|
409
|
+
// client router can detect deployment skew — replicate it.
|
|
410
|
+
...(wantsRsc &&
|
|
411
|
+
deploymentId && { "x-nextjs-deployment-id": deploymentId }),
|
|
400
412
|
};
|
|
401
413
|
if (req.headers.get("if-none-match") === etag) {
|
|
402
414
|
return new Response(null, { status: 304, headers });
|
|
@@ -408,7 +420,7 @@ function makePageHandler(page, bridge) {
|
|
|
408
420
|
};
|
|
409
421
|
}
|
|
410
422
|
|
|
411
|
-
async function buildTier2Routes(staticPages, assetMap, bridge) {
|
|
423
|
+
async function buildTier2Routes(staticPages, assetMap, bridge, deploymentId) {
|
|
412
424
|
const routes = {};
|
|
413
425
|
await Promise.all(
|
|
414
426
|
staticPages.map(async (spec) => {
|
|
@@ -416,7 +428,14 @@ async function buildTier2Routes(staticPages, assetMap, bridge) {
|
|
|
416
428
|
if (html == null) return;
|
|
417
429
|
const rsc = spec.rscKey ? await loadBytes(assetMap, spec.rscKey) : null;
|
|
418
430
|
const handler = makePageHandler(
|
|
419
|
-
{
|
|
431
|
+
{
|
|
432
|
+
html,
|
|
433
|
+
rsc,
|
|
434
|
+
headers: spec.headers,
|
|
435
|
+
status: spec.status,
|
|
436
|
+
contentType: spec.contentType,
|
|
437
|
+
deploymentId,
|
|
438
|
+
},
|
|
420
439
|
bridge
|
|
421
440
|
);
|
|
422
441
|
// Plain function route: GET/HEAD from memory, everything else
|
|
@@ -577,7 +596,12 @@ async function start(opts) {
|
|
|
577
596
|
|
|
578
597
|
const [tier1Routes, tier2Routes] = await Promise.all([
|
|
579
598
|
buildTier1Routes(tier1, assetMap, bridgeLazy),
|
|
580
|
-
buildTier2Routes(
|
|
599
|
+
buildTier2Routes(
|
|
600
|
+
staticPages,
|
|
601
|
+
assetMap,
|
|
602
|
+
bridgeLazy,
|
|
603
|
+
nextConfig?.deploymentId
|
|
604
|
+
),
|
|
581
605
|
]);
|
|
582
606
|
|
|
583
607
|
const routes = { ...tier1Routes, ...tier2Routes };
|