From 013a58d58eb02d01acbd2d3cab81bdcfadbc9ade Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Thu, 8 Dec 2022 20:00:52 +0100 Subject: [PATCH] Use proxy to ensure Flight is referencing to the latest module during development (#43823) As @timneutkens pointed out [here](https://github.com/vercel/next.js/pull/43819#discussion_r1042408158), changing the key will make Flight's module cache grow indefinitely. While I've thought about updating Flight's logic to clean the cache at some point, but that's tricky to do correctly as everything is asynchronous and we have to trigger clean up from outside (Webpack). So currently, a better way I can think of is to just give Flight a proxied object as `moduleExports`. Even if Flight is getting the same object from cache, it will always require the latest module from Webpack. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] [e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md) --- packages/next/client/app-index.tsx | 21 +++++++++++++++++---- packages/next/server/app-render.tsx | 26 +------------------------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/packages/next/client/app-index.tsx b/packages/next/client/app-index.tsx index 597258c195bd5b3..f9dc21c51b5b493 100644 --- a/packages/next/client/app-index.tsx +++ b/packages/next/client/app-index.tsx @@ -30,10 +30,23 @@ __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__ = (id: string) => { - const modId = id.replace(/\?.+$/, '') - return __webpack_require__(modId) -} +self.__next_require__ = + process.env.NODE_ENV !== 'production' + ? (id: string) => { + const mod = __webpack_require__(id) + if (typeof mod === 'object') { + // Return a proxy to flight client to make sure it's always getting + // the latest module, instead of being cached. + return new Proxy(mod, { + get(_target, prop) { + return __webpack_require__(id)[prop] + }, + }) + } + + return mod + } + : __webpack_require__ // 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 c126356e50219c0..472103a98c97497 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -1601,35 +1601,11 @@ 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 (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]) { - 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, - serverComponentManifestWithHMR, + serverComponentManifest, { context: serverContexts, onError: flightDataRendererErrorHandler,