I think I've found a problem with the current way we try to handle wasi:incoming-handler... Let me try to sum things up:
starlingmonkey.wasm always exports wasi:http/incoming-handlercomponentize-js removes the import by default and attempts to re-add it based on what the guest component exports, before it is mergedincomingHandler implementations, so the check was re-enabled)Here are the problems (I think) with this situation:
StarlingMonkey always exposes wasi:http/incoming-handler, because the user could use the fetchEvent integration at any time :shrug:
Without parsing the JS (like we used to), we do not know if someone has implemented wasi:http/incoming-handler themselves. :thinking:
fetchEvent may not be in use (i.e. that check that was re-added)There are 4 scenarios:
export wasi:http/incoming-handler :check:user does HTTP with fetchEvent, no wasi export :cross_mark:
wasi:http/incoming-handler is stripped from the component that comes outuser does HTTP with fetchEvent, w/ export wasi:http/incoming-handler :cross_mark:
incomingHandler is exported (like in the manual impl case) failI'm currently mulling two ways to solve this:
1.Always export wasi:http/incoming-handler when http feature is on
- This is just a little bit similar to what we hand before, i.e. requiring splice-bindings to know about features
- This solution is somewhat unsatisfying but is the simplest and isn't unreasonable, as the HTTP feature does indicate that there should be inclusion of the interface
Re-add parsing of the JS (no rewriting) via es-module-lexer to figure out which case we're in
incomingHandler export, we can assume that fetchEvent is usedaddEventListener was called?es-module-lexer was doing previously and check for top level calls to addEventListener.addEventListener was called.Any feedback would be appreciated. I'm leaning towards (1) for expedience (and I'm not sure it's worth re-introducing the additional dependencies to do (2) just yet, though it's the more satisfying solution).
On second thought, I really am starting to like the oxc based solution here -- the node bindings are quite ergonomic and look like they'll work nicely to help figure out top level statements and imports/exports.
This would require of course introducing a new non-trivial (but production ready, IMO) dependency to componentize-js -- thoughts, @Till Schneidereit ?
Hey Victor! Thanks for the write up. I was banging my head against the wall today trying to use local componentize-js. Everything appears to work correctly with the published version 18.2 for my use case, which is installing a handler using addEventListener("fetch"). However, when I switch to the local componentize-js for the same js code, I get this error:
Error: Unable to extract expected exports list
Error: "source.js" does not export a "incomingHandler" interface as expected by the world.
Try defining it by its alias:
export const incomingHandler = {};
I guess this is exactly the issue you described here. Do you happen to know which commit introduced this breaking change?
Yup, so the commit that introduced this change is this one (and the related PR):
https://github.com/bytecodealliance/ComponentizeJS/commit/54ab08566d0cdf7cd8db8483bc5c02d9e35e3ffb
https://github.com/bytecodealliance/ComponentizeJS/pull/218
The problem with 18.2 is that it breaks existing wasi:http implementations -- this is something that should have been solved before 18.2 was released, and why Jco has been stuck on 0.17.0 for a while now.
PR to fix this is up -- works on my machine :tm:
https://github.com/bytecodealliance/ComponentizeJS/pull/247
nice move!
Last updated: Dec 06 2025 at 07:03 UTC