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

Using JS Module inside Webpack Project #700

Closed
rylev opened this issue Aug 14, 2018 · 23 comments
Closed

Using JS Module inside Webpack Project #700

rylev opened this issue Aug 14, 2018 · 23 comments

Comments

@rylev
Copy link
Contributor

rylev commented Aug 14, 2018

This is probably a webpack issue, but I wanted to confirm here.

Using a wasm-bindgen I built a library that I want to include as a dependency in another webpack based project. I added a package.json file to the output from wasm-bindgen and set the generated js file as the main file. Finally, I set the directory where my generated files and this package.json are located as the location in my webpack project's package.json.

Inside of my webpack project I import this library using the async import() since wasm file's can't be imported synchronously. However, I still get the error:

WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:

I'm not sure why I'm getting this issue as I am using an async import() to import my wasm-bindgen generated lib. Any ideas? Does this seem like a webpack issue to you?

@xtuc
Copy link
Member

xtuc commented Aug 14, 2018


Could you please share you code here?

@rylev
Copy link
Contributor Author

rylev commented Aug 14, 2018

@xtuc I think I wasn't clear. I am using the import("../wasm-bindgen-thing") syntax and never importing the wasm-bindgen-thing using the import x from "wasm-bindgen-thing" syntax.

@rylev
Copy link
Contributor Author

rylev commented Aug 14, 2018

If I reduce my webpack project down to just import('../../../wasm-bindgen-thing').then(module => console.log(module)) where the wasm-bindgen-thing is just the straight output from wasm-bindgen, I get the same error.

@rylev
Copy link
Contributor Author

rylev commented Aug 14, 2018

Main project - src/index.ts:

import('../../dmg-01-js/pkg/dmg_01_js').then(dmg => console.log(dmg))

dmg_01_js:

import * as wasm from './dmg_01_js_bg';
function foo() {
    wasm.add(0,0)
}

webpack config:

module.exports = {
    entry: "./src/index.tsx",
    output: {
        filename: "cpu.js",
      path: __dirname + "/dist",
      // Export this as a library that can be accessed from plain JS
    },

    // Enable sourcemaps for debugging webpack's output.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: [".ts", ".tsx", ".js", ".json", ".wasm"]
    },
    mode: 'development',

    module: {
        rules: [
            // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
        ]
    },

};

@xtuc
Copy link
Member

xtuc commented Aug 14, 2018

Since the index uses a dynamic import, your bundle is splited and everything can be synchronous then. The example you posted seems fine to me, I'm just wondering if TypeScript would transform the import() to something else? could you please try with JS?

Also we are currently working on a better Webpack integration, see rustwasm/rust-webpack-template#15. It would be great if you can make any feedback on it.

@rylev
Copy link
Contributor Author

rylev commented Aug 14, 2018

@xtuc you might be right. I switched to js and it worked. I can try to find out what the typescript loader is doing

@xtuc
Copy link
Member

xtuc commented Aug 14, 2018

Yeah that would be very helpful for us

@MarcAntoine-Arnaud
Copy link

Thanks for your exchanges !
On my side I have tried to build a dependency, and to load it in Angular i-using typescript too.

I found something interesting:
In tsconfig.json it's possible to exclude some filetype/filename to prevent the module wrapping made by typescript.
I have seen that with debugging wasm loader which load a bad header (not containing .asm... but module = ...)

So after that I have add

"excluded" : ["**/*.wasm"]

And remove any loader in webpack. So now it will load "raw" files.
I still to have some issues, but it seems the right way !

@xtuc @rylev what do you think about that ?

@alexcrichton
Copy link
Contributor

This issue has been stale for a bit and I think it's largely about webpack issues so I'm going to close it here on this repo, but if there's wasm-bindgen issues please let us know!

@patientplatypus
Copy link

I am also getting this error:

 ERROR  Failed to compile with 1 errors                                                                                                                                                                                           3:07:46 PM

 error  in ./zenMiner/pkg/zenMiner_bg.wasm

WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
* multi (webpack)-dev-server/client?http://192.168.0.2:8081/sockjs-node (webpack)/hot/dev-server.js ./src/main.js --> ./src/main.js --> ./src/routes/index.js --> ./src/components/screens/Buy.vue --> ./src/components/screens/Buy.vue?vue&type=script&lang=js& --> ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options!./src/components/screens/Buy.vue?vue&type=script&lang=js& --> ./zenMiner/pkg/zenMiner.js --> ./zenMiner/pkg/zenMiner_bg.wasm
* ... --> ./zenMiner/pkg/zenMiner.js --> ./zenMiner/pkg/zenMiner_bg.wasm --> ./zenMiner/pkg/zenMiner.js --> ./zenMiner/pkg/zenMiner_bg.wasm
* ... --> ./src/main.js --> ./src/App.vue --> ./src/App.vue?vue&type=script&lang=js& --> ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& --> ./src/components/screens/Buy.vue --> ./src/components/screens/Buy.vue?vue&type=script&lang=js& --> ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options!./src/components/screens/Buy.vue?vue&type=script&lang=js& --> ./zenMiner/pkg/zenMiner.js --> ./zenMiner/pkg/zenMiner_bg.wasm

If this is a 'webpack issue' that means that people can't use Rust wasm in popular webpack based libraries such as React and Vue.js. This would seem to be a big deal and rather than merit closing the issue, I think it probably should be addressed. Thank you.

@rylev
Copy link
Contributor Author

rylev commented Sep 9, 2018

For the record, the way I currently work around this is by having one JavaScript file that exposes a function that simply imports the wasm module. This file is built using a babel loader and is not touched by the TypeScript compiler. I then can include that JavaScript file in my TypeScript.

