denoland/deno · error

esbuild produced no JavaScript output

Error message

esbuild produced no JavaScript output

What it means

The in-memory bundling helper returns the first JavaScript output file it finds (skipping non-JS outputs like CSS and sourcemaps); if none of esbuild's outputs is JS, it bails (cli/tools/bundle/mod.rs:922-938). The entry's graph produced only non-JS artifacts - classically a CSS-only or asset-only entrypoint.

Source

Thrown at cli/tools/bundle/mod.rs:938

  )?;

  for file in &output_files {
    let processed = maybe_process_contents(
      file,
      should_replace_require_shim(bundle_flags.platform),
      bundle_flags.minify,
    )?;
    if !processed.is_js {
      continue;
    }
    return Ok(
      processed
        .into_contents()
        .unwrap_or_else(|| file.contents.to_vec()),
    );
  }

  deno_core::anyhow::bail!("esbuild produced no JavaScript output")
}

fn metafile_from_response(
  response: &BuildResponse,
) -> Result<esbuild_client::Metafile, AnyError> {
  Ok(serde_json::from_str::<esbuild_client::Metafile>(
    response.metafile.as_deref().ok_or_else(|| {
      deno_core::anyhow::anyhow!("expected a metafile to be present")
    })?,
  )?)
}

async fn bundle_watch(
  flags: Arc<Flags>,
  bundler: EsbuildBundler,
  minified: bool,
  platform: BundlePlatform,
  output_dir: Option<&Path>,

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Pass a JS/TS module as the entrypoint - CSS should be imported from JS (import './style.css') rather than bundled as the entry
  2. Verify the entry file actually contains executable module code and is not empty/type-only
  3. Check that the correct entry path is being used (typo pointing at a sibling .css/.map file)

Example fix

// before: CSS as entry - no JS output
// run: bundleEntry('src/styles.css')  -> esbuild produced no JavaScript output
// after: JS entry that imports the CSS
// src/main.ts: import './styles.css'; export function app() { /* ... */ }
// run: bundleEntry('src/main.ts')
Defensive patterns

Strategy: validation

Validate before calling

const JS_ENTRY = /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/i;
function assertJsEntry(entry: string) {
  if (!JS_ENTRY.test(entry)) {
    throw new Error(`entry must be a JS/TS module, got: ${entry} (import CSS from JS instead)`);
  }
}

Type guard

function isJsModulePath(path: string): boolean {
  return /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/i.test(path);
}

Prevention

When it happens

Trigger: Bundling an entry whose outputs are all CSS/maps (e.g. a stylesheet passed where a JS/TS module is expected); a module graph that tree-shakes to zero JS; outputs filtered out because maybe_process_contents marks them non-JS.

Common situations: Build scripts passing style.css or an HTML/CSS asset as the entry to a flow that expects JS bytes; renaming entries such that the real JS entry is no longer passed.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/6c89c081eaadbbff. Report an issue: GitHub.