I was able to reduce size of my wasm app by 29.6%
I have been working on one of my hobby projects, pixeldraw (a raster drawing software) for the last few days. It is written using the rust programming language and iced is used for the gui. While primary focus was the desktop, I discovered that iced has wasm(web assembly) support. So I gave a thought about it and compiled it to wasm using trunk and hosted on my website so anyone interested can try it without downloading. My first concern was about the size of the wasm file. It is actually quite larger, 6167170 bytes (5.9 Mb). For a desktop app it was not a problem, it's only a one time download and also it's small compared to normal desktop app size. But for web it's really a problem, for each request the whole wasm file should be send. It will start to consume bandwidth quickly. So I started to search for ways to reduce the size (even though it's not a big problem for a site with less traffic).
- The first logical step will be to use
-Ozflag inwasm-optto optimize for size, but I am already using it. The 5.9 Mb size was after using it. So I am not considering it here. I added it here just as a reminder of this feature. - Then I checked the
Cargo.tomlfile. The release profile was;[profile.release]opt-level = 's'lto = true
strip = truecodegen-units = 1
It was optimized for size, but a little modification can be done here. I replaced the
sflag inopt-levelwithzwhich reduces the size further with a little performance reduction (but according to the documentation on some casesswill result in smaller size thanz).But the main change was to add
panic = "abort"(The default behavior ispanic = "unwind"). Since unwinding is useful for the desktop version and it is not recommended for the dependencies, I haven't added it to the[profile.release]section. Instead I created.cargo/config.tomland added it there specifically for the wasm target.[target.wasm32-unknown-unknown]rustflags = [ "-C", "panic=abort" ]Thus the normal build will use
panic = "unwind"andpanic = "abort"will be used while targeting wasm.After that I checked the size of wasm file. It is reduced to 5.1 Mb.
- After that I checked the dependencies section. There was a lot of space for improvement. Apart from the other crates common for both desktop and wasm, the initial structure of wasm target was like this;
[target.'cfg(target_arch = "wasm32")'.dependencies]
iced = { version = "0.14.0", features = ["canvas", "tokio", "image", "webgl", "fira-sans" ]}
wasm-bindgen-futures = "0.4"
And the dependencies field was;
[dependencies]# ... other dependencies
image = { version = "0.25.10", default-features = false }# ... other dependenciesYeah I am pulling most of the default features of iced which are not useful for the wasm.
tokiois not at all useful (wasm-bindgen-futureshandles it), so I removed it first. Instead of pulling all the default features of iced I disabled the default features and added only what is necessary (addedwgpu-bareandweb-colors). I am already using theimagecrate and iced is also using it. So I changedimagewithimage-without-codecsin iced features and theimagewas moved from dependencies and in the wasm specific target I addedpnganggiffeatures to theimagecrate which is needed for the app to work. Finally it looks like this;[target.'cfg(target_arch = "wasm32")'.dependencies]
iced = { version = "0.14.0", default-features = false, features = ["canvas", "image-without-codecs", "webgl", "fira-sans", "web-colors", "wgpu-bare"]}
wasm-bindgen-futures = "0.4"
image = { version = "0.25.10", default-features = false, features = ["png", "gif"]}
After the third step I checked the size again. It was 4340682 bytes (4.2 Mb). Totally I was able to reduce the size from 6167170 bytes to 4340682 bytes (1826488 bytes is removed), 29.6% reduction without changing my app logic or source code.