Meanwhile javascript will be much faster to download since it is smaller and javascript can execute while it is downloading.
Meanwhile javascript will be much faster to download since it is smaller and javascript can execute while it is downloading.
• WebAssembly is not huge. Fundamentally it’s generally smaller than JavaScript, but JavaScript comes with more of a standard library and more of a runtime, which unbalances comparisons. If you use something like Rust, it’s not difficult to get the basic overhead down to something like 10 kB, or for a larger project still well under 100 kB, until you touch things that need Unicode or CLDR tables; and it will generally scale similarly to JavaScript, once you take transport compression into account. If you use something like Go or .NET, sure, then there’s a heavier runtime, maybe a megabyte, maybe two, also depends on whether Unicode/CLDR tables are needed, and then JS will probably win handily on bundle size and startup time.
• JavaScript can’t execute while it’s downloading. In theory speculative parsing and even limited speculative execution is possible, but I don’t think any engine has tried that seriously. As for WebAssembly, it can be compiled and instantiated while streaming, generally at a faster rate than you can download it. The end result is that in an apples-to-apples comparison WebAssembly is significantly faster to start than JavaScript.
I always feel like I'm downloading megabytes of it whenever someone uses it. In practice it is. Even a basic hello world in rust will set you back a few megabytes compared to a the tens of bytes it takes in javascript.
>JavaScript comes with more of a standard library and more of a runtime, which unbalances comparisons.
Being able to make programs in a few bytes is a legitimate strength. You can't discount it because it's an effective way javascript saves size.
Lies. It’s 35 kB:
$ cargo new x
…
$ cd x
$ cat src/main.rs
fn main() {
println!("Hello, world!");
}
$ cargo build --release --target=wasm32-unknown-unknown
…
$ ls -l target/wasm32-unknown-unknown/release/x.wasm
… 34597 …
And that’s with the default allocator and all the std formatting and panic machinery. Without too much effort, you can get it to under 1 kB, if I remember correctly.For the rest: I mention comparisons being unbalanced because people often assume it will scale at the rate they’ve seen—twice as much code, twice as much size. Runtimes and heavy tables make for non-scaling overhead. That 35 kB you’ve paid for once, and now can use as much as you like without further growth.
Meanwhile, an empty React project seems to be up to 190 kB now, 61 kB gzipped.
For startup performance, it’s fairly well understood that image bytes are cheap while JavaScript bytes are expensive. WebAssembly bytes cost similar to images.
That's definitely not true.
A debug build of a "hello wasm-bindgen" style Rust program indeed takes ~2MB, but most of that is debug into; disabling that and/or stripping gets it down to 45-80kB (depending how I did it). And a release build starts at 35kB, and after `wasm-opt -O` gets down to 25kB. AFAIK most of the remaining space is used by wasm-bindgen boilerplate, malloc and panic machinery.
...and then, running wasm-bindgen to generate JS bindings somehow strips most of that boilerplate too, down to 1.4kB.
Side note, I never understood how wasm-opt is able to squeeze so much on top of what LLVM already did (it's a relatively fast post-build step and somehow reduces our production binaries by 10-20% and gives measurable speedups).
Lots of people pretend they don't need ICU or TZDB but that means leaving non-english-speakers or people outside of the US in the cold without support, which isn't the case for JS applications.
I still think this is a major unsolved problem for WebAssembly and I've previously raised it. I understand why it's not solved though - specifying and freezing the bitstream for ICU databases is a big task, etc.
Plus, WASM game runtimes need to bundle redundant 2D or 3D stacks, audio, fonts, harfbuzz, etc. yet don't expose eg. text rendering capabilities on par with those that browsers already have natively.
The whole thing is priorizing developer over user experience.
If size is your top priority, you can produce very small binaries, for example with C. Project [0] emulates an x86 architecture, including hardware, BIOS, and DOS compatibility, and ends up with a WebAssembly size of 78 kB uncompressed and a 24 kB transfer size.
Not many people are going to want to be rolling their own libc like that author. Most people just compile their app and ship megabytes of webassembly at the expense of their users. To me webassembly is just a shortcut to ship faster because you don't have to port existing code.
Emscripten provides a libc implementation based on musl, and so does wasi-libc (https://github.com/WebAssembly/wasi-libc).
If you explicitly list which functions you want to export from your WebAssembly module, the linker will remove all the unused code, in the same way that "tree-shaking" works for JS bundlers.
In my experience, a WebAssembly module (even with all symbols exported) is smaller than the equivalent native library. The bytecode is denser.
WebAssembly modules tend to be larger than JavaScript because AOT-compiled languages don't care as much about code size--they assume you only download the program/library once. In particular, LLVM (which I believe is the only mainstream WebAssembly-emitting backend) loves inlining everything.
Judicious use of `-Oz`, stripping debug info, and other standard code size techniques really help here. The app developer does have to care about code size, of course.
It will be a while before WASM GC will look close to any language's GC.
The native ecosystem never payed attention to binary size optimization, but the JS ecosystem payed attention to code size in the very beginning.
> The native ecosystem never payed attention to binary size optimization, but the JS ecosystem payed attention to code size in the very beginning.
That's not true at all. Native ecosystem stopped paying attention to it outside of embed once storage/memory got relatively cheap (i.e. we went from kilo and megabytes to gigabytes). Native also gets to use shared libraries...sometimes.
JavaScript ecosystem is like pendulum, sometimes they care, sometimes they don't.
I have high hopes for components, both for reducing size and for avoiding JavaScript.