Skip to content

fix: bundle plugin to JS for server mode compatibility#36

Merged
dialupdisaster merged 3 commits into
DEVtheOPS:mainfrom
bendtherules:fix/bundle-plugin-for-server-mode
Apr 30, 2026
Merged

fix: bundle plugin to JS for server mode compatibility#36
dialupdisaster merged 3 commits into
DEVtheOPS:mainfrom
bendtherules:fix/bundle-plugin-for-server-mode

Conversation

@bendtherules
Copy link
Copy Markdown
Contributor

@bendtherules bendtherules commented Apr 25, 2026

Problem

Plugin fails to load in server/CLI mode (opencode run) with errors like:

Export named 'OTLPLogExporter' not found in module

Works fine in TUI mode. Seems like a difference in plugin loading behaviour between TUI and other modes.

Root Cause

Best effort explanation from AI below -

The conditions: ["browser"] build setting (in Opencode) affects how the main thread resolves CJS modules at runtime, but Worker threads get a fresh module resolution context that behaves more like standalone bun. This is a Bun compiled binary quirk, not documented behavior — it's the most plausible explanation for why TUI (Worker thread) works while server/CLI (main thread) doesn't.
The bundled JS fix works because it resolves all imports at build time, eliminating runtime CJS/ESM interop entirely.

Fix

Pre-bundle all dependencies into a single JavaScript file using bun build, which resolves imports at build time and avoids CJS/ESM interop issues at runtime.

bun build resolves all imports at build time, inlining the CJS modules into a single JavaScript file. The named exports are extracted during the build, not at runtime. When opencode loads the bundled file, there are no CJS modules left to interop with — everything is already ESM.

Changes

  1. Add build script: bun build src/index.ts --outdir=./dist --target=node && tsc -p tsconfig.build.json
  2. Update exports/main/module to point to dist/index.js
  3. Add ./server export for explicit server mode entry point
  4. Add types condition to exports map and top-level types field for TypeScript consumers
  5. Add tsconfig.build.json to emit declaration files alongside bundled JS
  6. Add prepack hook (instead of prepublishOnly) to ensure build runs before npm publish, npm pack, and when installing from git
  7. Update files to ship dist/ instead of src/

Verification

I have verified that it works manually via -

  1. local file path
  2. pushed fork to npm and tested live with it.

Happy to delete the package after fix is merged.

Fixes #35

