Skip to content

Commit

Permalink
Fix tags cache (#317)
Browse files Browse the repository at this point in the history
* fix: fetchCache for next 14+

* fix: regression from #295, tags were not generated

* test: add test for revalidateTag

* pin next version

* add changeset
  • Loading branch information
conico974 committed Nov 28, 2023
1 parent e0cf328 commit abeb9cd
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 53 deletions.
5 changes: 5 additions & 0 deletions .changeset/poor-ravens-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"open-next": patch
---

Setting the right tag values for fetch cache (#304); Fix getHeader crash external rewrites (#321); Added --package-json option to specify package json path (#322); Change querystring format for multi value parameters (#320);Fix tags cache (#317);Fix skip trailing slash redirect (#323)
6 changes: 3 additions & 3 deletions examples/app-pages-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"build": "next build",
"start": "next start --port 3003",
"lint": "next lint",
"clean": "rm -rf .turbo node_modules .next .open-next"
"clean": "rm -rf .turbo node_modules .next .open-next"
},
"dependencies": {
"open-next": "workspace:*",
"@example/shared": "workspace:*",
"@open-next/utils": "workspace:*",
"next": "latest",
"next": "^14.0.3",
"open-next": "workspace:*",
"react": "latest",
"react-dom": "latest"
},
Expand Down
7 changes: 7 additions & 0 deletions examples/app-router/app/api/revalidate-tag/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { revalidateTag } from "next/cache";

export async function GET() {
revalidateTag("revalidate");

return new Response("ok");
}
19 changes: 19 additions & 0 deletions examples/app-router/app/revalidate-tag/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { unstable_cache } from "next/cache";
import type { ReactNode } from "react";

export default async function Layout({ children }: { children: ReactNode }) {
const fakeFetch = unstable_cache(
async () => new Date().getTime(),
["fakeFetch"],
{
tags: ["revalidate"],
},
);
const fetchedDate = await fakeFetch();
return (
<div>
<div>Fetched time: {new Date(fetchedDate).toISOString()}</div>
{children}
</div>
);
}
3 changes: 3 additions & 0 deletions examples/app-router/app/revalidate-tag/nested/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default async function Nested() {
return <div>Nested</div>;
}
8 changes: 8 additions & 0 deletions examples/app-router/app/revalidate-tag/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
async function getTime() {
return new Date().toISOString();
}

export default async function ISR() {
const time = getTime();
return <div>Time: {time}</div>;
}
8 changes: 8 additions & 0 deletions examples/app-router/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ export function middleware(request: NextRequest) {
);
}

// It is so that cloudfront doesn't cache the response
if (path.startsWith("/revalidate-tag")) {
responseHeaders.set(
"cache-control",
"private, no-cache, no-store, max-age=0, must-revalidate",
);
}

