Skip to content

Commit 01a3f98

Browse files
authored
fix: HMR not works when assetPrefix set to URL (#68622)
1 parent 604e68a commit 01a3f98

File tree

5 files changed

+60
-0
lines changed

5 files changed

+60
-0
lines changed

packages/next/src/server/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,16 @@ export default async function loadConfig(
10691069
}
10701070
}
10711071

1072+
if (
1073+
phase === PHASE_DEVELOPMENT_SERVER &&
1074+
URL.canParse(userConfig.assetPrefix ?? '')
1075+
) {
1076+
curLog.warn(
1077+
`Absolute URL assetPrefix "${userConfig.assetPrefix}" may disrupt development HMR.\n` +
1078+
'See more info here https://nextjs.org/docs/app/api-reference/next-config-js/assetPrefix'
1079+
)
1080+
}
1081+
10721082
if (userConfig.target && userConfig.target !== 'server') {
10731083
throw new Error(
10741084
`The "target" property is no longer supported in ${configFileName}.\n` +

packages/next/src/server/lib/router-server.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,15 @@ export async function initialize(opts: {
668668
// assetPrefix overrides basePath for HMR path
669669
if (assetPrefix) {
670670
hmrPrefix = normalizedAssetPrefix(assetPrefix)
671+
672+
if (URL.canParse(hmrPrefix)) {
673+
// remove trailing slash from pathname
674+
// return empty string if pathname is '/'
675+
// to avoid conflicts with '/_next' below
676+
hmrPrefix = new URL(hmrPrefix).pathname.replace(/\/$/, '')
677+
}
671678
}
679+
672680
const isHMRRequest = req.url.startsWith(
673681
ensureLeadingSlash(`${hmrPrefix}/_next/webpack-hmr`)
674682
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Root({ children }) {
2+
return (
3+
<html>
4+
<body>{children}</body>
5+
</html>
6+
)
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return <p>before edit</p>
3+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { createNext } from 'e2e-utils'
2+
import { findPort, retry } from 'next-test-utils'
3+
4+
describe('app-dir assetPrefix full URL', () => {
5+
let next, forcedPort
6+
beforeAll(async () => {
7+
forcedPort = ((await findPort()) ?? '54321').toString()
8+
9+
next = await createNext({
10+
files: __dirname,
11+
forcedPort,
12+
nextConfig: {
13+
assetPrefix: `http://localhost:${forcedPort}`,
14+
},
15+
})
16+
})
17+
afterAll(() => next.destroy())
18+
19+
it('should not break HMR when asset prefix set to full URL', async () => {
20+
const browser = await next.browser('/')
21+
const text = await browser.elementByCss('p').text()
22+
expect(text).toBe('before edit')
23+
24+
await next.patchFile('app/page.tsx', (content) => {
25+
return content.replace('before', 'after')
26+
})
27+
28+
await retry(async () => {
29+
expect(await browser.elementByCss('p').text()).toContain('after edit')
30+
})
31+
})
32+
})

0 commit comments

Comments
 (0)