Meta: This is not an RFC as I don’t believe the change needs one. Instead it is just a proposal and if neccessary parties agree on it, we should implement it. If you disagree, see this as a pre-RFC. I’m open to opening an RFC :).
Motivation
The current standard library and the wasm32-unknown-unknown
target has most of its functionality stubbed out.
There is no pthreads support by wasm yet, so some functionality has to remain stubbed out for unknown periods of time. But it is possible to provide support for other functionality, like println!
, panic messages, or obtaining the time, with current Web APIs.
These functionalities all require us to call into JS however, and here is the problem: The unknown target has no official functionality where crates can say “these js functions need to be provided as imports”.
The js!
macro by the stdweb
crate provides the needed functionality: it allows Rust code to specify the js code it needs. cargo-web
then comines all the js code of the used Rust crates.
The way how I understand stdweb
achieves this is by putting the js code as string literals into the generated web assembly file, and cargo-web
parses the web assembly file and extracts the literals.
Resulting story for users
println!
and other basic functionalities provided by std will work like on other targets, you can just use them.
Maybe in the future cargo itself can provide support but I want to keep my proposal minimal, so for the time being you’d be required to use cargo-web
if you want to use std togethe with the wasm32-unknown-unknown
target. cargo doc, cargo check etc. should all work without cargo-web
integration.
If you know of any use cases where you want std
but don’t want it to have working functionality, please speak up! Then we can push the current stubbed-out but dependency free std to crates.io.
This move will help to establish cargo-web
as standard tool. This allows third party OS abstraction crates like rand or glutin to rely on its presence and use the js!
macro themselves to get e.g. seeding from js. I think this is the most important benefit of my proposal.
Detailed changes
Basic idea: std should be using the js!
macro itself to provide support for println!
etc.
Changes for stdweb:
The main functionality of the js macro seems to be provided through the webcore module. Therefore, I think the webcore module should be factored out of stdweb into a separate crate/module that only depends on std itself. stdweb itself would then depend on that crate.
Changes for upstream Rust
There are two alternatives here: either, add webcore to the sysroot as full crate, and do extern crate webcore;
in std’s lib.rs, or use it as non-public submodule of std. I guess with both proposals you’d include webcore as a submodule of the tree.
The two approaches each have their own advantages and disadvantages.
-
extern crate webcore;
requires webcore to be#![no_std]
and webcore is not able to use functionality from std. - the submodule approach is a bit more ugly
If its possible to make webcore not use std, one should go with the extern crate route.
Note that webcore
would always remain an implementation detail of the standard library: you would still have to do webcore = ...
or stdweb = ...
inside your Cargo.toml if you wanted to use the js macro.
Once this is done, the test runners should be updated to use cargo-web instead of cargo.
Creation of embedding specific targets
As @rpjohnst and @shepmaster suggest, we should create several targets based on wasm32 for different environments, that each differ in their libstd but are otherwise unchanged. E.g. wasm32-rust-web
for client side usage in web browsers, wasm32-rust-node
for usage with node.js. “non-web embeddings” (plugin engines for example) could continue usage of the unknown-unknown
target.
I suggest we start with a -web
target.
Use by js templating tools
There are templating tools like webpack in the js world you can use to create client side artifacts. These tools should now use cargo-web instead of cargo and include the js emitted by cargo-web into their process.