As I've said before, this seems to be an issue with the TypeScript compiler - I'm not sure exactly what it's doing, but it seems to be messing up how imports work.

@patientplatypus it doesn't seem like you're using TypeScript but having the same issue. Are you using the import(WASM_FILE).then(module => /* use module here */) syntax?

@emk
Copy link

emk commented Oct 3, 2018

I've posted the pieces for a pure-TypeScript soluton on issue #43 using "module": "esNext" and Webpack.

@xtuc
Copy link
Member

xtuc commented Oct 3, 2018

@emk thanks! Would you mind adding it to our Readme for future users?

@emk
Copy link

emk commented Oct 3, 2018

@xtuc It might be a good idea to turn this into a fully-working example project, hook it up to CI as part of #922, and then add instructions to the README with a link to the actual working project. Otherwise, I fear that's it's too easy to leave out steps or to regress. Webpack + TypeScript + WebAssembly can be pretty fragile.

I'd be happy to take a shot at this sometime this coming weekend.

@xtuc
Copy link
Member

xtuc commented Oct 3, 2018

Yes, that's a good point. Should we commit a tsc configuration in the template? Could you please send a PR :)

@emk
Copy link

emk commented Oct 3, 2018

@xtuc It would be possible to update the template to use TypeScript, but it would involve the following changes:

  1. Convert the template's js/index.js to TypeScript.
  2. Update webpack.config.js to include ts-loader.
  3. Add a tsconfig.json file.
  4. Make sure that TypeScript can find the $CRATE.d.ts file, even when using wasm-pack and/or VS Code, so that everything hooks up nicely.

Would we really want to do (1)? Or would it be better to have a separate template for TypeScript projects?

There's already a rust-parcel-template project. Maybe we might want to add a rust-webpack-typescript-template project? The integration between wasm-bindgen and TypeScript is really slick once it's set up, and likely to be of interest to Rust programmers.

@sandromario
Copy link

sandromario commented Dec 28, 2018

Hi, I'm running into this problem too, but I'm a beginner and don't know where to start, sorry. Could someone help me please?

My workflow is very simple, as follows:

  1. I ran through the official "book" tutorial (https://rustwasm.github.io/book/).
  2. I've successfully run wasm-pack and npm run build, so the .wasm files and an example node module which uses the Rust files have been created successfully. No problems on that front.
  3. I've written my own Rust code, and I've recompiled using wasm-pack.
  4. I now want to use my Rust .wasm files in a different Webpack-based JS project, let's say it's in ~/my_js_code.

What do I need to do? I don't want to publish to an npm registry or anything. The "npm link" method, which worked in the "book" example, gave me the error described above:

ERROR in ../my-rust-project/pkg/my_rust_project_bg.wasm
WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
* ./src/test.js --> ../my-rust-project/pkg/my_rust_project.js --> ../my-rust-project/pkg/my_rust_project_bg.wasm
* ... --> ../my-rust-project/pkg/my_rust_project.js --> ../my-rust-project/pkg/my_rust_project_bg.wasm --> ../my-rust-project/pkg/my_rust_project.js --> ../my-rust-project/pkg/my_rust_project_bg.wasm

I then tried to follow your explanations above and have now managed to import the module like so:
import("../my-rust-project/pkg");

Questions:

  1. Now what do I do with this? How can I call my exported functions?
  2. Why do I now need a dynamic import ìmport(), although it wasn't needed in the book example?

@alexcrichton
Copy link
Contributor

@sandromario I think you're running into webpack/webpack#6615 where wasm instantiation is required to be asynchronous, which makes it a bit more difficult to expose and use at the bundler level, leading to this current limitation

@Kingsearch
Copy link

Kingsearch commented Aug 31, 2019

@rylev

require.ensure([], function () {
       const rust = require("../pkg")
       rust
           .run()
           .then(c => {
               console.log(c)
           })
   })

@sc-laurence
Copy link

I know this is an old issue but cant seem to see what the solution is?
I have posted a issue in a different repo
rustwasm/create-wasm-app#146 but think this might be more closely related? can I get a hand with this please.

@michaeljones
Copy link

For others experiencing this, I had this line in a typescript file:

const stitch = await import("../pkg/index.js").catch(console.error);

Which was triggering the WebAssembly module is included in initial chunk error.

I created a javascript file called import_wasm.js with the following contents:

export function import_wasm() {
    return import("../pkg/index.js");
}

And then added an import at the top of the original typescript file:

import { import_wasm } from "./import_wasm";

And changed the original line like so:

-    const stitch = await import("../pkg/index.js").catch(console.error);
+    const stitch = await import_wasm().catch(console.error);

I also had to add:

declare module "*import_wasm" {
    export const import_wasm: any;
}

To a types.d.ts file where the typescript compiler would find it. (I'm not sure what the * in the module name was necessary but it didn't work with import_wasm or ./import_wasm - I imagine there is a better solution though.)

And that resolved my issue.

@murtyjones
Copy link

Just wanted to share a similar solution building off of @michaeljones's excellent answer. I wanted to ensure that my wasm module would be typed, which the below solution does:

index.ts

import { import_wasm } from './import_wasm';

(async () => {
  const module = await import_wasm();
  module.greet();
})();

import_wasm.js

export function import_wasm() {
    return import("../pkg/index.js");
}

import_wasm.d.ts

export const import_wasm: () => Promise<typeof import('../pkg/index')>;

@noxue
Copy link

noxue commented Oct 5, 2022

if you are deploy to nginx , just set the mime-type,like this:

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  types {
    application/wasm wasm;
    application/octet-stream clr;
    application/octet-stream pdb;
    application/font-woff woff;
    application/font-woff woff2;
  }

https://platform.uno/docs/articles/how-to-host-a-webassembly-app.html

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

No branches or pull requests