rustwasm / wasm-bindgen

Facilitating high-level interactions between Wasm modules and JavaScript
https://rustwasm.github.io/docs/wasm-bindgen/
Apache License 2.0
7.82k stars 1.08k forks source link

The direction concerning Typescript #2417

Open 9SMTM6 opened 3 years ago

9SMTM6 commented 3 years ago

I've recently tried to implement a Library with a Rust-Core that can be used from JavaScript or TypeScript, with a proper Typescript API. Unfortunately I've stumbled upon multiple issues where some things are just not possible and some things are not well documented, or you get wrong impressions from the Documentation.

Its also really hard to find a place to document such issues.

When looking at the TypeScript-Support you see a few things in the Wasm-Bindgen Reference. The issue is that many of them seem to be Band-Aids that work for specific solutions but have Issues at large. I.e. the Typescript-Custom-Section doesn't work with external .d.ts Files - not even via std::include_str! despite that returning a static str ref as required, typescript_type only works when importing stuff like objects, but cant handle i.e. js_sys::Function and doesn't even get close to i.e. overriding the type of a method or class/struct.

Also some Typescript Concepts are pretty much impossible to transport, i.e. Unions (i.e. when passing Rust Objects to another polymorphic Rust Function, you need to i.e. come up with a Common wrapper for the Rust types), Generics (totally incompatible with Rust generics, the only way you could maybe get that working is via stringly typing with wasm-bindgen annotations.

If you combine that with Issues wasm-bindgen in general has (i.e. the inability to pass i.e. Arrays of Rust-Objects to Rust functions, more advanced references like std::rc::Rc to Rust Objects) I know at least for the moment I'm better served with writing a seperate Typescript-Wrapper, and JS would certainly also profit from that. Meaning I'd have a Rust Core (i.e. as seperate crates.io package), some Glue-Code in Rust with Wasm-Bindgen (with a dependency on the core package) and some Typescript code (the latter two I could probably combine in one npm-package).

So what do I want with this Issue? I want to know what the plans are, which ultimately would inform how, where and how much I could potentially contribute. Ultimately I'm happy and can work with what Is currently there, but I did expect a bit more from what I saw in the documentation, and would've wasted less time.

So my requests (I may be able to contribute a bit, but I'm unsure how much, and at the very least I'd need contact with other contributers)

1) the documentation needs improvements: More examples and a demonstration/examples of the limits and maybe sometimes alternatives (not just in the Typescript part, but there its especially lacking) 2) I think a guideline on whats reasonable to ask in Issues, where to make these Issues/requests and where you want to go with wasm-bindgen and Typescript is much needed 3) in general some coordination in the Typescript Efforts, as I said a lot of the current solutions feel tacked on

alexcrichton commented 3 years ago

Thanks for the report! I would agree that Typescript is sort of tacked on right-now, many of the features were added after-the-fact and this was never originally intended to be super ambitious about its typescript integration. PRs are always welcome to improve things!

9SMTM6 commented 3 years ago

Would there be a way of direct communication with a few people? I still struggle to get a grasp on what wasm-bindgen is targeting with some of the features, and where it wants to go, depending on that I'd recommend different things in documentation.

Also what I could potentially contribute to the code.

While I'm quite good with Typescript, I'm not all that familiar with Rust, so with some things I just don't know if my thoughts are realistic.

So communicating verbally, especially if supported by I. E. Screen sharing, would be a very good thing with its much faster feedback.

alexcrichton commented 3 years ago

Unfortunately the set of people with deep knowledge of wasm-bindgen is probably just me, but at this time I'm mostly only available through GitHub issues and I can't spend a ton of time redesigning things right now. I can try to help where I can, but I can only do but so much at this time.

9SMTM6 commented 3 years ago

Yes, of course, I'm not asking you to redesign wasm-bindgen, or to handhold me through something like that. Sorry If this is what you thought.

I'm not usually a person that likes being handheld anyways, I'm usually more efficient when I can deal with these things in my own time and on my own design.

I am, not gonna lie, not terribly knowledgable when it comes to FFI and also Rust, but I'm not entirely new to the topic either, I've worked with wasm-bindgen for the private project I wrote about above, and before that I worked with i.e. Cython for Scientific Programming (a way to glue Python and C/C++ together), and I like to imagine that I am quite decent when it comes to Typescript, and I think that I did pick up a good bit of Rust in the meantime too (though the usually great documentation was a big help there). I don't personally know anyone other than me that was intensely worked with Rust, only my Cousin gave it a try, but for his endeavors other languages are a better fit, and while hes brilliant hes not quite as much into these topics as me, at least that's my impression.

I'm no expert, and I've not i.e. gone through the wasm-bindgen Sourcecode. I've read a bit through this, but that's about it, I've not had a reason to do more. I don't intend to revamp the library, I don't have the knowledge and more importantly I lack the time and most likely the energy for such a likely massive undertaking.

No. I think for the moment, If I contribute, I will probably just rework (mostly clarify) some of the documentation I stumbled over, and then I'll consider what else could be done. And I'd certainly be available if i.e. you want some opinion on a potential typescript feature, I don't claim to be an authority without error there, but I like to think that I got a good grasp on most of Typescripts features.

However, to be able to clarify the documentation correctly I need to know If my interpretation of the intended feature is correct. To give an example: With the JS Snippet feature its entirely possible to add additional Javascript to the output of wasm-bindgen thats not needed for the Rust code. I am however under the impression that this is not intended but this feature is mostly supposed to allow for VERY SMALL HELPER CODE thats otherwise awkward/impossible to write directly in Rust, not to be able to add totally seperate JS-Code.

