-
Notifications
You must be signed in to change notification settings - Fork 8
RFC: Add support for local JS snippets in wasm-bindgen #6
Changes from 1 commit
1c57ae8
9fe2a6f
51c09bf
1c3e9ff
b83aabb
6e6eb0a
e6d588a
4d990bb
32952b5
02c4e1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -136,46 +136,59 @@ will import all the emitted JS files with relative imports. | |
|
|
||
| ### Updating `wasm-bindgen` output modes | ||
|
|
||
| The `wasm-bindgen` has a few modes of output generation today. This PR | ||
| proposes repurposing the existing `--browser` flag, deprecating the | ||
| `--no-modules` flag, and canonicalizing the output in three modes. All | ||
| modes will operate as follows: | ||
| The `wasm-bindgen` has a few modes of output generation today. These output | ||
| modes are largely centered around modules vs no modules and how modules are | ||
| defined. This RFC proposes that we move away from this moreso towards | ||
| *environments*, such as node.js-compatible vs browser-compatible code (which | ||
| involves more than only module format). This means that in cases where an | ||
| environment supports multiple module systems, or the module system is optional | ||
| (browsers support es modules and also no modules) `wasm-bindgen` will choose | ||
| what module system it thinks is best as long as it is compatible with that | ||
| environment. | ||
|
|
||
| The current output modes of `wasm-bindgen` are: | ||
|
|
||
| * **Default** - by default `wasm-bindgen` emits output that assumes the wasm | ||
| module itself is an ES module. This will naturally work with custom JS | ||
| snippets that are themselves ES modules, as they'll just be more modules in | ||
| the graph all found in the local output directory. | ||
| the graph all found in the local output directory. This output mode is | ||
| currently only consumable by bundlers like Webpack, the default output cannot | ||
| be loaded in either a web browser or Node.js. | ||
|
|
||
| * **`--no-modules`** - the `--no-modules` flag to `wasm-bindgen` is incompatible | ||
| with ES modules because it's intended to be included via a `<script>` tag | ||
| which is not a module. This mode, like today, will fail to work if upstream | ||
| crates contain local JS snippets. As a result, the `--no-modules` flag will | ||
| essentially be deprecated as a result of this change. | ||
| crates contain local JS snippets. | ||
|
|
||
| * **`--nodejs`** - this flag to `wasm-bindgen` indicates that the output should | ||
| be tailored for Node.js, notably using CommonJS module conventions. This mode | ||
| will, in the immediate term, fail if the crate graph includes any local JS | ||
| snippets. This failure mode is intended to be a temporary measure. Eventually | ||
| it should be relatively trivial with a JS parser in Rust to rewrite ES syntax | ||
| of locally imported JS modules into CommonJS syntax. | ||
| be tailored for Node.js, notably using CommonJS module conventions. In this | ||
| mode `wasm-bindgen` will eventually use a JS parser in Rust to rewrite ES | ||
| syntax of locally imported JS modules into CommonJS syntax. | ||
|
|
||
| * **`--browser`** - currently this flag is the same as the default output mode | ||
| except that the output is tailored slightly for a browser environment (such as | ||
| assuming that `TextEncoder` is ambiently available). This RFC proposes | ||
| assuming that `TextEncoder` is ambiently available). | ||
|
|
||
| This RFC proposes | ||
| repurposing this flag (breaking it) to instead generate an ES module natively | ||
| loadable inside the web browser, but otherwise having a similar interface to | ||
| `--no-modules` today, detailed below. | ||
|
|
||
| In summary, the three modes of output for `wasm-bindgen` will be: | ||
|
|
||
| * Bundler-oriented (no flags passed) intended for consumption by bundlers like | ||
| Webpack which consider the wasm module a full-fledged ES module. | ||
| This RFC proposes rethinking these output modes as follows: | ||
|
|
||
| * Node.js-oriented (`--nodejs`) intended for consumption only in Node.js itself. | ||
| | Target Environment | CLI Flag | Module Format | User Experience | How are Local JS Snippets Loaded? | | ||
| |-------------------------|-------------|---------------|------------------------------------------|----------------------------------------------------------------------------------------------| | ||
| | Node.js without bundler | `--nodejs` | Common.js | `require()` the main JS glue file | Main JS glue file `require()`s crates' local JS snippets. | | ||
| | Web without bundler | `--browser` | ES Modules | `<script>` pointing to main JS glue file, using `type=module` | `import` statements cause additional network requests for crates' local snippets. | | ||
| | Web with bundler | none | ES Modules | `<script>` pointing to main JS glue file | Bundler links crates' local snippets into main JS glue file. No additional network requests except for the `wasm` module itself. | | ||
|
|
||
| * Browser-oriented without a bundler (`--browser`) intended for consumption in | ||
| any web browser supporting JS ES modules that also supports wasm. This mode is | ||
| explicitly not intended to be usable with bundlers like webpack. | ||
| It is notable that browser with and without bundler is almost the same as far | ||
| as `wasm-bindgen` is concerned: the only difference is that if we assume a | ||
| bundler, we can rely on the bundler polyfilling wasm-as-ES-module for us. | ||
| Note the `--browser` here is relatively radically different today and as such | ||
| would be a breaking change. It's thought that the usage of `--browser` is small | ||
| enough that we can get away with this, but feedback is always welcome on this | ||
| point! | ||
|
|
||
| The `--no-modules` flag doesn't really fit any more as the `--browser` use case | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sounds rather strange: old browsers don't support ES6 modules, so we still need So it seems to me that the distinction isn't about "browser" vs "Node", it's about "no modules" vs "ES6 modules" vs "CommonJS modules". It should absolutely be possible to use ES6 modules with Node, and to use "no modules" with either Node or the browsers. So could you explain more about the motivations behind removing "no modules" and assuming that browsers have ES6 support?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'm personally more wary on this, expecially with Node and ES6 modules. AFAIK everyone agrees that ES6 modules should come to node but there hasn't been any consensus or real timeline to getting it added. The current We definitely have two axes here, though. One is Node vs browser environments (like where you get I'm hoping that we can pick a somewhat opinionated set of defaults and support. For example no modules on Node while possible I don't think would have many users. Similar for CommonJS in browsers I'm not really sure what the use case. Along these lines it seems that the --no-modules use case for browsers is becoming less useful and I'm not entirely certain where it'd be used. (I mentioned above as well, but for older browser compat it seems like you'd almost always use a bundler) This definitely isn't a strong motivation for removing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, so your perspective is basically "ES6 modules + bundler" is the replacement for That sounds reasonable to me, though I know some people won't like that. I agree that ES6 modules aren't ready for Node (and won't be anytime soon), I just don't want us to be locked into that sort of decision: we should be able to support ES6 modules in Node eventually (even if not right now). So, as you say, there are really two different axes here: runtime and module. Perhaps you're right and we can condense that down to one axis. Of course if we wanted to be really reductionistic we could only support one output format and rely upon bundlers like Webpack to handle all the intricacies of browser vs Node (some people do indeed use bundlers even on Node).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW I'm thinking we should continue this conversation below |
||
| is intended to subsume that. Note that the this RFC proposes only having the | ||
|
|
@@ -186,12 +199,11 @@ manner as Node.js is (once we're parsing the JS file and rewriting the exports), | |
| but it's proposed here to generally move away from `--no-modules` towards | ||
| `--browser`. | ||
|
|
||
| For some more detail about the `--browser` output, it's intended to look from | ||
| the outside like `--no-modules` does today. When using `--browser` a single | ||
| `wasm_bindgen` function will be exported from the module. This function takes | ||
| either a path to the wasm file or the `WebAssembly.Module` itself, and then it | ||
| returns a promise which resolves to a JS object that has the full wasm-bindgen | ||
| interface on it. | ||
|
|
||
| The `--browser` output is currently considered to export an initialization | ||
| function which, after called and the returned promise is resolved (like | ||
| `--no-modules` today) will cause all exports to work when called. Before the | ||
| promise resolves all exports will throw an error when called. | ||
|
|
||
| ### JS files depending on other JS files | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to support ES6 parsing + concatenation to support this use case, and I think it's worth it to do so.
Perhaps not necessary in the MVP, but shortly after the MVP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true yeah that this can be supported! I ended up realizing that a bit later when writing this and didn't come back to fully update this section.
I'm not certain though that we want to continue to support it even if we add an ES6 parser. I agree that technically we'll be empowered to support it with such a parser, but it's becoming less clear to me at least what the main use case is. It seems like this is largely mostly used for demo purposes which almost always can assume a newer browser anyway. Apart from that if you want browser compatibility then it seems like you almost for sure want a bundler and want to avoid
--no-modules(as the module format is likely the least of the concerns at that point, e.g.TextEncoder)Overall this may be a case where we just need to put more thought into wasm-bindgen's output format. I find it unfortunate that we have to choose from so many options, it feels like we're just inheriting a lot of issues with the existing JS ecosystem and having to deal with them all at once...
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the primary use case of
--no-modulesis for people who want a fast lightweight solution without needing to deal with npm or Webpack or Node.In other words, people with Rust experience who want to avoid the JS ecosystem as much as possible.
There is some merit to that, since npm and Webpack are rather slow (and have a lot of dependencies).
I don't have particularly strong opinions on it, I've comfortably used Webpack for many years (it is slow though).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I'm thinking we should continue this conversation below