next.js/packages/next/src/build/turbopack-build/index.ts
index.ts92 lines2.8 KB
import path from 'path'

import { Worker } from '../../lib/worker'
import { NextBuildContext } from '../build-context'
import { exportTraceState, recordTraceEvents } from '../../trace'

async function turbopackBuildWithWorker(): ReturnType<
  typeof import('./impl').turbopackBuild
> {
  const nextBuildSpan = NextBuildContext.nextBuildSpan!
  try {
    const worker = new Worker(path.join(__dirname, 'impl.js'), {
      exposedMethods: ['workerMain', 'waitForShutdown'],
      enableWorkerThreads: true,
      debuggerPortOffset: -1,
      isolatedMemory: false,
      numWorkers: 1,
      maxRetries: 0,
      forkOptions: {
        env: {
          NEXT_PRIVATE_BUILD_WORKER: '1',
          ...(process.env.NEXT_CPU_PROF
            ? {
                NEXT_CPU_PROF: '1',
                NEXT_CPU_PROF_DIR: process.env.NEXT_CPU_PROF_DIR,
                __NEXT_PRIVATE_CPU_PROFILE: 'build-turbopack',
              }
            : undefined),
        },
      },
    }) as Worker & typeof import('./impl')
    const {
      nextBuildSpan: _nextBuildSpan,
      // Config is not serializable and is loaded in the worker.
      config: _config,
      ...prunedBuildContext
    } = NextBuildContext
    const { buildTraceContext, duration } = await worker.workerMain({
      buildContext: prunedBuildContext,
      traceState: {
        ...exportTraceState(),
        defaultParentSpanId: nextBuildSpan.getId(),
        shouldSaveTraceEvents: true,
      },
    })

    return {
      // destroy worker when Turbopack has shutdown so it's not sticking around using memory
      // We need to wait for shutdown to make sure filesystem cache is flushed
      shutdownPromise: worker.waitForShutdown().then(({ debugTraceEvents }) => {
        if (debugTraceEvents) {
          recordTraceEvents(debugTraceEvents)
        }
        worker.end()
      }),
      buildTraceContext,
      duration,
    }
  } catch (err: any) {
    // When the error is a serialized `Error` object we need to recreate the `Error` instance
    // in order to keep the consistent error reporting behavior.
    if (err.type === 'Error') {
      const error = new Error(err.message)
      if (err.name) {
        error.name = err.name
      }
      if (err.cause) {
        error.cause = err.cause
      }
      error.message = err.message
      error.stack = err.stack
      throw error
    }
    throw err
  }
}

export function turbopackBuild(
  withWorker: boolean
): ReturnType<typeof import('./impl').turbopackBuild> {
  const nextBuildSpan = NextBuildContext.nextBuildSpan!
  return nextBuildSpan.traceChild('run-turbopack').traceAsyncFn(async () => {
    if (withWorker) {
      return await turbopackBuildWithWorker()
    } else {
      const build = (require('./impl') as typeof import('./impl'))
        .turbopackBuild
      return await build()
    }
  })
}
Quest for Codev2.0.0
/
SIGN IN