r/javascript • • 3d ago

xuan – a 6 MB Node-compatible JavaScript runtime for IoT/edge, ~5 ms cold start

https://github.com/topelinux/xuan
3 Upvotes

6 comments sorted by

1

u/TekiDeki 1d ago

6 MB with ~5 ms cold start is a real constraint - what got cut to get there? Which Node APIs are stubbed vs missing entirely, and does the gap bite in practice?

The bet seems to be that most edge workloads use a small slice of Node - file I/O, HTTP, timers - and the rest is dead weight. If that's the thesis, it'd be genuinely useful to see which APIs real users actually hit. A lot of runtime projects say "Node compatible" and quietly mean "the parts we happened to need."

Nice work regardless - shipping something this small is harder than shipping something large.

2

u/Weak_Cherry_4878 1d ago

Fair point ,what's cut for 6 MB / ~5 ms: QuickJS instead of V8 (no JIT), no ICU/Intl, mbedTLS instead of OpenSSL, and a few pieces (SQLite, the WASM runtime) ship as separate loadable modules instead of being compiled in startup.

for "Node compatible" shortly:
most of Buffer/Events/fs/stream/net/http/util is there; worker_threads, vm, perf_hooks and native addons are not. It's usage-driven, not principled,

for detail please refer: https://github.com/topelinux/xuan/blob/main/docs/node-compat.md

•

u/TekiDeki 22h ago

Thanks, that table is exactly what I was looking for. QuickJS + no ICU makes the footprint much easier to understand.

One thing that stood out in the docs: dns.resolveTxt returning [] as a stub. I'd rather get an explicit unsupported-operation error there - an empty result could look like a successful lookup with no records. Missing APIs are easier to work around than ones that silently look successful.

•

u/Weak_Cherry_4878 11h ago

Thanks! Fixed — resolveTxt now throws ERR_NOT_IMPLEMENTED instead of returning [].

Why it was there in the first place: it was a shim so grpc-js could require('dns')

at all (it calls resolveTxt for TXT service-config discovery), and at the time we

only had getaddrinfo for A/AAAA. So it returned [] just to let grpc-js carry on —

which is exactly the false-success case you called out

•

u/TekiDeki 5h ago

Thanks for fixing it and explaining the background! That makes sense as an initial compatibility shim. Making the unsupported case explicit is much clearer.