- [x] Decouple `exe` from format — make it a boolean option (`--exe`) layered on top of `--format` - [ ] Native addon / WASM support — map non-JS output to sea-config `assets` - [x] Cross-platform builds — download target platform's Node.js binary - [ ] Code signing — macOS notarization, Windows Authenticode - [x] Watch mode — rebuild exe on file changes - [ ] Copy-package — automatically include unbundleable packages and their dependencies (low priority) --- ### 1. Decouple `exe` from format Currently `exe` is a format (`--format exe`) that's internally mapped to `cjs`. Instead, `exe` should be a standalone boolean option: ```bash tsdown ./src/index.ts --format esm --exe tsdown ./src/index.ts --format cjs --exe ``` This way the user controls the actual module format, and `--exe` just enables the SEA post-build step. With Node.js landing ESM SEA support ([nodejs/node#61813](https://github.com/nodejs/node/pull/61813)), tsdown would pass `"mainFormat": "module"` or `"commonjs"` to sea-config.json based on the chosen format. No special mapping needed. Note: ESM mode currently cannot be used with `useCodeCache` or `useSnapshot` — tsdown should warn when these conflict. ### 2. Native addon / WASM support It's Rolldown's responsibility to handle `.node` and `.wasm` files during bundling. What tsdown needs to do is map the non-JS output chunks into sea-config `assets` and inject a runtime shim so they're loaded via `sea.getAsset()` + `process.dlopen()` instead of filesystem reads. ### 3. Cross-platform builds Build for linux/mac/windows from a single host by downloading the target platform's Node.js binary. For best startup performance, compiling on the target platform is still recommended. When cross-compiling, tsdown should warn and force-disable `useCodeCache` and `useSnapshot` since they are platform-specific and would crash on a different platform. ### 4. Code signing Currently only ad-hoc macOS codesign. Industry-standard signing for distributable binaries: - **macOS**: Developer ID signing + Apple notarization (`codesign --sign "Developer ID"` + `notarytool submit`). Without notarization, Gatekeeper blocks the binary for end users. - **Windows**: Authenticode signing via `signtool.exe` with an EV/OV code signing certificate. Unsigned exes trigger SmartScreen "unknown publisher" warnings. - **Linux**: No mandatory signing, but GPG signatures are common for package distribution. ### 5. Watch mode Currently disabled. Could rebuild the exe on file changes, though SEA build time (seconds) makes this less practical. Might still be useful for CLI tool iteration. ### 6. Copy-package — automatic handling of unbundleable packages Some packages can't be bundled — they contain native `.node` addons, `.wasm` modules, or use patterns like dynamic `require()` that break during bundling. These packages also have their own dependencies, so at runtime the entire dependency branch needs to be present in `node_modules`. Rolldown's `copy` module type works at the **single file** level — it copies one file and rewrites one import path. It can't handle this case because: - A package is a directory with `package.json`, multiple entry points, and internal `require()` calls between its own files - The package's dependencies also need to be present, forming a tree that must be resolved from `node_modules` - The `node_modules` layout matters — packages resolve their own deps relative to their location This requires **package-manager-level** dependency resolution, which is beyond what a bundler plugin should do. `copy-package` automates this at the tsdown layer: 1. User marks a package for copy (API/naming TBD) 2. tsdown externalizes the package from the bundle 3. tsdown walks its dependency graph from `node_modules`, following the full branch 4. The entire branch (pkg-a → pkg-b → pkg-c → ...) is copied into the output's `node_modules` 5. The bundled code's `require('pkg-a')` resolves to the copied location at runtime In exe mode, these copied packages would additionally be mapped into `sea-config.json` `assets`. tsdown handles the complexity here — dependency graph resolution, `node_modules` layout, and ensuring the copied branch is self-contained. > **Low priority.** The complexity of walking and copying dependency trees may not justify the use case. Worth revisiting once the more common exe scenarios (sections 1–5) are solid.