Repository: vercel/next.js
Pull request: trace-build: Add missing spans

## What?

Follow-up to #83949

While testing the changes I ran Turbopack builds and all time was captured, but for webpack there was some missing time related to tracing outputs (Turbopack does the tracing internally). This PR adds the missing spans to trace-build.

Closes PACK-5542

Changed files:
filename: packages/next/src/build/index.ts
patch: @@ -1734,21 +1734,27 @@ export default async function build(
                   }
                 ) as Worker & typeof import('./collect-build-traces')
 
-                buildTracesPromise = buildTraceWorker
-                  .collectBuildTraces({
-                    dir,
-                    config,
-                    distDir,
-                    // Serialize Map as this is sent to the worker.
-                    edgeRuntimeRoutes: collectRoutesUsingEdgeRuntime(new Map()),
-                    staticPages: [],
-                    hasSsrAmpPages: false,
-                    buildTraceContext,
-                    outputFileTracingRoot,
-                  })
-                  .catch((err) => {
-                    console.error(err)
-                    process.exit(1)
+                buildTracesPromise = nextBuildSpan
+                  .traceChild('collect-build-traces')
+                  .traceAsyncFn(() => {
+                    return buildTraceWorker
+                      .collectBuildTraces({
+                        dir,
+                        config,
+                        distDir,
+                        // Serialize Map as this is sent to the worker.
+                        edgeRuntimeRoutes: collectRoutesUsingEdgeRuntime(
+                          new Map()
+                        ),
+                        staticPages: [],
+                        hasSsrAmpPages: false,
+                        buildTraceContext,
+                        outputFileTracingRoot,
+                      })
+                      .catch((err) => {
+                        console.error(err)
+                        process.exit(1)
+                      })
                   })
               }
             })
@@ -2610,20 +2616,24 @@ export default async function build(
       await writeFunctionsConfigManifest(distDir, functionsConfigManifest)
 
       if (!isTurbopack && !isGenerateMode && !buildTracesPromise) {
-        buildTracesPromise = collectBuildTraces({
-          dir,
-          config,
-          distDir,
-          edgeRuntimeRoutes: collectRoutesUsingEdgeRuntime(pageInfos),
-          staticPages: [...staticPages],
-          nextBuildSpan,
-          hasSsrAmpPages,
-          buildTraceContext,
-          outputFileTracingRoot,
-        }).catch((err) => {
-          console.error(err)
-          process.exit(1)
-        })
+        buildTracesPromise = nextBuildSpan
+          .traceChild('collect-build-traces')
+          .traceAsyncFn(() => {
+            return collectBuildTraces({
+              dir,
+              config,
+              distDir,
+              edgeRuntimeRoutes: collectRoutesUsingEdgeRuntime(pageInfos),
+              staticPages: [...staticPages],
+              nextBuildSpan,
+              hasSsrAmpPages,
+              buildTraceContext,
+              outputFileTracingRoot,
+            }).catch((err) => {
+              console.error(err)
+              process.exit(1)
+            })
+          })
       }
 
       if (serverPropsPages.size > 0 || ssgPages.size > 0) {
@@ -4083,43 +4093,52 @@ export default async function build(
           })
       }
 
