(perf) : defer secondary startup payloads#4345
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR defers all secondary dashboard startup work — Umami analytics, Vercel Analytics, Google Fonts, Sentry preconnect, and Clerk dns-prefetch — until after first paint and browser idle, so a slow or unreachable third-party origin cannot contend with the initial dashboard shell load. A bounded 50-item queue buffers
Confidence Score: 4/5Safe to merge; the deferred-load architecture is sound and the existing analytics path is preserved through the pre-load queue. The deferred scheduling and font narrowing logic are well-tested at the unit level. Two gaps remain: the E2E spec installs __wmRunDeferredIdle but never invokes it, so no test confirms deferred requests actually fire after idle; and the Umami script error handler resets umamiLoadStarted without any wired retry path, leaving queued events stranded on a script load failure. e2e/secondary-startup.spec.ts (missing after-idle assertion) and src/services/analytics.ts (orphaned umamiLoadStarted reset in the error handler) Important Files Changed
Reviews (1): Last reviewed commit: "perf(dashboard): defer secondary startup..." | Re-trigger Greptile |
| page.on('request', (request) => { | ||
| const url = request.url(); | ||
| if (SECONDARY_STARTUP_REQUEST.test(url)) secondaryRequests.push(url); | ||
| }); | ||
|
|
||
| await page.goto('/'); | ||
| await page.locator('.auth-signin-btn, .panel').first().waitFor({ timeout: 20000 }); | ||
| await page.waitForTimeout(250); | ||
|
|
||
| expect(secondaryRequests).toEqual([]); | ||
| }); |
There was a problem hiding this comment.
__wmRunDeferredIdle is set up but never called — test only verifies half the contract
The init script installs __wmRunDeferredIdle as a manual trigger for queued idle callbacks, but no test case ever calls page.evaluate(() => window.__wmRunDeferredIdle()). The single test verifies that secondary requests are not made before idle runs, but there is no corresponding assertion that the analytics, fonts, Clerk, and YouTube requests are made once idle fires. A regression that silently dropped the deferred loader (e.g. an uncaught promise rejection in scheduleAfterFirstPaint) would leave this test green while the feature stops working entirely.
| script.addEventListener('error', () => { | ||
| umamiLoadStarted = false; | ||
| }, { once: true }); | ||
| document.head.appendChild(script); |
There was a problem hiding this comment.
Script error handler resets
umamiLoadStarted but no retry path exists
When the Umami script fails to load, umamiLoadStarted is reset to false — which allows loadUmamiScript() to run again — but nothing will ever call it a second time: umamiLoadScheduled stays true, so initAnalytics() treats the loader as already wired and returns early. The pendingUmamiCalls queue accumulates events that will never be drained until a page reload. The reset of umamiLoadStarted appears to signal a retry path that was not completed.
…alic - sendUmamiCall: return false in the catch so a throwing window.umami defers to the bounded queue/flush path instead of silently dropping the event (callers only queue when sendUmamiCall returns false). - buildDashboardFontStylesheetHref: restore the Nunito italic axis (ital,wght@0,400;0,600;0,700;1,400) the narrowed request dropped; happy-theme.css uses font-style:italic on Nunito-bodied elements, so the weight-only request regressed those to synthesized oblique. Weight narrowing (no 300) preserved. - Update the two font-href assertions that had locked in the regression. Addresses ce-code-review findings on PR #4345. Claude-Session: https://claude.ai/code/session_0187W7sB8cdp8sYK7J7qDNLn
…up tests Code-review follow-ups for #4345: - scripts/package.json: re-add overrides.undici "$undici" to match main (post-#4350). scripts/ is now byte-identical to main, clearing the husky pre-push lockfile-sync gate and re-pinning transitive undici. Lockfile is unchanged (already dedupes to 7.28.0). - analytics.ts: fix the loadUmamiScript existing-script branch (flush only when window.umami is set, else attach the load listener; set umamiLoadStarted to close the re-entry gap); make initAnalytics synchronous (no await, sole caller voids it); add resetAnalyticsForTesting; move the #4183 data-domains note next to UMAMI_DOMAINS as the single source of truth. - index.html: trim the Umami comment to a pointer at the new source of truth. - tests: add coverage for scheduleAfterFirstPaint load-listener + rIC-absent fallback branches, Umami retry-exhaustion, 50-cap queue overflow, throw-then-queue-then-flush, and the existing-script branch. - e2e: replace the flaky 250ms wait with the deterministic wmEventHandlersReady readiness gate. Claude-Session: https://claude.ai/code/session_015dspobi7rUanvd9zSamz8a
Summary
Fixes #4339
Validation
./node_modules/.bin/tsx --test tests/secondary-startup.test.mts tests/signup-analytics-gate.test.mts tests/brief-thread-open-telemetry.test.mjs tests/sentry-defer-replay.test.mts tests/csp-filter.test.mjs tests/premium-fetch.test.mts tests/wm-session-interceptor-target.test.mts(147 tests)npm run typechecknpx playwright test e2e/secondary-startup.spec.tsnode .github/scripts/audit-production-dependencies.mjs --workspace "scripts" --package-json "scripts/package.json" --lockfile "scripts/package-lock.json"git diff --checkgit push(typecheck/API typecheck/bundles/edge/markdown/MDX/proto/version sync)Follow-up Notes
ac545f72a.