-
Notifications
You must be signed in to change notification settings - Fork 2
fix: hand Next.js the mount-relative request path #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
kriszyp
wants to merge
5
commits into
main
Choose a base branch
from
fix/mount-relative-request-path
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+133
−4
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4ff6c3d
fix: hand Next.js the mount-relative request path
257c685
docs: record the harper adapter dependency in AGENTS.md
b00da7f
fix: keep the direct hand-off for unmounted Next.js apps
3d7b13c
fix: fall back to the direct hand-off when Harper has no Node adapter
50ab54b
fix: keep query strings out of the missing-adapter warning
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| package-lock=false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export default function Page() { | ||
| return <h1>Mounted About</h1>; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export const dynamic = 'force-dynamic'; | ||
|
|
||
| export async function GET(request) { | ||
| const url = new URL(request.url); | ||
| return Response.json({ pathname: url.pathname, search: url.search }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| export const metadata = { | ||
| title: 'Harper - Mounted Next.js App', | ||
| }; | ||
|
|
||
| export default function RootLayout({ children }) { | ||
| return ( | ||
| <html> | ||
| <body>{children}</body> | ||
| </html> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export default function Page() { | ||
| return <h1>Mounted Home</h1>; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| '@harperfast/nextjs': | ||
| package: '@harperfast/nextjs' | ||
| urlPath: /mounted |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import { withHarper } from '@harperfast/nextjs'; | ||
|
|
||
| export default withHarper({}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "name": "next-16-mounted", | ||
| "private": true, | ||
| "scripts": { | ||
| "dev": "next dev", | ||
| "build": "next build", | ||
| "start": "next start", | ||
| "lint": "next lint" | ||
| }, | ||
| "dependencies": { | ||
| "@harperfast/nextjs": "file:../../", | ||
| "react": "^19", | ||
| "react-dom": "^19", | ||
| "next": "^16" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import { fixture } from './fixture.ts'; | ||
|
|
||
| const { test, expect } = fixture('next-16-mounted'); | ||
|
|
||
| // Un-skip once harper's `Request.withNodeAdapter()` can serve Next.js — today an adapted request 500s | ||
| // on `headers.hasOwnProperty` and a missing `appendHeader`/`_implicitHeader`, and any response over | ||
| // the adapter's 16 KB buffer stalls. Skipped rather than left red because with CI disabled a green | ||
| // local run is this repo's only regression signal. See HarperFast/nextjs#61. | ||
| test.describe.fixme('served under a urlPath mount', () => { | ||
| test('mount root reaches the Next.js home page', async ({ request, harper }) => { | ||
| const response = await request.get(`${harper.httpURL}/mounted`); | ||
| expect(response.status()).toBe(200); | ||
| expect(await response.text()).toContain('Mounted Home'); | ||
| }); | ||
|
|
||
| test('a nested page under the mount reaches its Next.js route', async ({ request, harper }) => { | ||
| const response = await request.get(`${harper.httpURL}/mounted/about`); | ||
| expect(response.status()).toBe(200); | ||
| expect(await response.text()).toContain('Mounted About'); | ||
| }); | ||
|
|
||
| test('Next.js sees the mount-relative path, not the requested one', async ({ request, harper }) => { | ||
| const response = await request.get(`${harper.httpURL}/mounted/api/echo`); | ||
| expect(response.status()).toBe(200); | ||
| expect(await response.json()).toEqual({ pathname: '/api/echo', search: '' }); | ||
| }); | ||
|
|
||
| test('the query string survives mount stripping', async ({ request, harper }) => { | ||
| const response = await request.get(`${harper.httpURL}/mounted/api/echo?q=1`); | ||
| expect(response.status()).toBe(200); | ||
| expect(await response.json()).toEqual({ pathname: '/api/echo', search: '?q=1' }); | ||
| }); | ||
|
|
||
| // Asserts on the server-rendered markup only: Next.js still emits its `/_next/*` asset URLs at the | ||
| // root, outside the mount, until the app is built with a matching `basePath`. | ||
| test('the mount root renders in a browser', async ({ page, harper }) => { | ||
| await page.goto(`${harper.httpURL}/mounted`); | ||
| await expect(page.locator('h1')).toHaveText('Mounted Home'); | ||
| }); | ||
| }); | ||
|
|
||
| // Outside the fixme block: nothing rewrites this URL, so it never reaches the adapter. | ||
| test('paths outside the mount are not served by Next.js', async ({ request, harper }) => { | ||
| const response = await request.get(`${harper.httpURL}/about`); | ||
| expect(response.status()).toBe(404); | ||
| expect(await response.text()).not.toContain('Mounted About'); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the Next.js response has no body (for example, with
204 No Content,304 Not Modified, orHEADrequests),response.bodywill benullorundefined. Callingresponse.body.on('error', ...)directly will throw aTypeError: Cannot read properties of null (reading 'on')immediately when the promise resolves, causing these requests to fail with a 500 error.Using optional chaining (
response.body?.on) prevents this crash for empty responses.