Skip to main content
doc0blade47/next.jsdocumentation home
Sign in

SWC Compiler

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

The SWC compiler integration in Next.js serves as the high-performance native compilation and minification engine, replacing traditional JavaScript-based toolchains for parsing, transforming, and bundling application source code. Built around Rust-powered Node-API (NAPI-RS) bindings and WebAssembly fallbacks, the compiler subsystem powers core tasks including JavaScript and TypeScript transpilation, React JSX/TSX transformations, CSS processing via Lightning CSS, MDX compilation, and incremental building with Turbopack. By handling computationally intensive abstract syntax tree (AST) operations natively, it solves performance bottlenecks associated with large-scale JavaScript toolchains while maintaining seamless interoperability with Webpack loaders and testing environments.

Sources: packages/next/src/build/swc/index.ts:1307-1324, packages/next/src/build/webpack/loaders/next-swc-loader.ts:31-34, packages/next/src/build/swc/generated-native.d.ts:74-78

Binary Discovery and Loading Lifecycle

Architecture Target Resolution and Native Binding Loading

The SWC compiler initializes by attempting to load native Node-API bindings compiled for the host operating system and CPU architecture. The loader resolves environment-specific binaries through NAPI-RS packages (@next/swc-<triple>), querying the loaded binary's target metadata via getTargetTriple.

export declare function getTargetTriple(): string

Sources: packages/next/src/build/swc/generated-native.d.ts:108-108

export function getBinaryMetadata() {
  return {
    target: loadedBindings?.getTargetTriple?.(),
  }
}

Sources: packages/next/src/build/swc/index.ts:1864-1868

WebAssembly Fallback Mechanics

When native Node-API bindings cannot be loaded or resolved, the loader falls back to WebAssembly implementations. The loading sequence checks for a local test directory via NEXT_TEST_WASM_DIR before iterating through production WebAssembly distribution packages.

