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

Both #326

Closed
wants to merge 4 commits into from
Closed

Both #326

wants to merge 4 commits into from

Conversation

FreeMasen
Copy link
Contributor

This is to address #233

This adds a new flag to the CLI --both, using this flag will allow users to generate libraries that will be usable from both Node.js and compiled with webpack.

@FreeMasen
Copy link
Contributor Author

@fitzgen The one thing that is missing currently from the PR is a new test in the tests module. I have added an example project and updated the .travis.yml to build that project for both browser and node.

I am at a loss as to how to actually test this using the current testing system. The system seems to want to bundle with webpack and then execute in the node environment. When I tried duplicating node with the new flag it was failing to resolve the ./out.js functions.

The goal of this PR is to actually remove the requirement of using webpack when working in a Node.js environment while allowing webpack to correctly bundle the same files for the browser. That being said I am not sure how I should be testing this?

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sending this PR, @FreeMasen

I think that --both is a bit ambiguous. Can we think of something a little more specific?

I'm not super familiar with how JS folks usually support both ES modules and CommonJS at the same time, so I want to get @ashleygwilliams's feedback on this too.

@FreeMasen
Copy link
Contributor Author

One of the things that brought me to this issue was attempting to create this proof of concept when using wasm-pack.

Initially I ended up having to create 2 different packages, one for node.js and one for the browser, otherwise the library wouldn't be usable as a dependency. By implementing these changes in that project I was able to get the same set of files to be usable from either environment. The above link has an examples folder with a project using the parent project as an NPM installed dependency from both environments.

Also, I'll try and come up with a better flag.

@xtuc
Copy link
Member

xtuc commented Jun 26, 2018

With Webpack ESM and CJS interop is transparent (the default export might need the `.default depending on the direction)

@FreeMasen
Copy link
Contributor Author

@xtuc As things stand today, to get a Web Assembly module working in Node (without Experimental ESM turned on) we need to execute the following.

const imports = require('imports.js');
const fs = require('fs');
const bytes = fs.readFileSync('./thing.wasm');
const wasm = WebAssembly.Module(bytes);
const wasmInstance = WebAssembly.Instance(wasmModule, imports);

or something similar. While Webpack does support CJS, it cannot resolve a require('fs') and will fail to compile.

This causes a problem for someone who wants to publish a WebAssembly project to NPM and allow it to be used by other developers. So it is less a issue of ESM vs CJS but the current state of WASM in Node (supprted but not requireable).

@FreeMasen
Copy link
Contributor Author

@fitzgen
Some possible options for the flag could be

  • --dynamic
  • --browser --nodejs
    • both flags
  • --dual-env
  • --hybrid
  • --eval
  • eval-fs
    I am also open to suggestions.

@xtuc
Copy link
Member

xtuc commented Jun 28, 2018

I think we should create a documentation about usage with CJS and ESM on different platforms.

Node

Node itself does not support wasm (see following comments), and it's not related to the module system being used (if CJS or ESM).

With the experimental ESM support I've created a loader that supports wasm, see https://github.com/wasm-tool/node-loader. Otherwise for CJS, as you described, you'll need to load, provide the imports and instantiate the wasm module on your own.

Webpack

Webpack 4 added the support for wasm module and has support for ESM since even longer out of the box. I would recommend to publish an ESM version because it's still compatible with CJS (apart from the default export I mentioned before).

Note that having a webpack loader for wasm-bindgen would be ideal, and i'll do it when I have some time.

About fs, it has nothing to do with the module system used. Webpack can't bundle it because you don't have access to a file system in the browser. You can ask for a pollyfill via the configuration (example https://github.com/wasm-tool/emscripten/blob/master/README.md)

@FreeMasen
Copy link
Contributor Author

Node itself does not support wasm,

I don't understand how this could be true, if I use the WebAssembly global to build my own wasm module, I can use it today. It is exactly what I am doing in the new example I have added in this PR as an example of this working today. Am I misunderstanding something?

@xtuc
Copy link
Member

xtuc commented Jun 28, 2018

Sorry, I was a bit unprecise. Node has support for wasm, of course. What I meant is that there's not integration with the module system or basically it's not "managed". As you demonstrated the loading, imports and instatiation is manual.

@FreeMasen
Copy link
Contributor Author

I understand the resistance for moving forward with this solution. I do think it would be good to provide some solution that works today. I wonder if this might be better applied as an optional post-processing step, similar to wasm2es6js?

@xmclark
Copy link

xmclark commented Aug 25, 2018

So maybe I missed something, but I do not believe there is any issue with having an npm wasm package support both the browser and node.js and we do not need to inline the wasm like with wasm2es6js. package.json has a convention for supporting different targets e.g. browser and node.js. That convention is supported in both webpack and rollup.js.

In a package.json, there are two top level fields called 'main' and 'browser' for the entry point. The main field is typically required, but the browser is optional. The bundlers will look for both, and select the 'browser' field when targeting the browser.

A good example is superagent which is a request library for node.js (and the browser). Check out their package.json. They have a different file loaded when webpack or rollup bundles superagent for the browser.

The wasm load code would be partially duplicated when downloading the package, but only one of them would be run. The wasm, the js shims and any additional js would be common. You get support in both browsers.

@Pauan
Copy link
Contributor

Pauan commented Aug 26, 2018

@xmclark I agree with you, and I believe everything you said is correct.

However, I want to clarify something for the benefit of others:

The wasm load code would be partially duplicated

This duplication only occurs when downloading the npm package: when running the code in Node.js or bundling for the browser there is no duplication.

So there is no downside to the duplication (other than an extremely slightly longer npm download).

This pattern (using the main and browser fields in package.json) is extremely common, it is the idiomatic way to have code which works in both Node.js and the browser.

@alexcrichton
Copy link
Contributor

I'm gonna close this as it's been quiet for quite some time now, but we can of course resubmit/reopen!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants