-
Notifications
You must be signed in to change notification settings - Fork 60
npm packaging requirements #34
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
Is "files" field really necessary here? |
@chicoxyzzy No, the Instead of using |
Below is a fairly idiomatic (relative to webassembly/design/BinaryEncoding.md) binary encoding of the above JSON schema (with my arbitrary choice of That being said, I wonder whether it's better to simply stick the (UTF-8-encoded bytes of the) JSON blob literally as the payload of the custom section. Then extracting this from a given
Thoughts? I'm actually inclined toward the latter... @alexcrichton ? npm package custom sectionAs a custom section,
string
|
Heh yeah I'd be totally ok going with just raw JSON here in the custom sections. One point I'd want to clarify though, where do we think this'll happen? Depending on what happens we may not necessarily want the whole schema in a section of the wasm executable, but I'd wanna gut check my thinking. Our eventual end state would be something along the lines of:
Does that sound right? If so I think the only parts we'd need from the wasm blob which may affect In that sense I was thinking that the wasm cusotm sections would be engineered to be concatenateable where each crate would have an optional custom section listing its "custom js" or npm dependencies, and the linker would naturally binary-concatenate all these sections into one when producing the final output. I may be confused though! |
Am I missing something? Why are we talking about inserting
And linking all the npm dependencies together should probably be the responsibility of a bundler like Webpack or Parcel, not Rust. |
Just to check: in the case where we have multiple crates with individual package.json files, it's not enough to simply concatenate their contents; we need to apply a "semver constraint intersection" to "flatten" into a coherent final set of dependencies. Is your idea that this flattening would take place within the publication tool, which would read out a bunch of separate package.json custom sections and flatten them? @Pauan I believe the main rationale for using custom sections to store this data is that we will then be able to avoid a lot of special-case tooling, e.g. when linking crates. Even the npm publication tool is expected to be language-agnostic; each compiler will produce a custom section for dependencies in the form the tool expects. It's not the bundler's job, because this all needs to happen prior to publishing to npm. That is, we need to determine a package.json for publication, well before a bundler is involved. |
I don't think the compiler (or cargo) should get involved in choosing javascript package managers. There isn't just npm, there are also other package managers for javascript. This should definitely be a separate thing, and it should be also possible to turn it off completely for the case you don't want to publish on npm but use the wasm file directly, especially if you want to use it without using any bundler or similar. |
@est31 That's the plan. The idea is just to have a mechanism for recording data into custom sections for consumption by various tools. |
Oh sure, of course! I was mostly referring to the literal binary representation where the linker (I'd assume at least) would just bytewise concatenate similarly named sections from each module into one at the end. In that sense raw JSON may not work as they're not byte-wise concatenatable but a binary form with lengths and such should work. In other words the tool which is taking a wasm file and generating a package.json needs to basically iterate over the requests each of the inputs to the final wasm module had, but after this iteration it'd for sure do the resolution like you're mentioning. |
@alexcrichton Great, that's exactly what I hoped! Sounds very clean. |
I'm sorry, I'm still not understanding, could you elaborate some more? My understanding is that this is how the process should work: Let's say somebody wants to write some Rust code and then create a
Okay, great, they're done! Now, somebody else wants to consume that For the sake of this example, let's assume that they want to consume that
And that's it, everything should Just Work(tm). All of the packaging, bundling, and linking is done by external tools (npm and Webpack/Parcel/etc.). I think this is the only way that Rust can seamlessly work with npm. The only thing that rustc needs to do is that when you use What if you don't want to use This linking is handled entirely by rustc / llvm, it's just the normal workflow that Rust programmers are currently using. You can then publish a single Or perhaps rustc could support a sort of "dynamic linking" where it creates multiple But in any case, if you want to use (or publish) a WebAssembly module, you'll have to use the Is my above understanding correct, or do you have something different in mind? |
By the way, what I said above is assuming Rust has no built-in npm integration. If we wanted to integrate npm (and I think we should), then I imagine this is how it would work: If somebody wants to write some Rust code and publish it as the npm package
And they're done! When they run
All of this is an implementation detail of Cargo, so the user doesn't (and shouldn't!) need to worry about it. The user simply needs to use When consuming an npm package in Rust, they would follow these steps:
And they're done! When they specify
Once again, this is all internal implementation details that the user shouldn't need to know about. Fundamentally, it's doing the same steps that I described in my previous post, except that those steps have been integrated into Cargo so that it's easier for the programmer to use. Things get trickier when a Rust package
If you don't want to integrate this functionality directly into Cargo, we could make a separate third-party Why am I suggesting to use There are a wide variety of packages on npm: JavaScript code, TypeScript code, WebAssembly created with C++, WebAssembly created with Rust, hand-written WebAssembly, JavaScript code importing WebAssembly code, WebAssembly code importing JavaScript code, code intended for the browser only, code intended for Node only, code that works with the browser or Node, code that relies upon quirky behavior of npm, code that relies upon quirky behavior of Webpack, code that injects JSON/CSS/HTML into the final bundle, code which is dynamically imported at runtime (code-splitting), code which uses Webpack plugins, code which relies upon multiple different versions of npm packages existing simultaneously, etc. Bundlers (such as Webpack or Parcel) have been designed to deal with this complexity, they are the de-facto standard in the npm/JavaScript communities. They handle all of the above situations (and more!). Trying to replicate that behavior in rustc/Cargo is simply not practically viable. Even just trying to replicate npm's package version resolution mechanism is very tricky (people have tried). |
@Pauan Thanks for elaborating your thoughts! FWIW, I actually think we are all largely in agreement here, and there's just a bit of context that's missing re: what's being spelled out in this issue. First, and most important: did you read and understand the pipeline diagram? That's the clearest documentation we currently have for the intended pipeline here, and I think it addresses many of your concerns. But let me also try to explain things in text form. First off, we very much want to let npm and the bundlers do their work. The goal of this issue and the related one on expressing imports is just to figure out how to tell npm, and ultimately the bundlers, the information they need to know to do this work. We envision that process happening in two steps:
The use of custom sections is motivated by decoupling, in two ways:
Finally, a bit of broader context: @ashleygwilliams is coming from the npm perspective -- she works at npm -- and we've been discussing the above with the bundlers (we met with Parcel recently). Hopefully that helps clear some of this up! |
I did see that image, but it's quite large and requires both horizontal and vertical scrolling, so it was hard to read. I have read it more thoroughly now, it does help some.
So let me just verify that I'm understanding you correctly. Let's say you create a Rust project which uses multiple Rust crates. Each Rust crate might have a In addition, when Then you run a separate tool which will read the Is my understanding correct? If so, then I completely agree with the proposal, it makes perfect sense now.
Indeed, I am also coming at it from the npm perspective, because I am a long-time JavaScript and npm user. That's why the suggestion of using WebAssembly custom sections seemed odd to me, since I thought that the custom sections would be included in the npm package. But now I understand that the custom sections are simply an implementation detail, not something that is exposed to the programmer: the programmer uses
Yes it does clear it up, thanks a lot! |
we are tracking this in the wasm-pack repo and it has already shipped ;) |
moving this out of #5 because that's got a lot of discussion that's not quite on this topic.
to package up wasm for npm, we'll need these things for a package.json:
there's other metadata such a repo, author, contributors, that we may also want to consider, but the above is what is needed for bare minimum packaging. for more info: https://docs.npmjs.com/files/package.json
The text was updated successfully, but these errors were encountered: