I have... no idea if I'm asking in the right place, and if not, I'm hoping someone here can point me in the right direction.
i'm currently trying to figure out how to integrate wasm support for a Rust datetime library, and this integration involves platform specific things like, "find the current system configured time zone."
i am currently testing wasm32-wasip1
support in CI, and this just integrates with the "host" OS. so there's very specifically (at least I think) _no_ platform support that Jiff needs to be aware of here. you just need to let the wasmtime process access /usr/share/zoneinfo
and /etc/localtime
(on Unix).
but in other wasm contexts, it seems appropriate to use a crate like js-sys
to run some Javascript code to get the current time zone. it occurs to me that this is _not_ what should be done for _all_ wasm targets, yet that is effectively what is sometimes done.
i don't have a lot of wasm experience, and my wasm ecosystem knowledge is nearly non-existent. i don't even have a fully formed question, but i think it's something like, "how do I know when it's appropriate to use js-sys
on wasm targets to do platform-specific things?"
Whether or not this is the right place I can at least try to help out :)
I think that you'll probably want to break things down into a few buckets:
cfg(target_family = "wasm")
cfg(target_os = "wasi")
cfg(not(target_os = "wasi"))
isn't right all the time. The best approximation for this is that wasm32-unknown-unknown
is often used for the web and you can test with cfg(target_os="unknown")
. Some WASI use cases use this as well though which is why it's not perfect.That's at least the easy parts, but you probably already know much of that. The harder parts will make the answer much more nuanced here:
wasm32-wasip1
you probably can't rely on /usr/share/zoneinfo
and such. Most of the time guests don't have full access to the filesystem. Instead they typically get one directory. Or at least I haven't conventionally seen wasm tools get full access to the filesystem. This means that while you can probe for it you probably won't find those files and the answer is most likely "you're out of luck" and there's no way to do anything here.wasm32-wasip2
the wasi-clocks
proposal is undergoing changes to add support for basic time zones. Whether or not that's enough for Jiff I'm not sure. I believe a work in progress is here but I think changes are being made. For this there's no current implementation to test against though.js-sys
and web-sys
, yes, to hook into whatever the JS platform has for time zones and whatnot. I suspect that the APIs you want are already bound and present.That's all to say I think the outlook is not so good for wasm support in Jiff. What I might recommend is:
js-sys
/web-sys
integration. That'd be the detection for "compiling for the web". The end user experience is not great since it requires an opt in but that's sort of a reflection of the ecosystem right now (the whole rust/wasm-on-the-web is not as buttery smooth as native)wasm32-wasip1
is unlikely to ever be supported since it didn't have time zone support. The wasm32-wasip2
target is a work-in-progress.I suspect the folks working on timezones for wasm32-wasip2
in WASI itself would love to get your feedback, but I'm not sure how best to connect them other than hope they're reading this as well.
Looks like changes to wasi-clocks and timezones are at https://github.com/WebAssembly/wasi-clocks/issues/69. I haven't been following this though so I unfortunately can't give a tl;dr
yeah i've actually responded there! it sounds like they're trending towards the IANA tz ID, which is all Jiff needs.
there is a separate question of how to access the "system" tzdb, but this is basically only a thing on Unix. so Jiff just bundles it everywhere else (like Windows). this is not especially great for shipping an artifact to web browsers, but i don't really think there's much of an alternative.
yeah i've actually responded there
Oh excellent!
this is not especially great for shipping an artifact to web browsers
Makes sense yeah. Is the already a cargo feature to disable this? (or is that not possible?) Otherwise that's probably the best that can be done with wasm right now
and thank you for the reply!
the opt-in feature approach is definitely kind of a bummer, but yeah, i see why you suggest that. one specific issue that has also cropped up is that SystemTime::now()
will panic on some wasm targets but not on others. for cases where it panics, i think i'm supposed to use js-sys
to access the Javascript Date
API. that _seems_ like something that shouldn't require an opt-in though, i guess the alternative is to just go figure out exactly the wasm targets where std
will panic? maybe that also will be a good approximation for "the web"?
Alex Crichton said:
yeah i've actually responded there
Oh excellent!
this is not especially great for shipping an artifact to web browsers
Makes sense yeah. Is the already a cargo feature to disable this? (or is that not possible?) Otherwise that's probably the best that can be done with wasm right now
yeah it can be disabled. enabled by default. (well, the status quo is that Jiff doesn't have any wasm specific logic right now. but i expect "bundle tzdb" to be enabled by default on wasm. but can be disabled.)
i guess there's maybe two different issues here. on the one hand, it seems okay to ask for an opt-in to make "get the current local time zone" work correctly. but on the other, it seems bad to require an opt-in to make Timestamp::now()
not panic.
but both, i think, require js-sys
"on the web."
That's at least the easy parts, but you probably already know much of that.
i didn't! thank you for spelling that out. :-)
i guess the alternative is to just go figure out exactly the wasm targets where
std
will panic? maybe that also will be a good approximation for "the web"?
I can try to help out here: rustc --print target-list | rg '^wasm'
wasm32-unknown-emscripten
- I don't know much about this but it runs on the web and is cfg(unix)
. I don't think the usage of this in Rust is that high but "do what unix does" is generally the answer here and emscripten is reponsible for polyfilling everythingwasm32-unknown-unknown
- most web users will use this. This is, however, a catch-all target for "just generate a wasm binary where the standard library does nothing". This is the target though where SystemTime::new
panics for sure so you'll want to avoid it.wasm32-wasi
and wasm32-wasip1
- There's not much you can do here but provide knobs to users. By default there's no way to support Jiff on these targets. Opt-in-wise I'm sure there's at least some folks running these targets on the web. That may mean that you could even use js-sys
/ web-sys
here. You could even invent your own names and JS implementations and tell users "when the final wasm imports this hook it up to this JS". I wouldn't recommend that though and I'd recommend instead doing "not supported" things on these targetswasm32-wasip2
- this is where wasi-clocks
comes in. There's also the idea of "webidl.wit" somewhere around which is the idea of basically giving this target access to all Web apis by converting WebIDL to WIT. That has the downside though of if Jiff used that then it would only work on the web, not Wasmtime for example. Generally here the answer is say that it's not supported until wasi-clocks
is improved.wasm32-wasi-threads
- probably not used on the web, but some mad lad is probably working on it somewhere? Generally not a widely used targetwasm64-unknown-unknown
- same as 32-bit abovebut on the other, it seems bad to require an opt-in to make
Timestamp::now()
not panic.
I definitely agree with this, and I wish I had a better answer for you :(
I suppose most of what I'm saying here is convincing you that this may be the "least bad" solution for now.
For the least amount of end-user friction I would recommend unconditionally using js-sys/web-sys on cfg(all(target_family = "wasm", not(target_os = "wasi")))
that'll bite someone someday but it'll probably help more people in the meantime
@Alex Crichton These answers are mostly for "get the current tz", right?
right yeah, and then dealing with a few other big problems:
gotya, understood. the other competing pressure here, unfortunately, is that existing datetime libraries will "just work," so an opt-in will likely be a point of confusion for users migrating. even crates like [getrandom
seem to assume that wasm{32,64}-unknown-unknown
implies "it's on the web."] :-( although based on what you've told me, i do agree with you at least in principle that it seems like the least bad way to go about it. otherwise one is making assumptions that may not be true.
I'd follow community precedent there and not my own opinions
gotya
My personal opinion is that retroactively I think wasm32-unknown-unknown == web
was a mistake
but you're right that it's pretty embedded nowadays
yeah that makes sense as an opinion
this has actually be super duper helpful. and i'm glad i wasn't way off the mark. because something smelled amiss when i noticed that pretty much everyone did wasm integration just a little differently.
I think realistically 99% of users of wasm32-unknown-unknown are on the web and the 1% can probably work through various compilation features/gates/flags to get their use case sorted if necessary
yeah one of the major issues with web support is it's largely defined by wasm-bindgen
, but there's no like wasm32-wbindgen
target in the rust compiler (nor do I think there should be one)
Maybe a default "wasm-unknown-means-web" feature?
yeah Lann that's sort of what I'm thinking, but I wouldn't add that unless anyone actually asks for it
Alternatively what rust should perhaps do is add a wasm32-web
target with target_os = "web"
and it looks and behaves exactly like wasm32-unknown-unknown
except for the target_os = "web"
that would solve this once and for all, but cest la vie
okay, so i did a little more digging, specifically into getrandom
, and i think they are actually very well aligned with you @Alex Crichton. specifically, they have a js
feature that is disabled by default, and when enabled, _only_ adds dependencies js-sys
and wasm-bindgen
on the wasm{32,64}-unknown-unknown
targets. apparently there are some uses of wasm32-unknown-unknown
that are non-web related, specifically, coming from the Cosmopolitan folks i think?
in any case, it seems like the getrandom
maintainers also think there should be something like a wasm32-unknown-browser
target.
given this, i think i'm going to copy getrandom
's approach which is actually i think just about the same as what you suggested @Alex Crichton! i had just misunderstood what getrandom
was doing.
(but there are definitely other crates that are perhaps not behaving as nicely.)
This is a little off topic, but I would caution against using "browser" or "web" to mean "JS runtime": node is very widely used, and most anything that will run on the web will also run in node.
Last updated: Dec 23 2024 at 12:05 UTC