chore(cli): bundle with bun target node and publish from staged dir#2637
chore(cli): bundle with bun target node and publish from staged dir#2637RomanHotsiy wants to merge 11 commits intomainfrom
Conversation
🦋 Changeset detectedLatest commit: 1b232c3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1772635755 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1772635755
# or
npm install @redocly/openapi-core@0.0.0-snapshot.1772635755
# or
npm install @redocly/respect-core@0.0.0-snapshot.1772635755 |
tatomyr
left a comment
There was a problem hiding this comment.
Had a brief look. Will give it another pass later.
| import { performance } from 'node:perf_hooks'; | ||
| import { default as redoc } from 'redoc'; | ||
|
|
||
| import packageJson from '../../../package.json' with { type: 'json' }; |
There was a problem hiding this comment.
It probably makes more sense to import it from utils/package.js.
tests/e2e/helpers.ts
Outdated
| } | ||
|
|
||
| function cleanUpStyledComponentWarnings(str: string): string { | ||
| return str.replace(/^styled-components: it looks like an unknown prop .*?(?:\r?\n|$)/gm, ''); |
There was a problem hiding this comment.
I don't see the message anywhere. Why do wee need this?
scripts/release-publish.mjs
Outdated
| const result = spawnSync(command, args, { | ||
| cwd: rootDir, | ||
| stdio: 'inherit', | ||
| shell: process.platform === 'win32', |
There was a problem hiding this comment.
Are we going to publish from Win?
packages/cli/package.json
Outdated
| "prepublishOnly": "npm run copy-assets && cp ../../README.md ." | ||
| "compile": "bun build src/index.ts --target node --define process.env.NODE_ENV=process.env.NODE_ENV --outfile lib/index.js", | ||
| "prepare:publish-dir": "node ./scripts/prepare-publish-dir.mjs", | ||
| "clean:publish-dir": "node ./scripts/clean-publish-dir.mjs" |
|
|
||
| try { | ||
| run('npm', ['--workspace', 'packages/cli', 'run', 'prepare:publish-dir']); | ||
| run('npm', ['exec', 'changeset', 'publish']); |
There was a problem hiding this comment.
How does it know it should publish from packages/cli/.publish/ and not from packages/cli/?
There was a problem hiding this comment.
"publishConfig": {
"directory": ".publish"
},
in cli/package.json
| if (!value || typeof value !== 'object') { | ||
| return value; | ||
| } | ||
|
|
||
| const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined); | ||
| return Object.fromEntries(entries); |
There was a problem hiding this comment.
| if (!value || typeof value !== 'object') { | |
| return value; | |
| } | |
| const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined); | |
| return Object.fromEntries(entries); | |
| if (isPlainObject(value)) { | |
| const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== undefined); | |
| return Object.fromEntries(entries); | |
| } | |
| return value |
There was a problem hiding this comment.
Anyways, why do we need to clean up the constructed package json programmatically? Let's just construct it the way we want.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1b232c3. Configure here.
| } | ||
|
|
||
| if (result.status !== 0) { | ||
| process.exit(result.status ?? 1); |
There was a problem hiding this comment.
process.exit() bypasses finally cleanup in release script
Medium Severity
The run() function calls process.exit() when a command returns a non-zero exit code. In Node.js, process.exit() terminates the process immediately without unwinding the call stack, so the finally block on line 36 that runs clean:publish-dir never executes. Only the throw path (for spawn errors) is catchable. This means if changeset publish fails with a non-zero exit code, the .publish directory is never cleaned up. Changing the non-zero-status path to throw instead of process.exit() would let the try/catch/finally work as intended.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 1b232c3. Configure here.
tatomyr
left a comment
There was a problem hiding this comment.
Left a minor comment. Please also check this comment: #2637 (comment).
Otherwise LGTM.
| } | ||
|
|
||
| console.warn('Bun binary not found on PATH; falling back to `npx bun@1.3.10`.'); | ||
| return spawnSync('npx', ['--yes', 'bun@1.3.10', ...bunBuildArgs], { |
There was a problem hiding this comment.
Why not just use bun as a dev dependency?
There was a problem hiding this comment.
I think it's overkill, we need it only for publishing, I would keep it as is.


What/Why/How?
bun build --target node) instead of the previous TypeScript-only compile flow.createRequire('../../package.json')patterns with static JSON imports in CLI runtime paths.build-docstemplate fallback so bundled artifacts do not depend ontemplate.hbsbeing present as a filesystem asset.package.jsonmutation/restore with a staged publish directory (packages/cli/.publish) andpublishConfig.directorysochangeset publishpublishes from the staged manifest/artifacts.bin/cli.js, bundledlib/index.js,README.md,LICENSE, and a strippedpackage.json(no deps/devDeps/scripts).Reference
Testing
npm --workspace packages/cli run compilenode packages/cli/lib/index.js --helpnpm run typechecknpm run pack:preparenpm run release(no unpublished packages in this run; verified publish-dir prepare/cleanup path)Screenshots (optional)
Check yourself
Security
Note
Medium Risk
Medium risk because it replaces the CLI build and npm publish mechanics (Bun bundling + staged publish directory), which can break installs, releases, and runtime asset resolution if misconfigured.
Overview
Bundles the CLI into a single Node-targeted output using Bun (with an
npx bunfallback) to reduce install time and avoid runtimerequire-style package.json lookups.Changes publishing/packing to a staged
packages/cli/.publishdirectory viapublishConfig.directoryand newprepare:publish-dir/cleanup scripts, and updates release/snapshot/local pack flows (plus.gitignore) to publish/pack from that directory.Hardens bundled runtime behavior by embedding a fallback
build-docsHandlebars template whentemplate.hbsisn’t available on disk, and wiringredocversion lookup through a static JSON import. CI workflows are updated to install Bun and e2e now bundles the CLI before running.Reviewed by Cursor Bugbot for commit 1b232c3. Bugbot is set up for automated code reviews on this repo. Configure here.