Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm32-unknown-unknown support in non-browser environment #1118

Closed
dustin-rcg opened this issue Oct 30, 2022 · 16 comments · Fixed by #1147
Closed

wasm32-unknown-unknown support in non-browser environment #1118

dustin-rcg opened this issue Oct 30, 2022 · 16 comments · Fixed by #1147
Assignees
Labels
enhancement Improvement of existing features or bugfix k::dependencies Pull requests that update a dependency file rust Related to Rust specifically
Milestone

Comments

@dustin-rcg
Copy link

dustin-rcg commented Oct 30, 2022

When compiling projects targeting wasm32-unknown-unknown, dependencies on wbindgen are emitted in the wasm file.

(import "__wbindgen_placeholder__" "__wbindgen_describe" (func $_ZN12wasm_bindgen19__wbindgen_describe17hd0bb5db14a487f56E (type $t0)))
(import "__wbindgen_placeholder__" "__wbindgen_throw" (func $_ZN12wasm_bindgen16__wbindgen_throw17h1f7ec3f048b25bd4E (type $t10)))
(import "__wbindgen_externref_xform__" "__wbindgen_externref_table_grow" (func $_ZN12wasm_bindgen9externref31__wbindgen_externref_table_grow17h23c6ebadcc732f10E (type $t1)))
(import "__wbindgen_externref_xform__" "__wbindgen_externref_table_set_null" (func $_ZN12wasm_bindgen9externref35__wbindgen_externref_table_set_null17h8f133612ea24d34dE (type $t0)))

In a non-browser environment, these dependencies will not be supported. A non-browser environment is a substantial use case for a graphql server (perhaps more than a browser environment), and should be supported.

I came across this issue in the context of wasmcloud:

[error] Failed to start actor: {:bad_return_value, {:error, "Cannot Instantiate: Link(Import(\"__wbindgen_placeholder__\", \"__wbindgen_describe\", UnknownImport(Function(FunctionType { params: [I32], results: [] }))))"}}

There is a detailed discussion in the wasmcloud Slack on this issue about the time crate.

More info

The feature request for wasm32-uknown-unknown support from four years ago was limited to browsers with offline support. With the more recent developments in non-browser use cases, this should be revisited.

Some versions of dependencies such as time and chrono assume that wasm-bindgen is used, and require js-sys, which is only available in browser environments. Providing proper support for non-browser environments will involve scrutinizing/pinning the dependency versions to ensure they do not suffer from this problem.

Here are some example issues:

Ultimately, it seems like the wasm and rust communities need to define more appropriate build targets to differentiate browser and non-browser targets, but until then, support needs to be gated through dependencies.

@dustin-rcg dustin-rcg changed the title wasm32-unknown-uknown support in non-browser environment wasm32-unknown-unknown support in non-browser environment Oct 30, 2022
@LegNeato
Copy link
Member

Hmmm, not too familiar with the wasm stuff, but we do check in CI: https://github.com/graphql-rust/juniper/blob/master/.github/workflows/ci.yml#L302

@ilslv
Copy link
Member

ilslv commented Oct 31, 2022

@dustin-rcg do you have an example of CI testing wasm builds outside the browser? Or can you roughly describe what would it take?

@dustin-rcg
Copy link
Author

dustin-rcg commented Oct 31, 2022

@LegNeato The issue will not show up in cargo check because it does not validate the dependencies against a particular wasm runtime environment.

@ilslv I can give an example in terms of wasmcloud. The steps would roughly be:

In dev environment:

  1. Install the wasmcloud shell -- cargo install wash-cli
  2. Generate an actor from template -- wash new actor hello --template-name hello
  3. In the actor code, add a reference to the juniper version to be tested. It should be pretty easy to implement handle_request as a simple juniper server with minimal schema using GraphQLRequest#execute.
  4. Assuming in CI we will use a setup similar to this docker-compose, we modify the actor Makefile by changing localhost:5000 to registry:5000, so that the make commands are relative to the local OCI registry host that exists in CI.

In CI build:

  1. Setup the hosts like this docker-compose. Also add WASMCLOUD_OCI_ALLOWED_INSECURE: registry:5000 to the environment of the wasmcloud host (which allows the make start command work with the insecure registry host in a later step).
  2. Include an additional host, i.e. runner, which is based on an image with a rust build environment.
  3. In the Dockerfile for runner you will COPY in the actor source code. RUN make to build the actor. Add WASMCLOUD_CTL_HOST: wasmcloud to the environment for runner so that the wash commands target the wasmcloud host instead of localhost.
  4. In the CI commands for runner, run make push to push the actor into the local OCI registry. Run make start to cause the wasmcloud host to load the actor from the OCI registry and instantiate it.

The make start command is where it fails for me. The wasmcloud host logs contain output like

17:14:47.985 [error] Failed to start actor: {:bad_return_value, {:error, "Cannot Instantiate: Link(Import(\"__wbindgen_placeholder__\", \"__wbindgen_describe\", UnknownImport(Function(FunctionType { params: [I32], results: [] }))))"}}

On the other hand, if these commands succeed, then this should validate the non-browser environment.

You can of course, also validate that the graphql server works by sending a graphql query. This requires a few additional steps to start the HTTP capability provider, link the actor to the provider, and send the HTTP request to the wasmcloud host on the port specified in the link values. Roughly, those commands (for runner) would be:

  1. wash ctl start provider wasmcloud.azurecr.io/httpserver:0.16.2 to start the HTTP capability provider.
  2. wash ctl get hosts --output json to get the wasmcloud host-id
  3. wash ctl get inventory <host-id> --output json to get the actor-id and provider-id.
  4. wash ctl link put <actor-id> <provider-id> wasmcloud:httpserver address=0.0.0.0:8080
  5. curl wasmcloud:8080 <graphql-query>

