Skip to content

Commit 653c20c

Browse files
committed
Ensure "[Fast Refresh] rebuilding" logs have a matching "[Fast Refresh] done" log
1 parent eeff555 commit 653c20c

File tree

2 files changed

+81
-51
lines changed

2 files changed

+81
-51
lines changed

packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ function onFastRefresh(
5959
updatedModules: ReadonlyArray<string>
6060
) {
6161
dispatcher.onBuildOk()
62-
6362
reportHmrLatency(sendMessage, updatedModules)
6463

6564
dispatcher.onRefresh()
@@ -161,6 +160,7 @@ function tryApplyUpdates(
161160
) {
162161
if (!isUpdateAvailable() || !canApplyUpdates()) {
163162
dispatcher.onBuildOk()
163+
reportHmrLatency(sendMessage, [])
164164
return
165165
}
166166

@@ -430,7 +430,6 @@ function processMessage(
430430
router.hmrRefresh()
431431
dispatcher.onRefresh()
432432
})
433-
reportHmrLatency(sendMessage, [])
434433

435434
if (process.env.__NEXT_TEST_MODE) {
436435
if (self.__NEXT_HMR_CB) {

test/development/app-hmr/hmr.test.ts

Lines changed: 80 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { retry, waitFor } from 'next-test-utils'
33

44
const envFile = '.env.development.local'
55

6-
const isPPREnabledByDefault = process.env.__NEXT_EXPERIMENTAL_PPR === 'true'
7-
86
describe(`app-dir-hmr`, () => {
97
const { next } = nextTestSetup({
108
files: __dirname,
@@ -73,58 +71,67 @@ describe(`app-dir-hmr`, () => {
7371
const fastRefreshLogs = logs.filter((log) => {
7472
return log.message.startsWith('[Fast Refresh]')
7573
})
76-
// FIXME: 3+ "rebuilding" but single "done" is confusing.
74+
// FIXME: 3+ "rebuilding" but no "done" is confusing.
7775
// There may actually be more "rebuilding" but not reliably.
7876
// To ignore this flakiness, we just assert on subset matches.
7977
// Once the bug is fixed, each "rebuilding" should be paired with a "done in" exactly.
8078
expect(fastRefreshLogs).toEqual(
8179
expect.arrayContaining([
8280
{ source: 'log', message: '[Fast Refresh] rebuilding' },
8381
{ source: 'log', message: '[Fast Refresh] rebuilding' },
84-
{
85-
source: 'log',
86-
message: expect.stringContaining('[Fast Refresh] done in '),
87-
},
8882
{ source: 'log', message: '[Fast Refresh] rebuilding' },
8983
])
9084
)
85+
// FIXME: Turbopack should have matching "done in" for each "rebuilding"
86+
expect(logs).not.toEqual(
87+
expect.arrayContaining([
88+
expect.objectContaining({
89+
message: expect.stringContaining('[Fast Refresh] done in'),
90+
source: 'log',
91+
}),
92+
])
93+
)
9194
})
9295
} else {
9396
await retry(
9497
async () => {
95-
const fastRefreshLogs = logs.filter((log) => {
96-
return log.message.startsWith('[Fast Refresh]')
98+
const envValue = await browser.elementByCss('p').text()
99+
const mpa = await browser.eval(
100+
'window.__TEST_NO_RELOAD === undefined'
101+
)
102+
// Used to be flaky but presumably no longer is.
103+
// If this flakes again, please add the received value as a commnet.
104+
expect({ envValue, mpa }).toEqual({
105+
envValue: 'ipad',
106+
mpa: false,
97107
})
98-
// FIXME: Should be either a single "rebuilding"+"done" or the last "rebuilding" should be followed by "done"
99-
expect(fastRefreshLogs).toEqual([
100-
{ source: 'log', message: '[Fast Refresh] rebuilding' },
101-
{ source: 'log', message: '[Fast Refresh] rebuilding' },
102-
{
103-
source: 'log',
104-
message: expect.stringContaining('[Fast Refresh] done in '),
105-
},
106-
{ source: 'log', message: '[Fast Refresh] rebuilding' },
107-
])
108108
},
109109
// Very slow Hot Update for some reason.
110110
// May be related to receiving 3 rebuild events but only one finish event
111111
5000
112112
)
113+
114+
const fastRefreshLogs = logs.filter((log) => {
115+
return log.message.startsWith('[Fast Refresh]')
116+
})
117+
expect(fastRefreshLogs).toEqual([
118+
{ source: 'log', message: '[Fast Refresh] rebuilding' },
119+
{
120+
source: 'log',
121+
message: expect.stringContaining('[Fast Refresh] done in '),
122+
},
123+
{ source: 'log', message: '[Fast Refresh] rebuilding' },
124+
{ source: 'log', message: '[Fast Refresh] rebuilding' },
125+
{
126+
source: 'log',
127+
message: expect.stringContaining('[Fast Refresh] done in '),
128+
},
129+
{
130+
source: 'log',
131+
message: expect.stringContaining('[Fast Refresh] done in '),
132+
},
133+
])
113134
}
114-
const envValue = await browser.elementByCss('p').text()
115-
const mpa = await browser.eval('window.__TEST_NO_RELOAD === undefined')
116-
// Flaky sometimes in Webpack:
117-
// A. misses update and just receives `{ envValue: 'mac', mpa: false }`
118-
// B. triggers error on server resulting in MPA: `{ envValue: 'ipad', mpa: true }` and server logs: ⨯ [TypeError: Cannot read properties of undefined (reading 'polyfillFiles')] ⨯ [TypeError: Cannot read properties of null (reading 'default')]
119-
// A is more common than B.
120-
expect({ envValue, mpa }).toEqual({
121-
envValue:
122-
isPPREnabledByDefault && !process.env.TURBOPACK
123-
? // FIXME: Should be 'ipad' but PPR+Webpack swallows the update reliably
124-
'mac'
125-
: 'ipad',
126-
mpa: false,
127-
})
128135
} finally {
129136
await next.patchFile(envFile, envContent)
130137
}
@@ -158,14 +165,26 @@ describe(`app-dir-hmr`, () => {
158165
expect(await browser.elementByCss('p').text()).toBe('ipad')
159166
})
160167

161-
expect(logs).toEqual(
162-
expect.arrayContaining([
163-
expect.objectContaining({
164-
message: expect.stringContaining('[Fast Refresh] done in'),
165-
source: 'log',
166-
}),
167-
])
168-
)
168+
if (process.env.TURBOPACK) {
169+
// FIXME: Turbopack should have matching "done in" for each "rebuilding"
170+
expect(logs).not.toEqual(
171+
expect.arrayContaining([
172+
expect.objectContaining({
173+
message: expect.stringContaining('[Fast Refresh] done in'),
174+
source: 'log',
175+
}),
176+
])
177+
)
178+
} else {
179+
expect(logs).toEqual(
180+
expect.arrayContaining([
181+
expect.objectContaining({
182+
message: expect.stringContaining('[Fast Refresh] done in'),
183+
source: 'log',
184+
}),
185+
])
186+
)
187+
}
169188
} finally {
170189
await next.patchFile(envFile, envContent)
171190
}
@@ -198,14 +217,26 @@ describe(`app-dir-hmr`, () => {
198217
expect(await browser.elementByCss('p').text()).toBe('ipad')
199218
})
200219

201-
expect(logs).toEqual(
202-
expect.arrayContaining([
203-
expect.objectContaining({
204-
message: expect.stringContaining('[Fast Refresh] done in'),
205-
source: 'log',
206-
}),
207-
])
208-
)
220+
if (process.env.TURBOPACK) {
221+
// FIXME: Turbopack should have matching "done in" for each "rebuilding"
222+
expect(logs).not.toEqual(
223+
expect.arrayContaining([
224+
expect.objectContaining({
225+
message: expect.stringContaining('[Fast Refresh] done in'),
226+
source: 'log',
227+
}),
228+
])
229+
)
230+
} else {
231+
expect(logs).toEqual(
232+
expect.arrayContaining([
233+
expect.objectContaining({
234+
message: expect.stringContaining('[Fast Refresh] done in'),
235+
source: 'log',
236+
}),
237+
])
238+
)
239+
}
209240
} finally {
210241
await next.patchFile(envFile, envContent)
211242
}

0 commit comments

Comments
 (0)