next.js/packages/next/src/build/print-build-errors.ts
print-build-errors.ts87 lines3.2 KB
import { formatIssue, isRelevantWarning } from '../shared/lib/turbopack/utils'
import type { TurbopackResult } from './swc/types'

/**
 * Processes and reports build issues from Turbopack entrypoints.
 *
 * @param entrypoints - The result object containing build issues to process.
 * @param isDev - A flag indicating if the build is running in development mode.
 * @return This function does not return a value but logs or throws errors based on the issues.
 * @throws {Error} If a fatal issue is encountered, this function throws an error. In development mode, we only throw on
 *                 'fatal' and 'bug' issues. In production mode, we also throw on 'error' issues.
 */
export function printBuildErrors(
  entrypoints: TurbopackResult,
  isDev: boolean
): void {
  // Issues that we want to stop the server from executing
  const topLevelFatalIssues = []
  // Issues that are true errors, but we believe we can keep running and allow the user to address the issue
  const topLevelErrors = []
  // Issues that are warnings but should not affect the running of the build
  const topLevelWarnings = []

  // Track seen formatted error messages to avoid duplicates
  const seenFatalIssues = new Set<string>()
  const seenErrors = new Set<string>()
  const seenWarnings = new Set<string>()

  for (const issue of entrypoints.issues) {
    // We only want to completely shut down the server
    if (issue.severity === 'fatal' || issue.severity === 'bug') {
      const formatted = formatIssue(issue)
      if (!seenFatalIssues.has(formatted)) {
        seenFatalIssues.add(formatted)
        topLevelFatalIssues.push(formatted)
      }
    } else if (isRelevantWarning(issue)) {
      const formatted = formatIssue(issue)
      if (!seenWarnings.has(formatted)) {
        seenWarnings.add(formatted)
        topLevelWarnings.push(formatted)
      }
    } else if (issue.severity === 'error') {
      const formatted = formatIssue(issue)
      if (isDev) {
        // We want to treat errors as recoverable in development
        // so that we can show the errors in the site and allow users
        // to respond to the errors when necessary. In production builds
        // though we want to error out and stop the build process.
        if (!seenErrors.has(formatted)) {
          seenErrors.add(formatted)
          topLevelErrors.push(formatted)
        }
      } else {
        if (!seenFatalIssues.has(formatted)) {
          seenFatalIssues.add(formatted)
          topLevelFatalIssues.push(formatted)
        }
      }
    }
  }
  // TODO: print in order by source location so issues from the same file are displayed together and then add a summary at the end about the number of warnings/errors
  if (topLevelWarnings.length > 0) {
    console.warn(
      `Turbopack build encountered ${
        topLevelWarnings.length
      } warnings:\n${topLevelWarnings.join('\n')}`
    )
  }

  if (topLevelErrors.length > 0) {
    console.error(
      `Turbopack build encountered ${
        topLevelErrors.length
      } errors:\n${topLevelErrors.join('\n')}`
    )
  }

  if (topLevelFatalIssues.length > 0) {
    throw new Error(
      `Turbopack build failed with ${
        topLevelFatalIssues.length
      } errors:\n${topLevelFatalIssues.join('\n')}`
    )
  }
}
Quest for Codev2.0.0
/
SIGN IN