A dependency solver for the elm ecosystem
npm install elm-solve-deps-wasmThis repo holds a dependency solver for the elm ecosystem compiled to a WebAssembly module.
The wasm module is published on npm, so you can easily use it in your JS projects with:
``js`
let wasm = require("elm-solve-deps-wasm");
wasm.init();
let use_test = false; // solve for normal dependencies, not test dependencies
let additional_constraints = {}; // no additional package needed
let solution = wasm.solve_deps(
elm_json_config, // the elm.json that we have to solve
use_test,
additional_constraints,
fetchElmJson, // user defined (cf example-offline/dependency-provider-offline.js)
listAvailableVersions // user defined (cf example-offline/dependency-provider-offline.js)
);
Shrinking the generated WebAssembly package to the smallest size possible will benefit everyone using it as a dependency, so here is an attempt at doing it.
Most of the info required to [shrink the wasm size is available in the rustwasm reference book][shrink-wasm].
Here is a summary of the different techniques we use here.
- Compile with link time optimization (lto). In theory, this gives LLVM more opportunities to inline and prune functions.opt-level = "z"
- Use to optimize for size instead of for speed.wee_alloc
- Use the [ allocator][wee_alloc] which is optimized for size instead of the default allocator, optimized for speed.panic = "abort"
- Replace panic logic by abort with and with [wasm-snip --snip-rust-panicking-code][wasm-snip].wasm-opt -Oz -o output.wasm input.wasm
- Use [][wasm-opt] on the output of wasm-pack. Remark that it's better to use the latest one from the binaryen project instead of the one shipped with wasm-pack automatically, so we add wasm-opt = false to wasm-pack config.twiggy
- Profile the generated wasm with [][twiggy] to find optimization opportunities. This requires adding debug = true to the release compilation profile, and -g to wasm-opt.
With the above tricks we start with a .wasm file weighing 470kb and end with a 251kb file!wasm-opt
Most of it comes from the tool.
Here is the detail of what each step brings:
- Initial --release size: 479kb.wee_alloc
- When using : 470kb.wasm-opt -Oz
- When also adding : 366kb.lto = true
- When also adding and opt-level = "z": 276kb.wasm-snip --snip-rust-panicking-code
- When also adding : 271kb.debug = true
- When adding and using twiggy, I found out that there was a non-negligeable part of the wasm binary dedicated to formatting f64 numbers. But in fact, this never happens in our use case, so we can snipe it!wasm-snip -p "core::fmt::float::
- When also adding : 251kb.
So in summary, the steps to get the most shrinked wasm module are the following:
`sh`
wasm-pack build --target nodejs
wasm-snip --snip-rust-panicking-code -p "core::fmt::float::
wasm-opt -Oz -o output.wasm snipped.wasm
cp output.wasm pkg/elm_solve_deps_wasm_bg.wasm
All that being said, if you don't want to bother installing wasm-snip and the latest wasm-opt, you can simply call:`sh`
wasm-pack build --profiling --target nodejs.wasm` of size 276kb.
and let the provided wasm-opt do its job, with a generated
[shrink-wasm]: https://rustwasm.github.io/docs/book/reference/code-size.html
[wee_alloc]: https://github.com/rustwasm/wee_alloc
[wasm-snip]: https://github.com/rustwasm/wasm-snip
[wasm-opt]: https://rustwasm.github.io/docs/book/reference/code-size.html#use-the-wasm-opt-tool
[twiggy]: https://rustwasm.github.io/twiggy/index.html