Bun's on-the-fly TypeScript transpilation fails to extract named exports
from CJS modules (like @opentelemetry/*) when loaded via `await import()`
in opencode's compiled binary. This causes plugins to fail in server/CLI
mode while working fine in TUI mode.

Fix by pre-bundling all dependencies into a single JavaScript file using
`bun build`, which resolves imports at build time and avoids CJS/ESM
interop issues at runtime.

- Add `build` script: `bun build src/index.ts --outdir=./dist --target=node`
- Update exports/main/module to point to `dist/index.js`
- Add `prepublishOnly` to ensure build runs before npm publish
- Add `./server` export for explicit server mode entry point

Fixes DEVtheOPS#35
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough

Walkthrough

Package distribution configuration updated to publish built JavaScript artifacts from dist/ instead of TypeScript source from src/. Export entries repointed to dist/index.js, with a new "./server" subpath added. Build process integrated via build script and prepublishOnly hook.

Changes

Cohort / File(s) Summary
Package Configuration
package.json
Updated main, module, and exports fields to reference dist/index.js. Added exports["./server"] subpath. Changed files whitelist from src/ to dist/. Added build script (bun build) and prepublishOnly lifecycle hook to execute build before publishing.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Suggested reviewers

  • dialupdisaster
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: bundling the plugin to JavaScript for server mode compatibility, which directly addresses the root cause of the linked issue.
Linked Issues check ✅ Passed The PR fully addresses the coding requirements from issue #35 by implementing the fix to bundle dependencies into JS and updating export paths to point to the built output.
Out of Scope Changes check ✅ Passed All changes in package.json are directly related to the bundling fix: adding build script, updating exports/main/module, and adding prepublishOnly hook—all within the PR's stated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
package.json (1)

61-67: Consider prepack instead of (or in addition to) prepublishOnly.

prepublishOnly only runs on npm publish. prepack additionally runs on npm pack and when the package is installed from a git URL/tarball, which is a common way users try plugins before they hit npm. Given dist/ is gitignored, installing from git today would produce a broken package.

♻️ Suggested change
-    "prepublishOnly": "bun run build"
+    "prepack": "bun run build"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 61 - 67, The package.json currently only defines a
"prepublishOnly" script which runs build before npm publish; add a "prepack"
script that also runs the build (same command as "build") so packaging via npm
pack or installing from a git/tarball will include the built dist; update the
"scripts" object to include "prepack": "bun run build" (or the identical command
used by "prepublishOnly"/"build") and ensure it runs the same build pipeline as
the existing "build" script.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Around line 31-34: The package currently publishes only JS (exports: "." and
"./server" -> "./dist/index.js") but omits TypeScript declarations because
tsconfig.json has noEmit: true and bun build doesn't emit .d.ts, so TypeScript
consumers lose types; add a build-time declaration step: create a
tsconfig.build.json that overrides noEmit to false, sets declaration: true and
emitDeclarationOnly: true with outDir: "dist", update the "build" script to run
that tsc declaration step (or a separate "build:types" command) so .d.ts files
are emitted into dist/, and update package.json to expose them via the types
field/condition in the export map (add "types": "./dist/index.d.ts" or a "types"
export condition alongside the existing exports) so consumers get typings.

---

Nitpick comments:
In `@package.json`:
- Around line 61-67: The package.json currently only defines a "prepublishOnly"
script which runs build before npm publish; add a "prepack" script that also
runs the build (same command as "build") so packaging via npm pack or installing
from a git/tarball will include the built dist; update the "scripts" object to
include "prepack": "bun run build" (or the identical command used by
"prepublishOnly"/"build") and ensure it runs the same build pipeline as the
existing "build" script.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fd3d252c-e3c4-410d-9d15-462d6e75fbb6

📥 Commits

Reviewing files that changed from the base of the PR and between f79aa8e and 37a86e8.

📒 Files selected for processing (1)
  • package.json

Comment thread package.json
Add tsconfig.build.json that emits only declaration files into dist/,
so TypeScript consumers retain type information after the switch from
source to bundled JS entry points.

- Add tsconfig.build.json with emitDeclarationOnly + rootDir: ./src
- Update build script to run tsc -p tsconfig.build.json after bundling
- Add types field to package.json exports and top-level
- Include .d.ts condition in export map for both . and ./server

Addresses CodeRabbit review comment on PR DEVtheOPS#36
@bendtherules
Copy link
Copy Markdown
Contributor Author

Addressed CodeRabbit's review comment about missing TypeScript declarations:

  • Added tsconfig.build.json with emitDeclarationOnly: true and rootDir: ./src
  • Updated build script to run tsc -p tsconfig.build.json after bundling
  • Added types condition to exports map and top-level types field

Now dist/index.d.ts is emitted alongside the bundled JS. Commit: ce22030

prepack runs on both npm publish and npm pack (and when installing from
git/tarball), whereas prepublishOnly only runs on npm publish. Since dist/
is gitignored, installing directly from git would produce a broken package
without this change.

Addresses CodeRabbit nitpick comment on PR DEVtheOPS#36
@dialupdisaster dialupdisaster self-requested a review April 27, 2026 20:02
@dialupdisaster dialupdisaster merged commit 76aa5b2 into DEVtheOPS:main Apr 30, 2026
2 checks passed
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.

[Bug]: opencode run "xyz" fails to load plugin due to 'OTLPLogExporter' not found error

2 participants