-      if (config.experimental.adapterPath) {
-        await handleBuildComplete({
-          dir,
-          distDir,
-          config,
-          staticPages,
-          nextVersion: process.env.__NEXT_VERSION as string,
-          tracingRoot: outputFileTracingRoot,
-          hasNodeMiddleware,
-          hasInstrumentationHook,
-          adapterPath: config.experimental.adapterPath,
-          pageKeys: pageKeys.pages,
-          appPageKeys: denormalizedAppPages,
-          routesManifest,
-          prerenderManifest,
-          middlewareManifest,
-          functionsConfigManifest,
-          hasStatic404: useStaticPages404,
-          requiredServerFiles: requiredServerFilesManifest.files,
-        })
+      const adapterPath = config.experimental.adapterPath
+      if (adapterPath) {
+        await nextBuildSpan
+          .traceChild('adapter-handle-build-complete')
+          .traceAsyncFn(async () => {
+            await handleBuildComplete({
+              dir,
+              distDir,
+              config,
+              staticPages,
+              nextVersion: process.env.__NEXT_VERSION as string,
+              tracingRoot: outputFileTracingRoot,
+              hasNodeMiddleware,
+              hasInstrumentationHook,
+              adapterPath,
+              pageKeys: pageKeys.pages,
+              appPageKeys: denormalizedAppPages,
+              routesManifest,
+              prerenderManifest,
+              middlewareManifest,
+              functionsConfigManifest,
+              hasStatic404: useStaticPages404,
+              requiredServerFiles: requiredServerFilesManifest.files,
+            })
+          })
       }
 
       if (config.output === 'standalone') {
-        await writeStandaloneDirectory(
-          nextBuildSpan,
-          distDir,
-          pageKeys,
-          denormalizedAppPages,
-          outputFileTracingRoot,
-          requiredServerFilesManifest,
-          middlewareManifest,
-          hasNodeMiddleware,
-          hasInstrumentationHook,
-          staticPages,
-          loadedEnvFiles,
-          appDir
-        )
+        await nextBuildSpan
+          .traceChild('output-standalone')
+          .traceAsyncFn(async () => {
+            await writeStandaloneDirectory(
+              nextBuildSpan,
+              distDir,
+              pageKeys,
+              denormalizedAppPages,
+              outputFileTracingRoot,
+              requiredServerFilesManifest,
+              middlewareManifest,
+              hasNodeMiddleware,
+              hasInstrumentationHook,
+              staticPages,
+              loadedEnvFiles,
+              appDir
+            )
+          })
       }
 
       if (postBuildSpinner) postBuildSpinner.stopAndPersist()

filename: packages/next/src/trace/report/to-json-build.ts
patch: @@ -81,8 +81,12 @@ const allowlistedEvents = new Set([
   'run-typescript',
   'run-eslint',
   'static-check',
+  'collect-build-traces',
   'static-generation',
   'output-export-full-static-export',
+  'adapter-handle-build-complete',
+  'output-standalone',
+  'telemetry-flush',
 ])
 
 function reportToJsonBuild(event: TraceEvent) {

filename: test/e2e/app-dir/trace-build-file/trace-build-file.test.ts
patch: @@ -119,19 +119,48 @@ describe('trace-build-file', () => {
       const traceBuildPath = join(next.testDir, '.next/trace-build')
       const traceStructure = parseTraceFile(traceBuildPath)
 
-      const allowlistedEvents = new Set([
-        'next-build',
-        'run-turbopack',
-        'run-webpack',
-        'run-typescript',
-        'run-eslint',
-        'static-check',
-        'static-generation',
-        'output-export-full-static-export',
-      ])
+      // const allowlistedEvents = new Set([
+      //   'next-build',
+      //   'run-turbopack',
+      //   'run-webpack',
+      //   'run-typescript',
+      //   'run-eslint',
+      //   'static-check',
+      //   'static-generation',
+      //   'output-export-full-static-export',
+      // ])
+
+      const foundEvents = new Set<string>()
 
       for (const event of traceStructure.events) {
-        expect(allowlistedEvents.has(event.name)).toBe(true)
+        foundEvents.add(event.name)
+      }
+
+      if (process.env.IS_TURBOPACK_TEST) {
+        expect([...foundEvents].sort()).toMatchInlineSnapshot(`
+                [
+                  "next-build",
+                  "run-eslint",
+                  "run-turbopack",
+                  "run-typescript",
+                  "static-check",
+                  "static-generation",
+                  "telemetry-flush",
+                ]
+              `)
+      } else {
+        expect([...foundEvents].sort()).toMatchInlineSnapshot(`
+         [
+           "collect-build-traces",
+           "next-build",
+           "run-eslint",
+           "run-typescript",
+           "run-webpack",
+           "static-check",
+           "static-generation",
+           "telemetry-flush",
+         ]
+        `)
       }
     })