emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.74k stars 3.3k forks source link

ESM: Dynamic import of `module` does not work with Vite v4.3 #19886

Open WolfgangDrescher opened 1 year ago

WolfgangDrescher commented 1 year ago

I have a project that uses Verovio (https://github.com/rism-digital/verovio) which is a music notation engraving library in C++ that uses Emscripten with EXPORT_ES6 to allow using it via JavaScript in the browser. When I build the project with Vite.js I get an error:

Module "module" has been externalized for browser compatibility, imported by "~/node_modules/verovio/dist/verovio-module-hum.mjs". See http://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details

If you follow the link (http://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility) to the docs of Vite, it says:

If the module is imported from a third-party library (that's meant to be used in the browser), it's advised to report the issue to the respective library.

I think this is thrown because of the dynamic import statement import('module'):

https://github.com/emscripten-core/emscripten/blob/bec42dac7873903d09d713963e34020c22a8bd2d/src/shell.js#L194-L202

I guess the dynamic import is used to support ES6? In production mode with Vite everything works fine (the above error message is thrown as a warning), but when you use it development mode Vite is not able to import the Emscripten module because of the dynamic import. Is there a way Emscripten could improve this for a better support with Vite?

Also have a look at https://github.com/vitejs/vite/issues/13530 and https://github.com/nuxt/nuxt/issues/21578 and the reproduction repo: https://stackblitz.com/edit/github-rjaduf?file=src%2Fpages%2FHome.vue

Maybe @kleisauke or @curiousdannii have a better understanding about this than I do?

WolfgangDrescher commented 9 months ago

With Vite 5 this got even more problematic. Here is a reproduction repository: https://stackblitz.com/edit/github-rjaduf-38mdms?file=src%2Fpages%2FHome.vue

Because https://github.com/vitejs/vite/issues/13530 is closed as duplicate please also have a look at https://github.com/vitejs/vite/issues/14169.

Is there any chance we can get rid of the dynamic await import('module') statement in the EXPORT_ES6 build?

Pinging @kleisauke, @curiousdannii, @sbc100 and @RReverser that were involved into the EXPORT_ES6 refactoring and discussion. Sorry for the spam.

sbc100 commented 9 months ago

Looking at the comment around the await import('module') statement it seems that one solution that would avoid importing 'module would be to switch from using require to using await import everywhere.

Would that help in this case? i.e. is its specifically the import of module that is the issue or are dynamic imports in general a problem?

curiousdannii commented 9 months ago

@sbc100 That was the original plan, but it would've required a massive rewrite as none of the rest of the code is designed for async importing. Using createRequire was a clever way of getting things working without needing to rewrite the lot.

This seems like a particular issue with Vite's bundler. It's a shame they don't appear to be interested in fixing it on their end, but maybe there are legitimate reasons why they can't.

@WolfgangDrescher do you need multi environment builds? If you set it to only build for browser that code won't be emitted.

WolfgangDrescher commented 4 months ago

It looks like this specific problem did get resolved since Vite v5.1.1: https://stackblitz.com/edit/github-rjaduf-caswxa?file=package.json

However, a rewrite for asynchronous importing, as suggested by @curiousdannii, would probably be the best long-term solution for Emscripten.

vogel76 commented 3 months ago

We have same problem while developing Hive Blockchain TS communication library. When our package is installed in next application, next.js bundler fails on given import('module'); Maybe you could consider then rewriting parts of such code to await import?