Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,26 @@ const nextConfig = {
transpilePackages: ["jose"],
serverExternalPackages: ["@duckdb/node-api"],
async headers() {
// ponytail: un-hashed filenames under public/, so `immutable` is unsafe —
// a redeploy has to be able to replace these in place. An hour of freshness
// drops the per-navigation revalidation round-trip without stranding a
// stale asset for long.
const staticAssets = [
{
source: "/:dir(img|logo)/:path*",
headers: [
{
key: "Cache-Control",
value: "public, max-age=3600, stale-while-revalidate=604800",
},
],
},
];
if (process.env.STAGE === "prod") {
return [];
return staticAssets;
}
return [
...staticAssets,
{
source: "/:path*",
headers: [
Expand Down
41 changes: 27 additions & 14 deletions next.config.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import nextConfig from "./next.config.js";

const STATIC_ASSET_RULE = {
source: "/:dir(img|logo)/:path*",
headers: [
{
key: "Cache-Control",
value: "public, max-age=3600, stale-while-revalidate=604800",
},
],
};

const NOINDEX_RULE = {
source: "/:path*",
headers: [{ key: "X-Robots-Tag", value: "noindex, nofollow" }],
};

describe("next.config headers()", () => {
const originalStage = process.env.STAGE;

Expand All @@ -14,28 +29,26 @@ describe("next.config headers()", () => {
test("non-prod stage emits noindex header on all paths", async () => {
process.env.STAGE = "dev";
const result = await nextConfig.headers!();
expect(result).toEqual([
{
source: "/:path*",
headers: [{ key: "X-Robots-Tag", value: "noindex, nofollow" }],
},
]);
expect(result).toEqual([STATIC_ASSET_RULE, NOINDEX_RULE]);
});

test("prod stage emits no header overrides", async () => {
test("prod stage emits no noindex override", async () => {
process.env.STAGE = "prod";
const result = await nextConfig.headers!();
expect(result).toEqual([]);
expect(result).toEqual([STATIC_ASSET_RULE]);
});

test("missing STAGE defaults to noindex", async () => {
delete process.env.STAGE;
const result = await nextConfig.headers!();
expect(result).toEqual([
{
source: "/:path*",
headers: [{ key: "X-Robots-Tag", value: "noindex, nofollow" }],
},
]);
expect(result).toEqual([STATIC_ASSET_RULE, NOINDEX_RULE]);
});

test("static assets stay cacheable in every stage", async () => {
for (const stage of ["prod", "dev"]) {
process.env.STAGE = stage;
const result = await nextConfig.headers!();
expect(result).toContainEqual(STATIC_ASSET_RULE);
}
});
});
Loading