@LegNeato
Copy link
Member

LegNeato commented Nov 2, 2022

Does the above work with no default features? Curious to know if the issue is only contained to dependencies or it is also in Juniper proper.

@dustin-rcg
Copy link
Author

@LegNeato Yes, I am able to successfully run make start with this dependency: juniper = { version = "0.10", default-features = false }. What are the downsides to excluding the default features?

@dustin-rcg
Copy link
Author

I just realized that I am on an old version of juniper. It seems I was referring to an old version of the juniper book somehow. I will upgrade my project and update this issue accordingly.

@dustin-rcg
Copy link
Author

OK, using juniper 0.15.10, this is the minimum feature set I can get that passes make start:

juniper = { version = "0.15.10", default-features = false, features = [
    "uuid",
    "url",
    "schema-language",
] }

As soon as I add bson and chrono, I have the problem.

@dustin-rcg
Copy link
Author

dustin-rcg commented Nov 3, 2022

OK, It looks like the problem is that juniper depends on an old version of bson that is not properly gating features from chrono. Juniper should use a newer version of bson (current is 2.4.0, but juniper is on ^1.0).

juniper 0.15.10 -> bson ^1.0 = 1.2.4: https://github.com/graphql-rust/juniper/blob/juniper-v0.15.10/juniper/Cargo.toml#L39
bson 1.2.4 -> chrono ^0.4 = 0.4.22 without feature gates: https://github.com/mongodb/bson-rust/blob/v1.2.4/Cargo.toml#L47

This is pulling in the unwanted dependencies js-sys and wasm-bindgen in my Cargo.lock:

[[package]]
name = "chrono"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [
 "iana-time-zone",
 "js-sys",
 "num-integer",
 "num-traits",
 "time 0.1.44",
 "wasm-bindgen",
 "winapi",
]

@dustin-rcg
Copy link
Author

dustin-rcg commented Nov 3, 2022

Looks like this is already fixed in master, so looking forward to the next release!

@dustin-rcg dustin-rcg reopened this Nov 3, 2022
@tyranron tyranron added this to the 0.16.0 milestone Nov 3, 2022
@tyranron
Copy link
Member

tyranron commented Nov 3, 2022

@dustin-rcg could you check this directly from master?

@dustin-rcg
Copy link
Author

dustin-rcg commented Nov 3, 2022

Actually, there is still the problem in master: juniper = { git = "https://github.com/graphql-rust/juniper", branch = "master" }

$ cargo why wasm-bindgen
graphql -> juniper -> bson -> rand -> rand_chacha -> rand_core -> getrandom -> js-sys -> wasm-bindgen
graphql -> juniper -> bson -> rand -> rand_chacha -> rand_core -> getrandom -> wasm-bindgen
graphql -> juniper -> bson -> rand -> rand_core -> getrandom -> js-sys -> wasm-bindgen
graphql -> juniper -> bson -> rand -> rand_core -> getrandom -> wasm-bindgen
graphql -> juniper -> bson -> uuid -> getrandom -> js-sys -> wasm-bindgen
graphql -> juniper -> bson -> uuid -> getrandom -> wasm-bindgen
graphql -> juniper -> getrandom -> js-sys -> wasm-bindgen
graphql -> juniper -> getrandom -> wasm-bindgen
graphql -> juniper -> uuid -> getrandom -> js-sys -> wasm-bindgen
graphql -> juniper -> uuid -> getrandom -> wasm-bindgen
$ cargo why js-sys
graphql -> juniper -> bson -> rand -> rand_chacha -> rand_core -> getrandom -> js-sys
graphql -> juniper -> bson -> rand -> rand_core -> getrandom -> js-sys
graphql -> juniper -> bson -> uuid -> getrandom -> js-sys
graphql -> juniper -> getrandom -> js-sys
graphql -> juniper -> uuid -> getrandom -> js-sys

@LegNeato
Copy link
Member

LegNeato commented Nov 4, 2022

@LegNeato
Copy link
Member

LegNeato commented Nov 4, 2022

Here is how getrandom controls:

https://github.com/rust-random/getrandom/blob/master/Cargo.toml#L23

@LegNeato
Copy link
Member

LegNeato commented Nov 8, 2022

Likely blocked on rust-random/getrandom#319

@LegNeato
Copy link
Member

LegNeato commented Nov 8, 2022

Yet more info / another example of a library requiring getrandom and wanting to support this: briansmith/ring#1546

@tyranron tyranron self-assigned this Feb 27, 2023
@tyranron tyranron added enhancement Improvement of existing features or bugfix k::dependencies Pull requests that update a dependency file rust Related to Rust specifically labels Feb 27, 2023
tyranron added a commit that referenced this issue Feb 28, 2023
- gate `js-sys` and `wasm-bindgen` behind `js` Cargo feature
@tyranron
Copy link
Member

tyranron commented Feb 28, 2023

@dustin-rcg getrandom crate doesn't support building for wasm32-unknown-unknown target without enabling js feature at the moment. So you won't be able to use the crates, dependent on it, in the environment without js-sys support. At the moment, these are uuid, bson, time and chrono crates in juniper. All are feature-gated. If you exclude them, you should be OK now.

juniper = { git = "https://github.com/graphql-rust/juniper", branch = "master", default-features = false }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvement of existing features or bugfix k::dependencies Pull requests that update a dependency file rust Related to Rust specifically
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants