Commit 4eb8364
Fix initial page startup race for late-loading client bundles (#3151)
### Summary
Fixes a client lifecycle gap where React on Rails can miss the initial
page startup if the bundle begins executing after `DOMContentLoaded` has
already fired but before the document reaches `complete`.
Fixes #3150
### Problem
Core startup currently initializes immediately only when
`document.readyState === "complete"`, and otherwise waits for
`DOMContentLoaded`.
That avoids starting too early during `interactive`, when deferred or
module scripts may still be registering components.
But there is another browser timing window:
- the bundle starts while `document.readyState === "interactive"`
- `DOMContentLoaded` has already fired
- the document is not yet `"complete"`
In that case, the `DOMContentLoaded` listener is attached too late, so
the initial page-load callbacks never run.
### What changed
Adds a `readystatechange → complete` fallback listener when registration
happens during `interactive`. Both listeners share a single handler that
removes both on first fire, so initialization runs exactly once in real
browsers.
### Test plan
- Added regression coverage for the
missed-DOMContentLoaded-during-interactive scenario. Verified by
temporarily reverting the fix and running the new tests against main's
`pageLifecycle.ts` — exactly the new tests failed.
- Verified initial startup now runs when the client bundle begins during
`interactive` after `DOMContentLoaded` has already fired.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent ad45e4a commit 4eb8364
3 files changed
Lines changed: 47 additions & 27 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
80 | 82 | | |
81 | 83 | | |
82 | 84 | | |
83 | | - | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
84 | 97 | | |
85 | 98 | | |
86 | 99 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
34 | 37 | | |
35 | 38 | | |
36 | 39 | | |
| |||
81 | 84 | | |
82 | 85 | | |
83 | 86 | | |
84 | | - | |
| 87 | + | |
85 | 88 | | |
86 | 89 | | |
87 | 90 | | |
| |||
92 | 95 | | |
93 | 96 | | |
94 | 97 | | |
| 98 | + | |
95 | 99 | | |
96 | 100 | | |
97 | 101 | | |
| |||
272 | 276 | | |
273 | 277 | | |
274 | 278 | | |
275 | | - | |
276 | | - | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
277 | 283 | | |
278 | 284 | | |
279 | 285 | | |
| |||
285 | 291 | | |
286 | 292 | | |
287 | 293 | | |
288 | | - | |
289 | | - | |
290 | | - | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
291 | 297 | | |
292 | 298 | | |
293 | 299 | | |
| |||
324 | 330 | | |
325 | 331 | | |
326 | 332 | | |
327 | | - | |
| 333 | + | |
328 | 334 | | |
329 | 335 | | |
330 | 336 | | |
| |||
339 | 345 | | |
340 | 346 | | |
341 | 347 | | |
342 | | - | |
| 348 | + | |
343 | 349 | | |
344 | 350 | | |
345 | 351 | | |
346 | 352 | | |
347 | | - | |
| 353 | + | |
348 | 354 | | |
349 | 355 | | |
350 | 356 | | |
| |||
356 | 362 | | |
357 | 363 | | |
358 | 364 | | |
| 365 | + | |
359 | 366 | | |
360 | | - | |
361 | | - | |
362 | | - | |
363 | | - | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
364 | 371 | | |
365 | | - | |
366 | 372 | | |
367 | | - | |
| 373 | + | |
368 | 374 | | |
369 | | - | |
| 375 | + | |
370 | 376 | | |
371 | 377 | | |
372 | 378 | | |
| |||
0 commit comments