While the documentation makes one strongly suspect this, It does not explicitly argue against the latter usage, so I'm not entirely sure if I actually got your intentions or if I'm wrong, and I wouldn't want to write documentation that doesn't actually fit with your intentions.

On a simular stroke, to consider where I could contribute code that i.e. improves usability with typescript I need to know If what I am planning is actually feasable with appropriate effort or wished for by the other maintainers. Lets look at i.e. my complaint that I'm not able to include external .d.ts files with #[wasm_bindgen(typescript_custom_section)]. I tried to write something like that:

use wasm_bindgen::prelude::*;

#[wasm_bindgen(typescript_custom_section)]
const TS_TYPES2: &'static str = std::include_str!("test.d.ts");

and got this:

error: Expected a string literal to be used with #[wasm_bindgen(typescript_custom_section)].
 --> src\lib.rs:4:1
  |
4 | const TS_TYPES2: &'static str = std::include_str!("test.d.ts");
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Now. It seems to me that this is simply an validation error that should be solvable. But I'm not sure. The attribute as well as std::include_str! are, from what I understand, macros. And from what I've read when looking around Rust does actually unroll macros inside macros, but I just inferred that from somewhere else and without certainty. And a few further questions come up, that I'm not able to answer without having to resort to, frankly, not appropriate effort. I don't want to become a core Rust dev working on the implementation of macros and the likes, at least not now.

Well. Coming back to the #[wasm_bindgen(typescript_custom_section)]-Issue. Given that things work out as I hope, I would be able to write a seperate macro that includes .d.ts files easily. But if they don't I do not want to write that stuff from the ground up, so I would have wasted the time working on the issue, i.e. understanding the code of #[wasm_bindgen(typescript_custom_section)]. I'd prefer not to waste time where nothing can be gained.

So. This was a lot of text already, and I feel like such matters are far easier and more efficient to transport in other ways. Thats why I'd like to speak to, it seems, you, per i.e. Teams, Discord, Jira or whatever floats your boat. Its up to you whether you think It could be worth the effort, maybe you think I'm just full of myself and overestimate my ability, and maybe I am. I'm just gonna send you a Mail with some contact details.

RReverser commented 3 years ago

@9SMTM6 For your include_str! issue - have you considered using import or /// <reference path="..." /> (depending on type of .d.ts) directly in the string literal instead? That should work as you would expect. E.g.:

use wasm_bindgen::prelude::*;

#[wasm_bindgen(typescript_custom_section)]
const TS_TYPES2: &'static str = r#"/// <reference path="test.d.ts" />"#;

or

use wasm_bindgen::prelude::*;

#[wasm_bindgen(typescript_custom_section)]
const TS_TYPES2: &'static str = r#"import { SomeType, OtherType } from 'external-typings';"#;
9SMTM6 commented 3 years ago

@RReverser Thanks! Unfortunately that on its own will not work. But it may be an option for making a macro to include .d.ts files easily.

The typescript compiler tsc is kind of its own bundler as far as types are concerned, and if it sees such a reference it looks up the file and includes the types/imports in its analysis. But as wasm-bindgen isn't using tsc nor understanding the included code on its own, its not aware that for this snippet to work it also needs to include test.d.ts, so that file will not be included in the artifact and the user of the generated code will get errors because tsc cant find the referred file.

Also, not sure on that, but the 2nd syntax might be problematic depending on the settings of tsc regarding imports.

alexcrichton commented 3 years ago

I can try to help out with specific issues/bugs and/or specific feature requests. I generally just don't have time to discuss a larger-scale revamp or "what might the ideal end state of things look like"?

For example the typescript_custom_section issue could perhaps be fixed with a better implementation. Currently the proc-macro itself scrapes the value of the string, when instead we could perhaps have the compiler try to put it in a custom section which is then read after-the-fact by the wasm-bindgen binary. That way it should be able to handle your use case gracefully since the compiler does all the work and we just read what that work was afterwards. I'm not exactly sure what the codegen would look like here though.

9SMTM6 commented 3 years ago

I generally just don't have time to discuss a larger-scale revamp or "what might the ideal end state of things look like"

Maybe not on a global scale, however when it comes closer to the mentioned feature requests and especially documentation I'd really appreciate statements of what was the aim of said feature as far as you are concerned and/or what you consider doing in the future.

Examples

For example the typescript_custom_section issue could perhaps be fixed with a better implementation.

Thanks for the guidance. Tho I'd maybe consider making an entirely new macro for the purpose of including .d.ts files instead, but I guess I'll look into it. Tho as I said I'll concern myself with documentation for starters, the earliest I'll get to start looking into this code will probably be about mid of February. But thats optimistic.

alexcrichton commented 3 years ago

In general anything to do with JS/Rust interop feels like it's in-scope for wasm-bindgen, it's just that some thing are more ambitious than others. Sometimes technical constraints limit what can be done reasonable, but other times it's just that the effort to design something hasn't happened yet. I think all of your examples though would be great to solve.

HHogg commented 1 year ago

👋 I've been using wasm-bindgen for a typescript project, and wasm-bindgen does it's job really well, but the typescript integration is pretty unusable (though I'm not here to complain).

My rust knowledge is still pretty new, and unfortunately I don't have the time to dedicate to an open source project so it's not something I can investigate myself. Just here to mention an idea. https://github.com/1Password/typeshare looks to be pretty good at generating types from Rust. I'm wondering if there's a way wasm-bindgen can use that library to handle the TS part of things so wasm-bindgen can focus on what it does best?