-
Notifications
You must be signed in to change notification settings - Fork 60
Determine how to express JS dependencies in Rust crates #36
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
Comments
i think, if possible, all 3 would be extremely useful. i would prioritize them:
with 1 being basically required, 2 a nice to have, and 3 is a stretch goal. mostly because if we can do 1 that is a work around for 2 and 3 until we get to them :). 2 is slightly prioritized over 3 because it also can function as a type of work around for 3 (separate JS files can always be published as packages if you really need to or set it up so they already exist on the host) |
There's also JS generated by wasm-bindgen which isn't present in the crate but, after the wasm-bindgen step in the pipeline, might as well have been since it's all just ESMs that import and are imported by the .wasm module. |
I'd like to have some design work here going on in parallel with @ashleygwilliams's work on the npm publication side, if possible. Is anyone particularly interested in taking on the design questions here? |
Since I have the most experience with this one (as I've implemented it already in I can think of many ways we might want to do this, but one fairly important usecase is inline JavaScript. (See So, very roughly, I think something like this would make sense:
This would provide a minimal API surface based on which stuff like Of course there is also the unresolved elephant-in-the-room in the form of TypeScript, which we also might or might not want to support. If there would be a rough consensus that something like this is acceptable I would be willing to maybe write a full RFC. |
@koute I agree with almost everything you said, I just want to touch on a couple points:
Why does it need to generate a custom section? Isn't generating a normal wasm import good enough? I imagine that the way it would work is that when you use the The
TypeScript is JavaScript. Specifically it's a strict superset of JavaScript with erased static types, and the static types do not affect the runtime at all[1], so the types are purely used at develop-time for the sake of the programmer. TypeScript is compiled down to a combination of In other words, whatever support Rust gets for JavaScript should automatically work for TypeScript as well, so we can treat them as being the same thing. What would be useful is to have a program that can take a TypeScript Of course a program like that will only be approximate at best, because TypeScript's type system is extremely seriously unsound.
|
Yes, that's also a valid alternative. You could also have Rust generate a
Although the Personally I would lean towards the custom section approach, but I'm curious what others think about it.
Yes, that's precisely the point, however without any mechanism to say "arg #n is of typescript type X" the generated snippets would be - effectively - untyped if you'd want to include it in a TS project. |
But you said the procedural macro will accept a snippet of JavaScript code, so it's already not target-agnostic. I believe the target-agnostic way of including outside code is to use Actually, would that procedural macro even need to be included in rustc? Couldn't you write a procedural macro that simply compiles down to
I think it should be an error to use the
Are you suggesting that there will be a WebAssembly linker that can only link WebAssembly modules together (it cannot link JavaScript modules), but it somehow understands the custom section so it can generate the appropriate JavaScript code?
Yes, but why is that a problem? TypeScript already handles untyped JavaScript perfectly fine (in fact that's one of its biggest selling points), and I don't see any benefit to typing the JavaScript snippets anyways, because they will be using WebAssembly types, so from TypeScript's perspective they will always be accepting type |
In this case it would accept a snippet of JavaScript code, but it might have just as well accept something else. (And anyway - verifying that the snippet passed is in fact valid JS is out-of-scope of what Rust itself should do, I think.)
That is a great question. I think that you can put In general the point of this wouldn't necessarily be making it work (if you use
What I proposed wouldn't be a
I don't know what are the plans are for linking multiple
I don't know - you tell me. (: I'm just saying that it might be worth consideration, somehow, for when WASM starts supporting richer types than raw numerics. But I agree that this probably isn't super important for snippets meant to be used by a given crate internally. |
In a recent discussion one point that came up specifically about "coming from JS provided directly with the crate" is that we should strive to avoid moving output files on the filesystem. The reason why also led me to thinking that declaring dependencies on npm is also tricky! The rationale, as I understood it, for not moving files on the filesystem was primarily related to preserving ES6 import paths. That makes sense to me as well in the sense of let's say we've got something like: // src/lib.rs
#[wasm_module = "./foo.js"]
extern {
fn foo();
} // src/foo.js
import { bar } from './bar.js';
export function foo() {
bar();
} // src/bar.js
export function bar() {} If the |
I absolutely agree, which is why I suggested using
Yes, this is a tricky problem (PureScript also has this problem, and they decided that it wasn't worth it to fix it, much to my disappointment). There's only three solutions:
I'm personally in favor of solution 3 (moving the files but preserving the order). This has the benefit that dynamic |
There will be a huge pile of JS files, that we need to move around. Even when we specify selected As far as I understand, the bindgen will generate a file that will hold both the import and the exports (
|
Are you sure? My understanding is that we only need to bundle up the JS files which are included with the Rust crate. Npm files will be handled in a later bundling stage (unrelated to rustc). So the number of JS files should be pretty small. I imagine most Rust crates will have 0 JS files, some Rust crates will have 1 JS file, and it should be rare to have a Rust crate with more than 2 JS files in it. And in any case, why is it a problem to have many JS files? If the linker can handle 2 files, then it should be able to handle infinite files (within memory limits). |
Moving JS files will break its relative dependencies right ? Linkers can handle them, But I am not sure when there are circular deps. Instead of moving the JS, does it makes sense to point these files, this will not break any existing libs. |
That's why I said that it needs to maintain the relative ordering of the files, to prevent breaking relative dependencies.
Any ES6 linker/bundler must handle circular dependencies, it is mandated by the ECMAScript spec. So that's a given. When I said "linker" I meant the Just to be clear, we are discussing how to handle JS dependencies with the Rust compiler and the In this case, my suggestion is that when compiling a Rust crate, the Rust compiler will simply grab all the It doesn't need to parse the JS, it doesn't need to understand JS imports, it is just moving files around, nothing else. So circular dependencies will work just fine. Relative imports will work just fine. Even dynamic
The JS files are spread across multiple crates and folders, and npm requires that all of the files are contained within a single root folder, so we have to move the files no matter what. Theoretically, if Cargo changed the way that it fetches and extracts crates, it might be able to avoid moving the Moving the files really isn't a big deal at all. Package managers and compilers are constantly shifting files around: both npm and yarn move tens of thousands of files for a single As an optimization, it might make sense to use hard links rather than copying the files, but that's an internal implementation detail which can be optimized later (from the user's perspective it should have the same behavior either way). |
As discussed in today's WG meeting, we'd like to have a fleshed out RFC accepted for expressing npm dependencies by the Rust 2018 Release Candidate in 6 weeks: 2018-09-13. |
closing this in favor of the RFC rustwasm/rfcs#4 |
As part of the overall packaging pipeline, we will need a way within Rust to express JS dependencies. This happens in two parts:
extern
.This issue is about the second step, supplying the JS. There are at least three sources for the JS imports we want to consider:
Let's discuss which of these options we want to support, and how to express them on the Rust side.
The text was updated successfully, but these errors were encountered: