fix(jco): re-export browser bindgen from @bytecodealliance/jco-transpile#1751
fix(jco): re-export browser bindgen from @bytecodealliance/jco-transpile#1751zacharywhitley wants to merge 1 commit into
Conversation
|
Hey @zacharywhitley thanks for the report -- this is certainly a regression. The fix here should be to use the exports from Would you be up for trying to make those changes? (and a regression test would be appreciated too, just to avoid this happening again -- Jco in the browser has not gotten enough attention as of late and a E2E test or even a release gate like we have in CI would be incredibly helpful) |
|
Absolutely, I'll give it a go this evening. Thanks |
|
Appreciate it 🙇 Thanks for banging on this and helping fix it -- Jco in the browser definitely needs way more attention than we've (at the very least I) been able to give it up until now. |
The `@bytecodealliance/jco` browser entry (`src/browser.js`) imports the transpiled `js-component-bindgen-component.js` from `../obj/`, but `packages/jco/package.json`'s `files` array only lists `lib`, `src`, and `types`. As a result, `npm publish` drops the entire `obj/` directory and any bundler resolving jco's `browser` conditional export fails with `Failed to resolve import "../obj/js-component-bindgen-component.js"`. Per maintainer guidance in bytecodealliance#1751, wire the browser entry through `@bytecodealliance/jco-transpile` instead of trying to ship `obj/` from jco itself. `jco-transpile` already vendors the bindgen under `vendor/` and lists it in its `files` array, so a new `./component` subpath export makes that artifact reachable from downstream packages: - `packages/jco-transpile/package.json`: add `./component` to `exports` pointing at `./vendor/js-component-bindgen-component.{js,d.ts}`; bump to `0.4.3` to expose the new subpath. - `packages/jco/src/browser.js`: import `$init`, `generate`, and `generateTypes` from `@bytecodealliance/jco-transpile/component` instead of `../obj/js-component-bindgen-component.js`. Public exports and their $init-await wrapping are unchanged. - `packages/jco/package.json`: repoint the `./component` types export from the (unshipped) `./obj/js-component-bindgen-component.d.ts` to `./types/browser.d.ts`, which is already produced by `build:ts` and covered by the `types` entry in `files`. Also add a `browser-bundle-smoke` job to `.github/workflows/main.yml` that packs both packages, installs the tarballs into a scratch project, and bundles `import '@bytecodealliance/jco/component'` with `esbuild --platform=browser`. The job additionally asserts the jco tarball does not ship an `obj/` tree. This is the class of regression that bytecodealliance#646 originally fixed for 1.11.1 and that recurred in 1.25.2; a release gate against packed tarballs catches it without needing a real browser test harness.
81fac20 to
2b00711
Compare
|
Pushed the redirect. Approach (Option B): browser entry now imports Regression test: Two notes worth flagging:
Ready for another look @vados-cosmonic. |
There was a problem hiding this comment.
This is almost there, thanks for making the changes, @zacharywhitley -- I've left just a few more points to address/think about.
So basically I think when I release this, I'm going to:
- release the new version of
jco-transpilefirst (leaving theworkspace:dep in place forjco) - remove the
workspace:dep for jco, replacing it with the updatedjco-transpile - release
jco
| mkdir -p /tmp/jco-pack | ||
| (cd packages/jco-transpile && npm pack --pack-destination /tmp/jco-pack --ignore-scripts) | ||
| (cd packages/jco && npm pack --pack-destination /tmp/jco-pack --ignore-scripts) | ||
| ls -la /tmp/jco-pack |
There was a problem hiding this comment.
You should be able to use pnpm --filter <project> pack --pack-destination <path> for this I think
| fi | ||
|
|
||
| - name: Bundle the browser entry with esbuild against the packed tarballs | ||
| run: | |
There was a problem hiding this comment.
What do you think about compress all these intermediate steps of this into one JS script (scripts/build-browser-bundle.mjs?)
| { | ||
| "name": "@bytecodealliance/jco-transpile", | ||
| "version": "0.4.2", | ||
| "version": "0.4.3", |
There was a problem hiding this comment.
yeah let's leave this unchanged for now -- right now our release scripts will do this update automatically (since we usually don't know how many breaking changes got in until we cut a release)...
It's a bit weird, but we do stay on the previous version until the new release actually happens.
As far as the things you flagged:
|
| npm install --no-save --no-audit --no-fund \ | ||
| /tmp/jco-pack/bytecodealliance-jco-transpile-*.tgz \ | ||
| /tmp/jco-pack/bytecodealliance-jco-*.tgz |
|
Oh and one more thing -- if we could use the |
|
Will do. Happy to be contributing. I have another project that I'm working on that works with the CM. It was originally for implementing the CM for Endive but it turned out to be generally applicable and I'm porting it over to the browser. It comes from a very different direction than jco. I don't know if there could be any cross pollination or if you're just interested but anything that furthers the CM couldn't be bad. I just have to finish a few things and then I'll open it up. It implements most of the CM in webassembly itself. |
Definitely interested in getting whatever changes we can learn from in here! Jco is aiming to be toolkit, so multiple runtimes, multiple host implementations (this should be possible soon once we externalize the runtime) are all welcome.
Well that sounds amazing -- my interest is piqued and I'm sure almost all of the folks on Zulip would be too! is this some sort of cross of https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-dylib and a new interface that covers the CM but with only core types? Very interesting. |
Thanks for the link. That might slot in nicely. You nailed it. I've had a bit of a change in how I view the webassembly runtime. I used to think of it as a hard split between guest and host with the guest being webassembly and the host being whatever the embedding language was but then I realized that you can fold most of the host side code into guest side implementations and then guest vs host becomes more about the direction you're traversing the WIT interface than where the implementation lives. Now your host side code is portable and sandboxed (minus the explicit interface you expose). I've been pulling on that thread and it goes interesting places |
|
That's certainly super interesting -- there are some guests built with wit-dylib (e.g. componentize-js), so if those codebases/generated components & WAT are interesting to you, feel free to peruse them! Of course for compiled languages native bindings are much more efficient but really interested to see what you're working on, feel free to discuss/ask questions in the Zulip if you ever have any, I'm sure others would also be interesting/would like to theory craft on what is possible. There has been discussion lately of distilling the interface needed by modules (essentially to make it as easy as possible for people to implement the CM) down as well, so this fits in there, but I'm not sure how much of it is well documented yet. |
Problem
@bytecodealliance/jco@1.25.2(published 2026-07-09) ships a broken browser build.packages/jco/src/browser.jsimports the bindgen artifact from../obj/js-component-bindgen-component.js, butpackages/jco/package.json'sfilesarray is only["lib","src","types"], sonpm publishdrops the entireobj/directory and any bundler resolving thebrowserconditional export fails:Issue #646 tracked the same class of regression in 1.11.0. It has re-regressed since the vendoring reorg (#1732 / #1744) —
obj/is no longer produced next tobrowser.jsat publish time.Fix (revised per maintainer guidance)
Per @vados-cosmonic in #1751 (comment), this PR now wires the browser entry through
@bytecodealliance/jco-transpilerather than re-adding theobj/*globs topackages/jco'sfileslist. The siblingjco-transpilepackage already vendors the bindgen undervendor/js-component-bindgen-component.jsand ships it via itsfilesarray, so exposing it as a subpath export makes it consumable fromjco(and any other downstream) without duplicating the artifact.packages/jco-transpile/package.json: add a./componentsubpath toexportspointing at./vendor/js-component-bindgen-component.{js,d.ts}. Version bumped to0.4.3(patch — non-breaking additive export).packages/jco/src/browser.js: replaceimport ... from "../obj/js-component-bindgen-component.js"withimport ... from "@bytecodealliance/jco-transpile/component". Public exports (generate,generateTypes,transpile, and their$init-await wrapping) are preserved for backwards compatibility.packages/jco/package.json: repoint the./componenttypes export from the (unshipped)./obj/js-component-bindgen-component.d.tsto./types/browser.d.ts, which is already produced bybuild:tsand covered by thetypesentry infiles.obj/is no longer referenced from anywhere the tarball needs to see.Note:
packages/jco/package.json's@bytecodealliance/jco-transpiledependency is left at^0.4.2— that satisfies workspace-linked0.4.3in local dev, and oncejco-transpile@0.4.3is on the registry, npm/pnpm consumers of a futurejcorelease automatically resolve to a version that has the new subpath. Maintainers may prefer to bump the range explicitly at release time.Regression test
Added a
browser-bundle-smokejob to.github/workflows/main.yml(release gate — runs on every PR):build/jco-transpile-vendorartifacts.types/anddist/are in place.npm pack --ignore-scriptsfor both packages into a scratch dir.obj/tree (guards against re-addingobj/*tofiles"just in case").esbuild --bundle --platform=browseronimport '@bytecodealliance/jco/component'.out.jsis empty.node:*is marked external in the smoke test because the vendored bindgen has runtime feature detection with a dynamicawait import('node:fs/promises')for host env use; a browser code path never reaches that import and the smoke test only needs to prove import resolution and bundling succeed. This is the same class of check upstream would need for a real browser E2E test but doesn't require puppeteer / a browser runtime, so it runs on every PR.Verification
Locally, before the fix,
esbuild --bundle --platform=browseronimport '@bytecodealliance/jco/component'fails at the../obj/...import. After the fix, packing both packages, installing into/tmp/jco-bundler-smoke, and running:produces a 410 KB
out.jsand exits 0. The packedbytecodealliance-jco-1.25.2.tgzcontains zero entries underobj/(confirmed withtar tzf ... | grep -c obj→0).References
obj/directory #646 — original 2025obj/-missing regression fixed in 1.11.1jco-transpile3c64835a— chore(jco): remove un-needed dist files, re-enable testsBranch-name note
Branch is still
fix/ship-obj-in-tarball— the name predates the maintainer's redirect tojco-transpileand is kept as-is to preserve this PR's URL. The commit and description reflect the actual approach.