From f347527abce274137b8be4c95e2f9d80f55582ed Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 7 Dec 2022 16:57:04 +0100 Subject: [PATCH 1/2] fix hmr issue after reloading the module --- packages/next/client/app-index.tsx | 5 ++++- packages/next/server/app-render.tsx | 26 +++++++++++++++++++++++++- test/e2e/app-dir/index.test.ts | 26 +++++++++++++++++++------- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/packages/next/client/app-index.tsx b/packages/next/client/app-index.tsx index b13c09275563237..7cc36bcfd0b4011 100644 --- a/packages/next/client/app-index.tsx +++ b/packages/next/client/app-index.tsx @@ -29,7 +29,10 @@ __webpack_require__.u = (chunkId: any) => { // Ignore the module ID transform in client. // eslint-disable-next-line no-undef // @ts-expect-error TODO: fix type -self.__next_require__ = __webpack_require__ +self.__next_require__ = (id: string) => { + const modId = id.replace(/\?.+$/, '') + return __webpack_require__(modId) +} // eslint-disable-next-line no-undef ;(self as any).__next_chunk_load__ = (chunk: string) => { diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index a625740694b3292..65ce9333e2fd67d 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -1598,11 +1598,35 @@ export async function renderToHTMLOrFlight( ).slice(1), ] + const serverComponentManifestWithHMR = dev + ? new Proxy(serverComponentManifest, { + get: (target, prop) => { + if ( + typeof prop === 'string' && + !prop.startsWith('_') && + target[prop] + ) { + // Attach TS query param to IDs to get rid of flight client's module cache on HMR. + const namedExports: any = {} + const ts = Date.now() + for (let key in target[prop]) { + namedExports[key] = { + ...target[prop][key], + id: `${target[prop][key].id}?ts=${ts}`, + } + } + return namedExports + } + return target[prop] + }, + }) + : serverComponentManifest + // For app dir, use the bundled version of Fizz renderer (renderToReadableStream) // which contains the subset React. const readable = ComponentMod.renderToReadableStream( flightData, - serverComponentManifest, + serverComponentManifestWithHMR, { context: serverContexts, onError: flightDataRendererErrorHandler, diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index 3feabb920119664..649192e05c19fe0 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -441,7 +441,7 @@ describe('app dir', () => { } }) - it.skip('should HMR correctly when changing the component type', async () => { + it('should HMR correctly when changing the component type', async () => { const filePath = 'app/dashboard/page/page.jsx' const origContent = await next.readFile(filePath) @@ -466,13 +466,12 @@ describe('app dir', () => { ) // Change to client component - await new Promise((resolve) => setTimeout(resolve, 1000)) await next.patchFile( filePath, origContent .replace("// 'use client'", "'use client'") .replace( - 'hello dashboard/page in server component!', + 'hello dashboard/page!', 'hello dashboard/page in client component!' ) ) @@ -482,18 +481,31 @@ describe('app dir', () => { ) // Change back to server component + await next.patchFile( + filePath, + origContent.replace( + 'hello dashboard/page!', + 'hello dashboard/page in server component2!' + ) + ) + await check( + () => browser.elementByCss('p').text(), + /in server component2/ + ) + + // Change to client component again await next.patchFile( filePath, origContent - .replace("'use client'", "// 'use client'") + .replace("// 'use client'", "'use client'") .replace( - 'hello dashboard/page in client component!', - 'hello dashboard/page in server component!' + 'hello dashboard/page!', + 'hello dashboard/page in client component2!' ) ) await check( () => browser.elementByCss('p').text(), - /in server component/ + /in client component2/ ) } finally { await next.patchFile(filePath, origContent) From c074bb845999a415da89b2e6ca148b7504156e2e Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 7 Dec 2022 17:13:27 +0100 Subject: [PATCH 2/2] Update packages/next/server/app-render.tsx --- packages/next/server/app-render.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 65ce9333e2fd67d..ab1a260bda4ce19 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -1606,7 +1606,7 @@ export async function renderToHTMLOrFlight( !prop.startsWith('_') && target[prop] ) { - // Attach TS query param to IDs to get rid of flight client's module cache on HMR. + // Attach TS (timestamp) query param to IDs to get rid of flight client's module cache on HMR. const namedExports: any = {} const ts = Date.now() for (let key in target[prop]) {