From 90ebc0eae2807ae976fe0a4d2b6c7608e1f72240 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 22 Aug 2022 22:19:02 -0500 Subject: [PATCH] Fix disposing active entries in dev compilers --- .../server/dev/on-demand-entry-handler.ts | 96 +++++++++++-------- .../test/index.test.ts | 6 +- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/packages/next/server/dev/on-demand-entry-handler.ts b/packages/next/server/dev/on-demand-entry-handler.ts index 00561904706e5be..09570760812f9b9 100644 --- a/packages/next/server/dev/on-demand-entry-handler.ts +++ b/packages/next/server/dev/on-demand-entry-handler.ts @@ -453,65 +453,83 @@ export function onDemandEntryHandler({ tree: FlightRouterState ): { success: true } | { invalid: true } { const pages = getEntrypointsFromTree(tree, true) + let toSend: { invalid: true } | { success: true } = { invalid: true } for (const page of pages) { - const pageKey = `server/${page}` + for (const compilerType of [ + COMPILER_NAMES.client, + COMPILER_NAMES.server, + COMPILER_NAMES.edgeServer, + ]) { + const pageKey = `${compilerType}/${page}` + const entryInfo = entries[pageKey] + + // If there's no entry, it may have been invalidated and needs to be re-built. + if (!entryInfo) { + // if (page !== lastEntry) client pings, but there's no entry for page + continue + } + + // We don't need to maintain active state of anything other than BUILT entries + if (entryInfo.status !== BUILT) continue + + // If there's an entryInfo + if (!lastServerAccessPagesForAppDir.includes(pageKey)) { + lastServerAccessPagesForAppDir.unshift(pageKey) + + // Maintain the buffer max length + // TODO: verify that the current pageKey is not at the end of the array as multiple entrypoints can exist + if (lastServerAccessPagesForAppDir.length > pagesBufferLength) { + lastServerAccessPagesForAppDir.pop() + } + } + entryInfo.lastActiveTime = Date.now() + entryInfo.dispose = false + toSend = { success: true } + } + } + return toSend + } + + function handlePing(pg: string) { + const page = normalizePathSep(pg) + let toSend: { invalid: true } | { success: true } = { invalid: true } + + for (const compilerType of [ + COMPILER_NAMES.client, + COMPILER_NAMES.server, + COMPILER_NAMES.edgeServer, + ]) { + const pageKey = `${compilerType}${page}` const entryInfo = entries[pageKey] // If there's no entry, it may have been invalidated and needs to be re-built. if (!entryInfo) { // if (page !== lastEntry) client pings, but there's no entry for page - return { invalid: true } + if (compilerType === COMPILER_NAMES.client) { + return { invalid: true } + } + continue } + // 404 is an on demand entry but when a new page is added we have to refresh the page + toSend = page === '/_error' ? { invalid: true } : { success: true } + // We don't need to maintain active state of anything other than BUILT entries if (entryInfo.status !== BUILT) continue // If there's an entryInfo - if (!lastServerAccessPagesForAppDir.includes(pageKey)) { - lastServerAccessPagesForAppDir.unshift(pageKey) + if (!lastClientAccessPages.includes(pageKey)) { + lastClientAccessPages.unshift(pageKey) // Maintain the buffer max length - // TODO: verify that the current pageKey is not at the end of the array as multiple entrypoints can exist - if (lastServerAccessPagesForAppDir.length > pagesBufferLength) { - lastServerAccessPagesForAppDir.pop() + if (lastClientAccessPages.length > pagesBufferLength) { + lastClientAccessPages.pop() } } entryInfo.lastActiveTime = Date.now() entryInfo.dispose = false } - - return { success: true } - } - - function handlePing(pg: string) { - const page = normalizePathSep(pg) - const pageKey = `client${page}` - const entryInfo = entries[pageKey] - - // If there's no entry, it may have been invalidated and needs to be re-built. - if (!entryInfo) { - // if (page !== lastEntry) client pings, but there's no entry for page - return { invalid: true } - } - - // 404 is an on demand entry but when a new page is added we have to refresh the page - const toSend = page === '/_error' ? { invalid: true } : { success: true } - - // We don't need to maintain active state of anything other than BUILT entries - if (entryInfo.status !== BUILT) return - - // If there's an entryInfo - if (!lastClientAccessPages.includes(pageKey)) { - lastClientAccessPages.unshift(pageKey) - - // Maintain the buffer max length - if (lastClientAccessPages.length > pagesBufferLength) { - lastClientAccessPages.pop() - } - } - entryInfo.lastActiveTime = Date.now() - entryInfo.dispose = false return toSend } diff --git a/test/development/basic/gssp-ssr-change-reloading/test/index.test.ts b/test/development/basic/gssp-ssr-change-reloading/test/index.test.ts index 8d8cf6d6364319e..072943ed482cdc5 100644 --- a/test/development/basic/gssp-ssr-change-reloading/test/index.test.ts +++ b/test/development/basic/gssp-ssr-change-reloading/test/index.test.ts @@ -3,7 +3,7 @@ import { join } from 'path' import webdriver from 'next-webdriver' import { createNext, FileRef } from 'e2e-utils' -import { check, getRedboxHeader, hasRedbox } from 'next-test-utils' +import { check, getRedboxHeader, hasRedbox, waitFor } from 'next-test-utils' import { NextInstance } from 'test/lib/next-modes/base' const installCheckVisible = (browser) => { @@ -319,6 +319,10 @@ describe('GS(S)P Server-Side Change Reloading', () => { expect(props.count).toBe(1) expect(props.data).toEqual({ hello: 'world' }) + // wait longer than the max inactive age for on-demand entries + // to ensure we aren't incorrectly disposing the active entry + await waitFor(20 * 1000) + const page = 'lib/data.json' const originalContent = await next.readFile(page)