mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
2e4f08ca0a
### What? Two fixes for the Turbopack build tracing introduced in #90397: 1. **Don't block SSG on Turbopack shutdown**: `workerMain()` no longer awaits the shutdown promise before returning. Trace event collection is deferred to `waitForShutdown()`, which the parent process awaits *after* SSG completes. This allows static generation and Turbopack persistence/cache-flush to run in parallel. 2. **Add persistence spans to `trace-build` allowlist**: `turbopack-build-events`, `turbopack-persistence`, and `turbopack-compaction` are now included in the `to-json-build.ts` allowlist so they appear in `.next/trace-build`. ### Why? - The `await shutdownPromise` in `workerMain()` was too eager — it prevented the caller from acknowledging the build as complete and starting SSG until Turbopack persistence finished flushing to disk. - The persistence/compaction spans emitted by Rust (`turbopack-persistence`, `turbopack-compaction`) were not in the `to-json-build.ts` allowlist, so they were silently filtered out of `.next/trace-build`. ### How? **`impl.ts` (worker)**: - Removed `await shutdownPromise` from `workerMain()` — it now returns build results immediately - `waitForShutdown()` now returns `{ debugTraceEvents }` after awaiting shutdown, so trace events are collected only after all compilation events (including persistence spans) have been processed **`index.ts` (parent)**: - Moved `recordTraceEvents(debugTraceEvents)` from the `workerMain` result handler into the `shutdownPromise` `.then()` chain, so events are replayed into the parent reporter after shutdown completes **`to-json-build.ts`**: - Added `turbopack-build-events`, `turbopack-persistence`, `turbopack-compaction` to the allowlist **Test updates**: - Enabled `turbopackFileSystemCacheForBuild: true` in the trace-build test fixture - Updated the Turbopack inline snapshot to include `turbopack-build-events`
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
import { readFileSync } from 'fs'
|
|
import type { TraceEvent } from 'next/dist/trace'
|
|
|
|
export interface TraceStructure {
|
|
events: TraceEvent[]
|
|
eventsByName: Map<string, TraceEvent[]>
|
|
eventsById: Map<string, TraceEvent>
|
|
rootEvents: TraceEvent[]
|
|
orphanedEvents: TraceEvent[]
|
|
}
|
|
|
|
/**
|
|
* Parses a Next.js trace file (e.g. `.next/trace` or `.next/trace-build`)
|
|
* and returns the flat list of trace events.
|
|
*/
|
|
export function parseTraceEvents(tracePath: string): TraceEvent[] {
|
|
const traceContent = readFileSync(tracePath, 'utf8')
|
|
const allEvents: TraceEvent[] = []
|
|
for (const line of traceContent.trim().split('\n')) {
|
|
if (!line.trim()) continue
|
|
allEvents.push(...(JSON.parse(line) as TraceEvent[]))
|
|
}
|
|
return allEvents
|
|
}
|
|
|
|
/**
|
|
* Parses a Next.js trace file and returns a structured representation
|
|
* with events indexed by name and id, plus root/orphaned classification.
|
|
*/
|
|
export function parseTraceFile(tracePath: string): TraceStructure {
|
|
const allEvents = parseTraceEvents(tracePath)
|
|
|
|
const eventsByName = new Map<string, TraceEvent[]>()
|
|
const eventsById = new Map<string, TraceEvent>()
|
|
const rootEvents: TraceEvent[] = []
|
|
const orphanedEvents: TraceEvent[] = []
|
|
|
|
for (const event of allEvents) {
|
|
const byName = eventsByName.get(event.name)
|
|
if (byName) {
|
|
byName.push(event)
|
|
} else {
|
|
eventsByName.set(event.name, [event])
|
|
}
|
|
eventsById.set(event.id.toString(), event)
|
|
}
|
|
|
|
for (const event of allEvents) {
|
|
if (!event.parentId) {
|
|
rootEvents.push(event)
|
|
} else if (!eventsById.has(event.parentId.toString())) {
|
|
orphanedEvents.push(event)
|
|
}
|
|
}
|
|
|
|
return {
|
|
events: allEvents,
|
|
eventsByName,
|
|
eventsById,
|
|
rootEvents,
|
|
orphanedEvents,
|
|
}
|
|
}
|