Skip to content

fix: split ESM/CJS builds to fix Electron bundling issue#1441

Merged
nicknisi merged 1 commit intoversion-8from
nicknisi/esm-cjs-bundling
Jan 9, 2026
Merged

fix: split ESM/CJS builds to fix Electron bundling issue#1441
nicknisi merged 1 commit intoversion-8from
nicknisi/esm-cjs-bundling

Conversation

@nicknisi
Copy link
Member

@nicknisi nicknisi commented Jan 9, 2026

Summary

  • Splits tsdown build config into separate ESM and CJS configurations
  • ESM: unbundled with external deps (ESM consumers import ESM deps directly)
  • CJS: bundled with iron-webcrypto and uint8array-extras inlined

Problem

Previous single config with noExternal created lib/node_modules/ structure that broke Electron asar packaging and pnpm symlink resolution.

Why CJS inlining is required

iron-webcrypto and uint8array-extras are ESM-only packages—they don't ship CJS builds. CJS code can't require() ESM modules, so these deps must be inlined/bundled into the CJS output for compatibility.

ESM build: unbundled with external deps (ESM consumers can import ESM)
CJS build: bundled with iron-webcrypto/uint8array-extras inlined

This prevents the problematic lib/node_modules/ structure that broke
Electron asar packaging and pnpm symlink resolution.
@nicknisi nicknisi requested a review from a team as a code owner January 9, 2026 15:10
@nicknisi nicknisi requested review from robertLichtnow and removed request for a team January 9, 2026 15:10
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Splits the tsdown build configuration from a single unified config into two separate ESM and CJS builds, resolving Electron asar packaging and pnpm symlink issues.

  • ESM build remains unbundled, allowing consumers to import ESM dependencies directly
  • CJS build bundles ESM-only dependencies (iron-webcrypto, uint8array-extras) for compatibility
  • Build order is correct: ESM cleans output directory first, then CJS adds .cjs/.d.cts files
  • jose dependency correctly excluded from bundling as it's dynamically imported via import() in src/utils/jose.ts

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The build configuration changes are well-architected and solve a real problem (Electron asar packaging) without introducing new issues. The split config correctly handles ESM/CJS differences, maintains proper build ordering, and appropriately bundles only the necessary ESM-only dependencies while leaving dynamically imported packages external.
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
tsdown.config.ts 5/5 Split build config into separate ESM (unbundled) and CJS (bundled) configurations to fix Electron asar packaging issues

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant Build as tsdown Build
    participant ESM as ESM Config
    participant CJS as CJS Config
    participant Output as lib/ Directory

    Dev->>Build: npm run build
    
    Note over Build,Output: Array config processed sequentially
    
    Build->>ESM: Process first config
    ESM->>Output: clean: true (clear directory)
    ESM->>Output: Generate .js files (unbundled)
    ESM->>Output: Generate .d.ts files
    Note over ESM,Output: Dependencies external<br/>(iron-webcrypto, jose)
    
    Build->>CJS: Process second config
    Note over CJS: clean: false (preserve ESM files)
    CJS->>CJS: Bundle iron-webcrypto<br/>and uint8array-extras
    CJS->>Output: Generate .cjs files (bundled)
    CJS->>Output: Generate .d.cts files
    Note over CJS,Output: ESM-only deps inlined<br/>jose remains external
    
    Output-->>Dev: Build complete<br/>Both formats in lib/
Loading

@nicknisi nicknisi requested a review from stacurry January 9, 2026 16:03
@nicknisi nicknisi merged commit 11c5455 into version-8 Jan 9, 2026
8 checks passed
@nicknisi nicknisi deleted the nicknisi/esm-cjs-bundling branch January 9, 2026 16:50
nicknisi added a commit that referenced this pull request Jan 9, 2026
## Summary
- Splits tsdown build config into separate ESM and CJS configurations
- ESM: unbundled with external deps (ESM consumers import ESM deps
directly)
- CJS: bundled with `iron-webcrypto` and `uint8array-extras` inlined

## Problem
Previous single config with `noExternal` created `lib/node_modules/`
structure that broke Electron asar packaging and pnpm symlink
resolution.

## Why CJS inlining is required
`iron-webcrypto` and `uint8array-extras` are ESM-only packages—they
don't ship CJS builds. CJS code can't `require()` ESM modules, so these
deps must be inlined/bundled into the CJS output for compatibility.
nicknisi added a commit that referenced this pull request Jan 12, 2026
## Summary
- Splits tsdown build config into separate ESM and CJS configurations
- ESM: unbundled with external deps (ESM consumers import ESM deps
directly)
- CJS: bundled with `iron-webcrypto` and `uint8array-extras` inlined

## Problem
Previous single config with `noExternal` created `lib/node_modules/`
structure that broke Electron asar packaging and pnpm symlink
resolution.

## Why CJS inlining is required
`iron-webcrypto` and `uint8array-extras` are ESM-only packages—they
don't ship CJS builds. CJS code can't `require()` ESM modules, so these
deps must be inlined/bundled into the CJS output for compatibility.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants