Skip to content

chore(build): rename configs, remove dead code, fix runtime bugs#1141

Closed
jdalton wants to merge 1 commit intomainfrom
chore/build-rename-configs
Closed

chore(build): rename configs, remove dead code, fix runtime bugs#1141
jdalton wants to merge 1 commit intomainfrom
chore/build-rename-configs

Conversation

@jdalton
Copy link
Copy Markdown
Contributor

@jdalton jdalton commented Apr 1, 2026

Summary

  • Renames esbuild config files to consistent naming scheme (esbuild.cli.mjs, esbuild.index.mjs, esbuild.build.mjs, esbuild-utils.mjs)
  • Removes dead code: unused plugin, orphaned scripts, unreachable resolver logic, template configs never called, stale constants/scripts
  • Refactors createBuildRunnerrunBuild (static imports, no IIFE, no dynamic imports); extracts resolveSocketLibExternal() and resolveConstant() helpers to deduplicate repeated blocks
  • Fixes runtime bugs: spawn() result misused with .on(), mixed return type in validateBundle(), undefined function refs, missing null guards, scoping issues, forbidden fs.access() usage
  • Switches Promise.allPromise.allSettled for parallel build/download tasks
  • Normalizes utf8utf-8, console.* → logger, removes stale JSDoc

Test plan

  • pnpm run build completes without errors
  • pnpm run build --force rebuilds cleanly
  • SEA binary builds successfully

Note

Medium Risk
Medium risk because it rewires the CLI build orchestration/config entrypoints and touches multiple build/test scripts; failures would surface as broken builds or packaging rather than runtime user-facing logic.

Overview
Modernizes the CLI esbuild setup by renaming/splitting configs to esbuild.cli.mjs, esbuild.index.mjs, and adding esbuild.build.mjs as the new orchestrator, then updates build scripts/templates/docs to call the new entrypoints.

Removes dead build infrastructure (the deadCodeEliminationPlugin and several unused/orphaned esbuild scripts/configs) and refactors shared build helpers by replacing createBuildRunner with a single runBuild() implementation in esbuild-utils.mjs.

Hardens build/test tooling by switching key parallel tasks to Promise.allSettled, adding null/exit-code guards around spawn() results, normalizing file encodings to utf-8, and fixing error handling/return types in validation and packaging scripts.

Written by Cursor Bugbot for commit 70074cf. Configure here.

Renames:
- esbuild.cli.build.mjs → esbuild.cli.mjs
- esbuild.index.config.mjs → esbuild.index.mjs
- esbuild.config.mjs → esbuild.build.mjs
- esbuild-shared.mjs → esbuild-utils.mjs

Dead code removed:
- esbuild-plugin-dead-code-elimination.mjs (unused plugin)
- scripts/esbuild.config.mjs (broken orphan, imported non-existent file)
- socketPackages={} + resolvePackageSubpath + resolve-socket-packages plugin (~50 lines never executed)
- template esbuild.build.mjs files (never called by any build script)
- INLINED_LEGACY_BUILD constant (no references in codebase)
- build:sea:internal:bootstrap script (referenced missing file)
- publish:sea script (referenced missing publish-sea.mjs)
- e2e:smol script (--smol not in BINARY_FLAGS, always errored)
- treeShaking:true (redundant default when bundle:true)
- external:[] (redundant default with platform:'node')

Refactored:
- createBuildRunner → runBuild (static imports, no IIFE, no dynamic imports)
- esbuild.build.mjs runs builds in-process via runBuild instead of spawning subprocesses
- Extracted resolveSocketLibExternal() helper (deduped 2x verbatim block)
- Extracted resolveConstant() inner fn (deduped 2x identical constants resolver)
- All template configs use runBuild() instead of duplicating manual build+write pattern

Runtime bugs fixed:
- test-wrapper.mjs: spawn() result used with .on() event listeners (Promise, not ChildProcess)
- validateBundle(): returned false|array mixed type; caller did violations.length on false
- verify-package.mjs: error(err) called undefined fn; logger used outside validate() scope;
  fileExists() used forbidden fs.access(); unnecessary import process from node:process
- wasm.mjs: showHelp() used logger not in scope (only defined in error branch)
- patches.mjs: commitPatch() used logger not in scope; local logger shadowed module import
- build.mjs watch mode: watchResult.code accessed without null guard
- build-js.mjs: buildResult.code accessed without null guard
- cli-sentry template build.mjs: two spawn results accessed .code without null guard
- validate-bundle.mjs: .catch used console.error instead of logger

Consistency:
- All esbuild configs use sourcemap:false explicitly
- utf8 → utf-8 throughout
- All console.log/error → logger across .config/ and scripts/
- Stale JSDoc removed from cover.mjs helpers
- build-infra/package.json and cli/package.json indentation fixed

chore(build): Promise.allSettled, fix import order, update stale docs

- Switch Promise.all → Promise.allSettled in build.mjs phase 4 post-processing,
  esbuild.build.mjs variant orchestration, and download-assets.mjs parallel
  downloads so all tasks complete before reporting failures
- Fix import order in esbuild.build.mjs (const logger was between import groups)
- docs/build-guide.md: update config file names (esbuild.cli.mjs, esbuild.index.mjs,
  esbuild.build.mjs) to match renames from previous commit
- build-infra/README.md: remove deleted deadCodeEliminationPlugin section and
  stale usage examples; update Related Files to current config names

chore(build): Promise.allSettled in download-iocraft-binaries
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Comment @cursor review or bugbot run to trigger another review on this PR

const failed = results.filter(r => r.status === 'rejected')
if (failed.length > 0) {
process.exitCode = 1
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Orchestrator failure detection is unreachable dead code

Medium Severity

The runBuild function catches all errors internally and never rejects — it always resolves to undefined. The orchestrator uses Promise.allSettled and filters for r.status === 'rejected', which can therefore never match. The failed array is always empty and process.exitCode = 1 in the orchestrator is unreachable. The build still exits correctly because runBuild itself sets process.exitCode = 1, but the orchestrator's failure-detection logic is dead code and gives a false impression of where error handling occurs.

Additional Locations (1)
Fix in Cursor Fix in Web

const failed = results.filter(r => !r.ok)
const failed = settled.filter(
r => r.status === 'fulfilled' && !r.value.ok,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Download error filter ignores rejected promises silently

Low Severity

The Promise.allSettled filter only checks r.status === 'fulfilled' && !r.value.ok, so any promise that actually rejects (e.g. due to an unexpected throw escaping the inner catch) would be silently ignored — no error logged, no process.exitCode set. The old Promise.all would have propagated such rejections. Adding a check for r.status === 'rejected' entries would close this gap.

Additional Locations (1)
Fix in Cursor Fix in Web

@jdalton
Copy link
Copy Markdown
Contributor Author

jdalton commented Apr 1, 2026

Superseded by #1140 which already includes these changes.

@jdalton jdalton closed this Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant