• 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.
> Even a basic hello world in rust will set you back a few megabytes
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.
I should also mention that that 35 kB is uncompressed—gzipped, it’s 13 kB, and with brotli it’s 11.3 kB.
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.
> 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.
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).
I think you're understating the cost of having to ship your own standard library with every wasm application - the chunk of stdlib used by a real app is bigger than 10kb. ICU data files are in the tens of megabytes, TZDB is a chunk of data too.
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.
A lot of the stuff WebAssembly is obviously good at is stuff where you never need any of those tables—algorithms, computations, not UI stuff. I would like to see improvements like you to make it more generally useful, but there’s still plenty of scope for WASM even without running into these issues. Also I think you’re probably overestimating the size of the stuff you actually need to include. You tend to include specific tables rather than all the data. More typical figures are like “oh, you used regex with its default features… that’ll cost 500 kB”. And that’ll also be a pre-compression 500 kB. Though on the other hand you can also end up including multiple copies of things when you’re careful about optimising what each one has!
Just to correct slightly, I suspect most people who write Go WebAssembly are using https://tinygo.org/, which also achieves starting binaries in the 10kb range.
• 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.