async function loadWasmRawBindings(importPath = ''): Promise<RawWasmBindings> {
  let attempts = []
 
  // Used by `run-tests` to force use of a locally-built wasm binary. This environment variable is
  // unstable and subject to change.
  const testWasmDir = process.env.NEXT_TEST_WASM_DIR
 
  if (testWasmDir) {
    // assume these are node.js bindings and don't need a call to `.default()`
    const rawBindings = await import(
      pathToFileURL(path.join(testWasmDir, 'wasm.js')).toString()
    )
    infoLog(`next-swc build: wasm build ${testWasmDir}`)
    return rawBindings
  } else {
    for (let pkg of ['@next/swc-wasm-nodejs', '@next/swc-wasm-web']) {

Sources: packages/next/src/build/swc/index.ts:1328-1343

> [!NOTE]
> The WebAssembly initialization path distinguishes between Node.js and browser or web environments. When loading `@next/swc-wasm-web`, the loader explicitly invokes the exported `default()` initialization method to set up memory instances before binding execution.

Sources: packages/next/src/build/swc/index.ts:1355-1361

The fallback mechanism records detailed failure diagnostics when modules are missing or encounter load errors, collecting failure attempts until a valid binding instance is established or all options are exhausted.

} catch (e: any) {
  // Only log attempts for loading wasm when loading as fallback
  if (importPath) {
    if (e?.code === 'ERR_MODULE_NOT_FOUND') {
      attempts.push(`Attempted to load ${pkg}, but it was not installed`)
    } else {
      attempts.push(
        `Attempted to load ${pkg}, but an error occurred: ${e.message ?? e}`
      )
    }

Sources: packages/next/src/build/swc/index.ts:1364-1373

Package Caching and Binary Download Management

If required packages are absent from local directories, the extraction subsystem downloads compressed distribution tarballs from the active registry into a designated cache directory (next-swc).

const cacheDirectory = getCacheDirectory(
  'next-swc',
  process.env['NEXT_SWC_PATH']
)
 
const extractFromTar = () =>
  x({
    file: path.join(cacheDirectory, tarFileName),
    cwd: outputDirectory,
    strip: 1,
  })
 
if (!fs.existsSync(path.join(cacheDirectory, tarFileName))) {
  Log.info(`Downloading swc package ${pkgName}... to ${cacheDirectory}`)
  await fs.promises.mkdir(cacheDirectory, { recursive: true })
  const tempFile = path.join(
    cacheDirectory,
    `${tarFileName}.temp-${Date.now()}`
  )
 
  const registry = getRegistry()
 
  const downloadUrl = `${registry}${pkgName}/-/${tarFileName}`
 
  await fetch(downloadUrl).then((res) => {

Sources: packages/next/src/lib/download-swc.ts:17-41

Download FunctionTarget Package VariantDestination Directory Parameter
downloadNativeNextSwc@next/swc-${triple}bindingsDirectory
downloadWasmSwc@next/swc-wasm-${variant}wasmDirectory

Sources: packages/next/src/lib/download-swc.ts:108-146

The cache manager restricts resource bloat by enforcing a strict retention ceiling, automatically pruning older version directories exceeding the configured storage limit.

const MAX_VERSIONS_TO_CACHE = 8

Sources: packages/next/src/lib/download-swc.ts:10-10

const cacheFiles = await fs.promises.readdir(cacheDirectory)
 
if (cacheFiles.length > MAX_VERSIONS_TO_CACHE) {
  cacheFiles.sort((a, b) => {
    if (a.length < b.length) return -1
    return a.localeCompare(b)
  })
 
  // prune oldest versions in cache
  for (let i = 0; i++; i < cacheFiles.length - MAX_VERSIONS_TO_CACHE) {
    await fs.promises
      .unlink(path.join(cacheDirectory, cacheFiles[i]))
      .catch(() => {})
  }
}

Sources: packages/next/src/lib/download-swc.ts:91-105

Synchronous Installation and On-Demand Fetching

Deferred Bundle Loading

The SWC installation workflow avoids eager loading of compiler modules by deferring package requirements. Loading the main index module transitively pulls in configuration dependencies that evaluate process.env.NODE_ENV at require time. By routing installation requests through an isolated installer script, the process guarantees environment variables are configured before React or bundler modules initialize.

/**
 * This module provides a way to install SWC bindings without eagerly loading the entire swc/index module.
 *
 * The swc/index module can transitively load other modules (like webpack-config) that import React,
 * and React's entry point checks process.env.NODE_ENV at require time to decide whether to load
 * the development or production bundle. By deferring the require of swc/index until this function
 * is called, we ensure NODE_ENV is set before React is loaded.
 */
 
/**
 * Loads and caches the native bindings. This is idempotent and should be called early so bindings
 * can be accessed synchronously later.
 *
 * @param useWasmBinary - Whether to use WASM bindings instead of native bindings
 */
export async function installBindings(
  useWasmBinary: boolean = false
): Promise<void> {
  // Lazy require to avoid loading swc/index (and transitively webpack-config/React)
  // before NODE_ENV is set
  const { loadBindings } = require('./index') as typeof import('./index')
  await loadBindings(useWasmBinary)
}

Sources: packages/next/src/build/swc/install-bindings.ts:1-23

Note

The installBindings helper is fully idempotent and caches native bindings internally so that subsequent synchronous compiler accesses complete without asynchronous overhead. Sources: packages/next/src/build/swc/install-bindings.ts:11-18

On-Demand Binary Extraction and Pruning

When native bindings or WebAssembly packages are missing from local directories, the extraction subsystem streams tarball archives from the package registry into temporary cache locations before unpacking them.

if (!fs.existsSync(path.join(cacheDirectory, tarFileName))) {
  Log.info(`Downloading swc package ${pkgName}... to ${cacheDirectory}`)
  await fs.promises.mkdir(cacheDirectory, { recursive: true })
  const tempFile = path.join(
    cacheDirectory,
    `${tarFileName}.temp-${Date.now()}`
  )
 
  const registry = getRegistry()
 
  const downloadUrl = `${registry}${pkgName}/-/${tarFileName}`
 
  await fetch(downloadUrl).then((res) => {
    const { ok, body } = res
    if (!ok || !body) {
      Log.error(`Failed to download swc package from ${downloadUrl}`)
    }
 
    if (!ok) {
      throw new Error(`request failed with status ${res.status}`)
    }
    if (!body) {
      throw new Error('request failed with empty body')
    }
    const cacheWriteStream = fs.createWriteStream(tempFile)
    return body.pipeTo(
      new WritableStream({
        write(chunk) {
          return new Promise<void>((resolve, reject) =>
            cacheWriteStream.write(chunk, (error) => {
              if (error) {
                reject(error)
                return
              }
 
              resolve()
            })
          )
        },
        close() {
          return new Promise<void>((resolve, reject) =>
            cacheWriteStream.close((error) => {
              if (error) {
                reject(error)
                return
              }
 
              resolve()
            })
          )
        },
      })
    )
  })
 
  await fs.promises.access(tempFile) // ensure the temp file existed
  await fs.promises.rename(tempFile, path.join(cacheDirectory, tarFileName))
} else {
  Log.info(`Using cached swc package ${pkgName}...`)
}

Sources: packages/next/src/lib/download-swc.ts:29-88

To prevent unbounded disk utilization in the cache directory, the manager evaluates cached version counts and prunes stale artifacts when entries exceed the retention threshold.

const cacheFiles = await fs.promises.readdir(cacheDirectory)
 
if (cacheFiles.length > MAX_VERSIONS_TO_CACHE) {
  cacheFiles.sort((a, b) => {
    if (a.length < b.length) return -1
    return a.localeCompare(b)
  })
 
  // prune oldest versions in cache
  for (let i = 0; i++; i < cacheFiles.length - MAX_VERSIONS_TO_CACHE) {
    await fs.promises
      .unlink(path.join(cacheDirectory, cacheFiles[i]))
      .catch(() => {})
  }
}

Sources: packages/next/src/lib/download-swc.ts:91-105

Supported NAPI Targets

The build pipeline defines target triplets and architectures for native compilation and packaging within the NAPI configuration manifest.

Target Architecture & OS TripleDescription
x86_64-apple-darwin64-bit macOS (Intel)
x86_64-pc-windows-msvc64-bit Windows (MSVC)
x86_64-unknown-linux-gnu64-bit Linux (GLIBC)
i686-pc-windows-msvc32-bit Windows (MSVC)
aarch64-unknown-linux-gnuARM64 Linux (GLIBC)
aarch64-apple-darwinARM64 macOS (Apple Silicon)
x86_64-unknown-linux-musl64-bit Linux (MUSL)
aarch64-unknown-linux-muslARM64 Linux (MUSL)
aarch64-pc-windows-msvcARM64 Windows (MSVC)
wasm32-wasip1-threadsWebAssembly WASIp1 with threads

Sources: packages/next-swc/package.json:25-38

Compilation Options and Transform Normalization

Parser and Base Options Construction

SWC compiler options are assembled through getBaseSWCOptions, which inspects configuration files, compiler flags, and bundle layers to construct unified parser and transformation targets. The parser configuration automatically distinguishes between TypeScript and ECMAScript syntax based on file extensions while enabling dynamic imports and import attributes.

export function getParserOptions({ filename, jsConfig, ...rest }: any) {
  const isTSFile = filename.endsWith('.ts')
  const hasTsSyntax = isTypeScriptFile(filename)
  const enableDecorators = Boolean(
    jsConfig?.compilerOptions?.experimentalDecorators
  )
  return {
    ...rest,
    syntax: hasTsSyntax ? 'typescript' : 'ecmascript',
    dynamicImport: true,
    decorators: enableDecorators,
    // Exclude regular TypeScript files from React transformation to prevent e.g. generic parameters and angle-bracket type assertion from being interpreted as JSX tags.
    [hasTsSyntax ? 'tsx' : 'jsx']: !isTSFile,
    importAssertions: true,
  }
}

Sources: packages/next/src/build/swc/options.ts:39-54

Warning

Regular TypeScript files exclude React transformation inside the parser config to prevent generic parameters and angle-bracket type assertions from being misparsed as JSX tags. Sources: packages/next/src/build/swc/options.ts:50-51

React and Styling Transform Normalization

The transformation pipeline normalizes compiler settings for React, Emotion, and styled-components depending on whether code runs in server or client layers. When Emotion options are configured and the bundle does not target the React server layer, the import source defaults to @emotion/react.

react: {
  importSource:
    jsConfig?.compilerOptions?.jsxImportSource ??
    (compilerOptions?.emotion && !isReactServerLayer
      ? '@emotion/react'
      : 'react'),
  runtime: 'automatic',
  pragmaFrag: 'React.Fragment',
  throwIfNamespace: true,
  development: !!development,
  useBuiltins: true,
  refresh: !!hasReactRefresh,
},

Sources: packages/next/src/build/swc/options.ts:153-165

CSS-in-JS transformations for Emotion and styled-components are omitted on the server layer when building Server Components, avoiding client-only integration overhead during server compilation.

// Disable css-in-js libs (without client-only integration) transform on server layer for server components
...(!isReactServerLayer && {
  emotion: getEmotionOptions(compilerOptions?.emotion, development),
  styledComponents: getStyledComponentsOptions(
    compilerOptions?.styledComponents,
    development
  ),
}),

Sources: packages/next/src/build/swc/options.ts:215-222

Emotion label generation and auto-formatting options normalize user-provided configurations through explicit conditional branches.

Emotion Config PropertyDefault / Behavior
enabledtrue when emotion options are present
autoLabelDetermined by string value (dev-only, always, never)
sourcemapEnabled in development mode when source maps are requested
importMapCustom import mappings passed directly to the transform

Sources: packages/next/src/build/swc/options.ts:291-312

Parallel Transformation and Worker Pools

Loader Worker Pool Scheduling

SWC bindings register a worker scheduler via runLoaderWorkerPool to spawn and manage individual Node.js worker threads for parallel AST processing. Each worker pool is keyed by a composite identifier combining the current working directory and filename.

function getPoolId(cwd: string, filename: string) {
  return `${cwd}:${filename}`
}
 
export async function runLoaderWorkerPool(
  bindings: typeof import('./generated-native'),
  bindingPath: string
) {
  bindings.registerWorkerScheduler(
    (creation) => {
      const {
        options: { filename, cwd },
      } = creation
 
      const poolId = getPoolId(cwd, filename)
 
      const worker = new Worker(/* turbopackIgnore: true*/ filename, {
        workerData: {
          bindingPath,
          cwd,
        },
      })
 
      // This will cause handing when run in jest worker, but not as a first level thread of nodejs thread
      // worker.unref()
 
      const workers =
        loaderWorkers[poolId] || (loaderWorkers[poolId] = new Map())
 
      workers.set(worker.threadId, worker)
    },
    (termination) => {
      const {
        options: { filename, cwd },
        workerId,
      } = termination
 
      const poolId = getPoolId(cwd, filename)
      const workers = loaderWorkers[poolId]
      workers.get(workerId)?.terminate()
      workers.delete(workerId)
    }
  )

Sources: packages/next/src/build/swc/loaderWorkerPool.ts:5-47

Warning

Calling worker.unref() causes hanging when workers run inside a Jest environment; it remains commented out in the implementation to ensure proper lifecycle management under test runners. Sources: packages/next/src/build/swc/loaderWorkerPool.ts:28-29

Development Validation Worker Pool

The development validation system maintains a dedicated worker pool instance via installDevValidationWorker to offload validation logic and isolate runtime module states from the main thread.

const worker = new Worker(workerPath, {
  maxRetries: 0,
  numWorkers: 1,
  // Always worker-threads, regardless of `experimental.workerThreads`.
  // Unlike the `'use cache'` probe (which follows the flag), validation has
  // no reason to prefer a child process: it doesn't need process-level
  // isolation (a worker thread already has its own V8 heap and module
  // registry, so the reloaded route is isolated from the main thread), and
  // threads let a superseded validation be aborted mid-run through a shared
  // `SharedArrayBuffer`, which a separate process can't receive. Threads
  // also carry the transported Flight bytes as typed arrays via structured
  // clone, with no JSON round-trip to corrupt them.
  enableWorkerThreads: true,
  // Listing the method explicitly tells jest-worker to skip the discovery
  // `require()` it would otherwise do in the parent process to enumerate
  // the module's exports. This worker's top-level imports (`require-hook`,
  // `node-environment`) run runtime setup meant only for the isolated
  // worker thread, so they must not be evaluated in the parent.
  exposedMethods: [
    'runDevValidation',
    'applyHmrUpdate',
    'invalidateCaches',
  ],
  forkOptions: {
    env: {
      ...process.env,
      NODE_OPTIONS: workerNodeOptions,
    },
  },
}) as Worker & ValidationPool

Sources: packages/next/src/server/dev/dev-validation-worker-pool.ts:157-186

Worker Configuration PropertyValue / Behavior
maxRetries0
numWorkers1
enableWorkerThreadstrue
exposedMethodsrunDevValidation, applyHmrUpdate, invalidateCaches

Sources: packages/next/src/server/dev/dev-validation-worker-pool.ts:158-179

Note

Thread-based validation uses a SharedArrayBuffer to mirror abort signals across thread boundaries, allowing an in-flight validation run to be canceled mid-run at its next depth boundary. Sources: packages/next/src/server/dev/dev-validation-worker-pool.ts:234-243

Configuration and Jest Transpilation Hooks

TypeScript Configuration Transpilation

The configuration transpilation pipeline transforms TypeScript configuration files such as next.config.ts into executable CommonJS modules using SWC. The transpileConfig function coordinates loading the local tsconfig.json compiler options, configuring parser syntax, and falling back or executing through native bindings.

function resolveSWCOptions(
  cwd: string,
  compilerOptions: RelevantCompilerOptions
): SWCOptions {
  return {
    jsc: {
      parser: {
        syntax: 'typescript',
      },
      ...(compilerOptions.paths ? { paths: compilerOptions.paths } : {}),
      ...(compilerOptions.baseUrl
        ? // Needs to be an absolute path.
          { baseUrl: path.resolve(cwd, compilerOptions.baseUrl) }
        : compilerOptions.paths
          ? // If paths is given, baseUrl is required.
            { baseUrl: compilerOptions.pathsBasePath ?? cwd }
          : {}),
    },
    module: {
      type: 'commonjs',
    },
    isModule: 'unknown',
    env: {
      targets: {
        // Setting the Node.js version can reduce unnecessary code generation.
        node: process?.versions?.node ?? '20.19.0',
      },
    },
  } satisfies SWCOptions
}

Sources: packages/next/src/build/next-config-ts/transpile-config.ts:14-43

Note

If process.env.__NEXT_NODE_NATIVE_TS_LOADER_ENABLED is set to true, the pipeline checks Node.js built-in TypeScript strip or transform features before falling back to SWC-based transpilation. Sources: packages/next/src/build/next-config-ts/transpile-config.ts:69-78

When compiling configuration code, handleCJS inspects the resulting source for require( expressions. If present, it activates registerHook to dynamically intercept subsequent module imports during execution.

// register require hook only if require exists
if (code.includes('require(')) {
  registerHook(swcOptions)
  hasRequire = true
}
 

Sources: packages/next/src/build/next-config-ts/transpile-config.ts:133-138

Require Hook Management

The require hook utility overrides Node.js extension handlers (.js, .ts, .cts, .mts, .cjs, .mjs) to synchronously transpile required files on the fly.

for (const ext of extensions) {
  const oldHook = require.extensions[ext] ?? oldJSHook
  require.extensions[ext] = function (mod: any, oldFilename) {
    const _compile = mod._compile
 
    mod._compile = function (code: string, filename: string) {
      const swc = transformSync(code, swcOptions)
      return _compile.call(this, swc.code, filename)
    }
 
    return oldHook(mod, oldFilename)
  }
}

Sources: packages/next/src/build/next-config-ts/require-hook.ts:30-42

ExtensionHook Action
.jsFalls back to oldJSHook; if ERR_REQUIRE_ESM occurs, reads file content and compiles via SWC.
.ts, .cts, .mts, .cjs, .mjsOverrides mod._compile to transform source text using transformSync before native compilation.

Sources: packages/next/src/build/next-config-ts/require-hook.ts:6-42

Warning

SWC is loaded lazily via require('../swc') inside registerHook to prevent loading development React binaries before NODE_ENV is initialized. Sources: packages/next/src/build/next-config-ts/require-hook.ts:10-12

Jest Transformation Hook

The Jest transformer integrates SWC into test suites by exposing a createTransformer factory that constructs synchronous transform options for each test file.

const createTransformer: TransformerCreator<
  SyncTransformer<JestTransformerConfig>,
  JestTransformerConfig
> = (inputOptions) => ({
  process(src, filename, jestOptions) {
    const jestConfig = getJestConfig(jestOptions)
 
    const swcTransformOpts = getJestSWCOptions({
      isServer:
        jestConfig.testEnvironment === 'node' ||
        jestConfig.testEnvironment.includes('jest-environment-node'),
      filename,
      configDir: inputOptions?.configDir,
      jsConfig: inputOptions?.jsConfig,
      resolvedBaseUrl: inputOptions?.resolvedBaseUrl,
      pagesDir: inputOptions?.pagesDir,
      serverComponents: inputOptions?.serverComponents,
      modularizeImports: inputOptions?.modularizeImports,
      swcPlugins: inputOptions?.swcPlugins,
      compilerOptions: inputOptions?.compilerOptions,
      imageConfig: inputOptions?.imageConfig,
      serverReferenceHashSalt: '',
      esm:
        isSupportEsm &&
        isEsm(Boolean(inputOptions?.isEsmProject), filename, jestConfig),
    })
 
    return transformSync(src, { ...swcTransformOpts, filename })
  },
})

Sources: packages/next/src/build/swc/jest-transformer.ts:82-111

The transformer evaluates the test environment and file extensions to determine ECMAScript module support before dispatching to transformSync.

function isEsm(
  isEsmProject: boolean,
  filename: string,
  jestConfig: Config.ProjectConfig
): boolean {
  return (
    (/\.jsx?$/.test(filename) && isEsmProject) ||
    jestConfig.extensionsToTreatAsEsm?.some((ext: any) =>
      filename.endsWith(ext)
    )
  )
}

Sources: packages/next/src/build/swc/jest-transformer.ts:69-80

Diagnostic Telemetry and Failure Recovery

Load Failure Events and WebAssembly Fallback Tracking

When native Node-API bindings fail to load, loadWasmRawBindings tracks each failure attempt across packages like @next/swc-wasm-nodejs and @next/swc-wasm-web. If a module is missing, it records ERR_MODULE_NOT_FOUND events or accumulates fallback error strings before raising the complete attempt list.

async function loadWasmRawBindings(importPath = ''): Promise<RawWasmBindings> {
  let attempts = []
 
  // Used by `run-tests` to force use of a locally-built wasm binary. This environment variable is
  // unstable and subject to change.
  const testWasmDir = process.env.NEXT_TEST_WASM_DIR
 
  if (testWasmDir) {
    // assume these are node.js bindings and don't need a call to `.default()`
    const rawBindings = await import(
      pathToFileURL(path.join(testWasmDir, 'wasm.js')).toString()
    )
    infoLog(`next-swc build: wasm build ${testWasmDir}`)
    return rawBindings
  } else {
    for (let pkg of ['@next/swc-wasm-nodejs', '@next/swc-wasm-web']) {
      try {
        let pkgPath = pkg
 
        if (importPath) {
          // the import path must be exact when not in node_modules
          pkgPath = path.join(importPath, pkg, 'wasm.js')
        }
        const importedRawBindings = await import(
          pathToFileURL(pkgPath).toString()
        )
        let rawBindings
        if (pkg === '@next/swc-wasm-web') {
          // https://rustwasm.github.io/docs/wasm-bindgen/examples/without-a-bundler.html
          // `default` must be called to initialize the module
          rawBindings = await importedRawBindings.default!()
        } else {
          rawBindings = importedRawBindings
        }
        infoLog(`next-swc build: wasm build ${pkg}`)
        return rawBindings
      } catch (e: any) {
        // Only log attempts for loading wasm when loading as fallback
        if (importPath) {
          if (e?.code === 'ERR_MODULE_NOT_FOUND') {
            attempts.push(`Attempted to load ${pkg}, but it was not installed`)
          } else {
            attempts.push(
              `Attempted to load ${pkg}, but an error occurred: ${e.message ?? e}`
            )
          }
        }
      }
    }
  }
 
  throw attempts
}
 
// helper for tryLoadWasmWithFallback / loadBindings.
async function loadWasm(importPath = '') {
  const rawBindings = await loadWasmRawBindings(importPath)
 
  function removeUndefined(obj: any): any {
    // serde-wasm-bindgen expect that `undefined` values map to `()` in rust, but we want to treat
    // those fields as non-existent, so remove them before passing them to rust.
    //
    // The native (non-wasm) bindings use `JSON.stringify`, which strips undefined values.
    if (typeof obj !== 'object' || obj === null) {
      return obj
    }
    if (Array.isArray(obj)) {
      return obj.map(removeUndefined)
    }
    const newObj: { [key: string]: any } = {}
    for (const [k, v] of Object.entries(obj)) {
      if (typeof v !== 'undefined') {
        newObj[k] = removeUndefined(v)
      }
    }
    return newObj
  }
 
  // Note wasm binary does not support async intefaces yet, all async
  // interface coereces to sync interfaces.

Sources: packages/next/src/build/swc/index.ts:1328-1414

Warning

When NEXT_TEST_WASM_DIR is set, raw bindings are loaded directly from the local test directory via file URLs without invoking an initialization function, whereas @next/swc-wasm-web requires a explicit call to .default() to initialize the module. Sources: packages/next/src/build/swc/index.ts:1331-1361

Lockfile Management and Edge Runtime Diagnostics

The native binding layer exposes explicit methods for file locking and runtime analysis, including lockfileTryAcquire, lockfileTryAcquireSync, lockfileUnlock, and lockfileUnlockSync. Additionally, warnForEdgeRuntime analyzes source code to produce NapiSourceDiagnostic warnings for production and development targets.

rspack: {
  getModuleNamedExports: function (
    resourcePath: string
  ): Promise<string[]> {
    return bindings.getModuleNamedExports(resourcePath)
  },
  warnForEdgeRuntime: function (
    source: string,
    isProduction: boolean
  ): Promise<NapiSourceDiagnostic[]> {
    return bindings.warnForEdgeRuntime(source, isProduction)
  },
},
expandNextJsTemplate(
  content: Buffer,
  templatePath: string,
  nextPackageDirPath: string,
  replacements: Record<`VAR_${string}`, string>,
  injections: Record<string, string>,
  imports: Record<string, string | null>
): string {
  return bindings.expandNextJsTemplate(
    content,
    templatePath,
    nextPackageDirPath,
    replacements,
    injections,
    imports
  )
},
lockfileTryAcquire(filePath: string, content?: string | null) {
  return bindings.lockfileTryAcquire(filePath, content)
},
lockfileTryAcquireSync(filePath: string, content?: string | null) {
  return bindings.lockfileTryAcquireSync(filePath, content)
},
lockfileUnlock(lockfile: Lockfile) {
  return bindings.lockfileUnlock(lockfile)
},
lockfileUnlockSync(lockfile: Lockfile) {
  return bindings.lockfileUnlockSync(lockfile)
},

Sources: packages/next/src/build/swc/index.ts:1762-1803

Binding MethodParameter TypesPurpose
lockfileTryAcquire`filePath: string, content?: stringnull`
lockfileTryAcquireSync`filePath: string, content?: stringnull`
lockfileUnlocklockfile: LockfileAsynchronously releases an acquired lockfile reference.
lockfileUnlockSynclockfile: LockfileSynchronously releases an acquired lockfile reference.
warnForEdgeRuntimesource: string, isProduction: booleanScans source code for unsupported features and returns an array of NapiSourceDiagnostic objects.

Sources: packages/next/src/build/swc/index.ts:1768-1803, packages/next/src/build/swc/types.ts:103-109

Was this page helpful?