2 messages were moved here from #jco > Ahead of time TS to WASM/I by Victor Adossi.
Mendy Berger said:
I build/vibed a small project to show that reusing JS bindings is possible. It mostly just repurposes Jco and ComponentizeJS parts.
I got Boa, Porffor, and Static Hermes to work with it with relatively little code per engine/compiler
Hey awesome work! I don't think the repo is public/accessible quite yet (I get a 404), but I'm looking forward to seeing it the code!
Did you by any chance get that approach to work with Perry? Would love to compare it to perry-wit or perry as used in Jco right now!
Also, do you happen to have P3 support in there? not required for a quick experiment of course, but this is one big separation. Would also love to see some perf/size comparison with wit-dylib.
Sorry, it's public now
I didn't do Perry as I didn't wanna step on the other engineers toes, but I think it should be adoptable to Perry as well
No P3 since it was adopted from the P2 ComponentizeJS almost as is. But if you think this approach is worth pursuing I can work on that
As far as I can tell the the project you're using still has a runtime that needs to be adapted per-library, and I am not 100% sure where the benefit is. Trying to think about it, it seems the benefit is extracting/reusing the WIT generation, and then pulling the per-guest runtimes into one project, what else am I missing?
In the case of WIT generation/robustness, I'd take the code from the new componentize-js rather than the code from current componentize-js.
IMO One of the reasons perry-wit was really interesting was because it goes from TS to LLVM IR and modifies the IR (via pliron) to add support for P3/hook into perry underneath, and runtime changes are essentially required for P3 support.
This is a great start though!
I could definitely see pulling this project into Jco as the default implementation of those backends (boa, stricthermes, porffor) for the p2 case, especially if there's a usable NPM package (could be napi-rs based or jco transpile based).
We definitely want more support for more languages
still has a runtime that needs to be adapted per-library
Not sure exactly what you mean. There's no custom wasm runtime. There is however some glue code that each engine/compiler needs, ~400 lines per engine in the examples. But that glue only moves numbers and bytes between core wasm and JS: calling exports, calling imports, reading/writing memory, UTF-8. It doesn't depend on the WIT world at all.
The benefit is everything that does depend on it: lifting and lowering records, variants, lists, strings, resources etc. to and from JS values, and checking the exports. That's generated once, in JS, so it runs on any engine. Without it, each engine needs its own componentize tool that reimplements all of that natively, the way ComponentizeJS does for SpiderMonkey.
FWIW I think the glue can be reduced further, I started with what Jco and ComponentizeJS already had. But there will always have to be some amount of custom, per-engine code.
Since we're in the LLM age (:tm:) I got a :robot: to help me figure this out and try to put some numbers behind the intuition. The repo is completely vibecoded, but it's at least a starting point for trying to figure out what in the world the size/performance differences and characteristics are:
https://github.com/vados-cosmonic/js-guest-bindgen-comparison/blob/main/SUMMARY.md
Along with the README I've also included the prompt as a vague attempt at reproducible vibes:
https://github.com/vados-cosmonic/js-guest-bindgen-comparison/blob/main/PROMPT.md
Trying to get it to put some graphs in the README and improve the SVGs right now
![]()
![]()
We really live in an amazing time to be bale to so easily generate this code and decent graphs to show results. This would have been weeks/months of work (for me at least!) otherwise
This is really cool!
Not surprising that wit-dylib is much slower and bigger with a compiler.
I didn't expect wit-bindgen-c to be so much faster with porffor, since the js is also compiled. But it does make sense if the compiled JS still brings some baggage.
Do you have any idea/intuition where componentize-qjs and the new componentize-js would fit in on bin size and perf? I think the Porffor numbers are pretty nice.
Combine that with the recent improvements in Porffor's spec compliance (> 96%) and Porffor seems like a great choice for a lot of projects!
Hey so the repo actually has all of that --
approach A: js-guest-bindgen
approach B: new componentize-js + per-WIT native bindings (lift/lower/etc happens outside of JS)
approach C: new componentize-js + wit-dylib
![]()
approach B is essentially the same as A and much smaller (~50%!) under Porffor
![]()
There's more testing to do (more engines, diff scenarios, etc) BUT perf is also much better under B & C (by a factor of magnitude):
![]()
Things get better if you tune A so there's definitely hope but IMO the machinery from the new componentize-js is really good and worth stealing/modularizing so it can be used in other places
Victor Adossi said:
Things get better if you tune A so there's definitely hope but IMO the machinery from the new componentize-js is really good and worth stealing/modularizing so it can be used in other places
Without actually looking at the code generation machinery, shouldn't this be a general purpose component optimizer that can inline wit-dylib calls?
Tomasz Andrzejak said:
Victor Adossi said:
Things get better if you tune A so there's definitely hope but IMO the machinery from the new componentize-js is really good and worth stealing/modularizing so it can be used in other places
Without actually looking at the code generation machinery, shouldn't this be a general purpose component optimizer that can inline
wit-dylibcalls?
Yes I think that would work!
Thinking about this a bit more, one way of doing such optimization for wit-dylib specifically without implementing component aware optimizer, would be to generate relocatable wit-dylib object that can be statically linked with runtime and then hand off optimization to binaryen.
A chain like this: runtime.a + wit-dylib.o -> wasm-ld -> combined.wasm -> wasm-opt -> optimized runtime. The key here is that wit-dylib object is relocatable so that wasm-ld knows which implementation to patch from runtime.
Last updated: Oct 31 2026 at 23:03 UTC