Skip to content

Commit 15f1160

Browse files
authored
Fix pages router context (#607)
* fix pages router context * changeset * review fix
1 parent 0361672 commit 15f1160

File tree

8 files changed

+119
-1
lines changed

8 files changed

+119
-1
lines changed

.changeset/twelve-turtles-trade.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/cloudflare": patch
3+
---
4+
5+
fix page router shared context to use the correct one
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
test.describe("head properly populated", () => {
4+
test("should properly populate the <head>", async ({ page }) => {
5+
await page.goto("/head");
6+
const title = await page.title();
7+
const description = await page.locator('meta[name="description"]').getAttribute("content");
8+
const favicon = await page.locator('link[rel="icon"]').getAttribute("href");
9+
expect(title).toBe("SSR Head");
10+
expect(description).toBe("SSR");
11+
expect(favicon).toBe("/favicon.ico");
12+
});
13+
});

examples/playground14/pages/head.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Head from "next/head";
2+
3+
export function getServerSideProps() {
4+
return {
5+
props: {
6+
time: new Date().toISOString(),
7+
},
8+
};
9+
}
10+
export default function Page({ time }) {
11+
return (
12+
<div>
13+
<Head>
14+
<title>SSR Head</title>
15+
<meta name="description" content="SSR" />
16+
<link rel="icon" href="/favicon.ico" />
17+
</Head>
18+
<div className="flex" data-testid="time">
19+
Time: {time}
20+
</div>
21+
</div>
22+
);
23+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
test.describe("head properly populated", () => {
4+
test("should properly populate the <head>", async ({ page }) => {
5+
await page.goto("/head");
6+
const title = await page.title();
7+
const description = await page.locator('meta[name="description"]').getAttribute("content");
8+
const favicon = await page.locator('link[rel="icon"]').getAttribute("href");
9+
expect(title).toBe("SSR Head");
10+
expect(description).toBe("SSR");
11+
expect(favicon).toBe("/favicon.ico");
12+
});
13+
});

examples/playground15/pages/head.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Head from "next/head";
2+
3+
export function getServerSideProps() {
4+
return {
5+
props: {
6+
time: new Date().toISOString(),
7+
},
8+
};
9+
}
10+
export default function Page({ time }) {
11+
return (
12+
<div>
13+
<Head>
14+
<title>SSR Head</title>
15+
<meta name="description" content="SSR" />
16+
<link rel="icon" href="/favicon.ico" />
17+
</Head>
18+
<div className="flex" data-testid="time">
19+
Time: {time}
20+
</div>
21+
</div>
22+
);
23+
}

examples/playground15/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"name": "next"
1818
}
1919
],
20-
"target": "ES2017"
20+
"target": "ES2017",
21+
"strictNullChecks": true
2122
},
2223
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx", "worker-configuration.d.ts"],
2324
"exclude": ["node_modules", "open-next.config.ts"]

packages/cloudflare/src/cli/build/bundle-server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { inlineFindDir } from "./patches/plugins/find-dir.js";
1717
import { patchInstrumentation } from "./patches/plugins/instrumentation.js";
1818
import { inlineLoadManifest } from "./patches/plugins/load-manifest.js";
1919
import { handleOptionalDependencies } from "./patches/plugins/optional-deps.js";
20+
import { patchPagesRouterContext } from "./patches/plugins/pages-router-context.js";
2021
import { patchDepdDeprecations } from "./patches/plugins/patch-depd-deprecations.js";
2122
import { fixRequire } from "./patches/plugins/require.js";
2223
import { shimRequireHook } from "./patches/plugins/require-hook.js";
@@ -93,6 +94,7 @@ export async function bundleServer(buildOpts: BuildOptions): Promise<void> {
9394
fixRequire(updater),
9495
handleOptionalDependencies(optionalDependencies),
9596
patchInstrumentation(updater, buildOpts),
97+
patchPagesRouterContext(buildOpts),
9698
inlineEvalManifest(updater, buildOpts),
9799
inlineFindDir(updater, buildOpts),
98100
inlineLoadManifest(updater, buildOpts),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* ESBuild plugin to handle pages router context.
3+
*
4+
* We need to change the import path for the pages router context to use the one provided in `pages-runtime.prod.js`
5+
*/
6+
7+
import { BuildOptions, compareSemver } from "@opennextjs/aws/build/helper.js";
8+
import type { OnResolveResult, PluginBuild } from "esbuild";
9+
10+
export function patchPagesRouterContext(buildOpts: BuildOptions) {
11+
const pathRegex = /^.*\/(?<CONTEXT>.*)\.shared-runtime$/;
12+
const isAfter15 = compareSemver(buildOpts.nextVersion, ">=", "15.0.0");
13+
const isAfter153 = compareSemver(buildOpts.nextVersion, ">=", "15.3.0");
14+
const basePath = `next/dist/server/${isAfter15 ? "" : "future/"}route-modules/pages/vendored/contexts/`;
15+
return {
16+
name: "pages-router-context",
17+
setup: (build: PluginBuild) => {
18+
// If we are after 15.3, we don't need to patch the context anymore
19+
if (isAfter153) {
20+
return;
21+
}
22+
// We need to modify some imports (i.e. https://github.com/vercel/next.js/blob/48540b836642525b38a2cba40a92b4532c553a52/packages/next/src/server/require-hook.ts#L59-L68)
23+
build.onResolve(
24+
{ filter: /.*shared-runtime/ },
25+
async ({ path, resolveDir, ...options }): Promise<OnResolveResult | undefined> => {
26+
const match = path.match(pathRegex);
27+
if (match && match.groups?.CONTEXT) {
28+
const newPath = `${basePath}${match.groups.CONTEXT}.js`;
29+
return await build.resolve(newPath, {
30+
resolveDir,
31+
...options,
32+
});
33+
}
34+
}
35+
);
36+
},
37+
};
38+
}

0 commit comments

Comments
 (0)