const r = NextResponse.next({
headers: responseHeaders,
request: {
Expand Down
6 changes: 3 additions & 3 deletions examples/app-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"build": "next build",
"start": "next start --port 3001",
"lint": "next lint",
"clean": "rm -rf .turbo node_modules .next .open-next"
"clean": "rm -rf .turbo node_modules .next .open-next"
},
"dependencies": {
"open-next": "workspace:*",
"@example/shared": "workspace:*",
"@open-next/utils": "workspace:*",
"next": "latest",
"next": "^14.0.3",
"open-next": "workspace:*",
"react": "latest",
"react-dom": "latest"
},
Expand Down
4 changes: 2 additions & 2 deletions examples/pages-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
"build": "next build",
"start": "next start --port 3002",
"lint": "next lint",
"clean": "rm -rf .turbo node_modules .next .open-next"
"clean": "rm -rf .turbo node_modules .next .open-next"
},
"dependencies": {
"@example/shared": "workspace:*",
"@types/node": "20.5.0",
"@types/react": "18.2.20",
"@types/react-dom": "18.2.7",
"autoprefixer": "10.4.15",
"next": "latest",
"next": "^14.0.3",
"postcss": "8.4.27",
"react": "latest",
"react-dom": "latest",
Expand Down
14 changes: 12 additions & 2 deletions packages/open-next/src/adapters/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,22 @@ export default class S3Cache {
this.buildId = NEXT_BUILD_ID!;
}

public async get(key: string, options?: boolean | { fetchCache?: boolean }) {
public async get(
key: string,
// fetchCache is for next 13.5 and above, kindHint is for next 14 and above and boolean is for earlier versions
options?:
| boolean
| { fetchCache?: boolean; kindHint?: "app" | "pages" | "fetch" },
) {
if (globalThis.disableIncrementalCache) {
return null;
}
const isFetchCache =
typeof options === "object" ? options.fetchCache : options;
typeof options === "object"
? options.kindHint
? options.kindHint === "fetch"
: options.fetchCache
: options;
return isFetchCache
? this.getFetchCache(key)
: this.getIncrementalCache(key);
Expand Down
5 changes: 3 additions & 2 deletions packages/open-next/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,8 +509,6 @@ function createCacheAssets(monorepoRoot: string, disableDynamoDBCache = false) {
fs.writeFileSync(cacheFilePath, JSON.stringify(cacheFileContent));
});

removeFiles(outputPath, (file) => !file.endsWith(".cache"));

if (!disableDynamoDBCache) {
// Generate dynamodb data
// We need to traverse the cache to find every .meta file
Expand Down Expand Up @@ -597,6 +595,9 @@ function createCacheAssets(monorepoRoot: string, disableDynamoDBCache = false) {
);
}
}

// We need to remove files later because we need the metafiles for dynamodb tags cache
removeFiles(outputPath, (file) => !file.endsWith(".cache"));
}

/***************************/
Expand Down
56 changes: 56 additions & 0 deletions packages/tests-e2e/tests/appRouter/revalidateTag.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { expect, test } from "@playwright/test";

test("Revalidate tag", async ({ page, request }) => {
test.setTimeout(45000);
let responsePromise = page.waitForResponse((response) => {
return response.status() === 200;
});
await page.goto("/revalidate-tag");
let elLayout = page.getByText("Fetched time:");
let time = await elLayout.textContent();
let newTime;

let response = await responsePromise;
const nextCacheHeader = response.headers()["x-nextjs-cache"];
expect(nextCacheHeader).toMatch(/^(HIT|STALE)$/);

// Send revalidate tag request

const result = await request.get("/api/revalidate-tag");
expect(result.status()).toEqual(200);
const text = await result.text();
expect(text).toEqual("ok");

responsePromise = page.waitForResponse((response) => {
return response.status() === 200;
});
await page.reload();
elLayout = page.getByText("Fetched time:");
newTime = await elLayout.textContent();

expect(newTime).not.toEqual(time);

response = await responsePromise;
expect(response.headers()["x-nextjs-cache"]).toEqual("MISS");

//Check if nested page is also a miss
responsePromise = page.waitForResponse((response) => {
return response.status() === 200;
});
await page.goto("/revalidate-tag/nested");
elLayout = page.getByText("Fetched time:");
newTime = await elLayout.textContent();
expect(newTime).not.toEqual(time);

response = await responsePromise;
expect(response.headers()["x-nextjs-cache"]).toEqual("MISS");

// If we hit the page again, it should be a hit
responsePromise = page.waitForResponse((response) => {
return response.status() === 200;
});
await page.goto("/revalidate-tag/nested");

response = await responsePromise;
expect(response.headers()["x-nextjs-cache"]).toEqual("HIT");
});

1 comment on commit abeb9cd

@vercel
Copy link

@vercel vercel bot commented on abeb9cd Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

open-next – ./

open-next-git-main-sst-dev.vercel.app
open-next.vercel.app
open-next-sst-dev.vercel.app

Please sign in to comment.