-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Avoid importing Node's modules on demand #17851
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
Avoid importing Node's modules on demand #17851
Conversation
What about in the case of |
We should probably be excluding the |
Can you run |
Ah, @@ -199,7 +199,9 @@ if (ENVIRONMENT_IS_NODE) {
scriptDirectory = __dirname + '/';
}
+#if !SINGLE_FILE
#include "node_shell_read.js"
+#endif
if (process['argv'].length > 1) {
thisProgram = process['argv'][1].replace(/\\/g, '/'); But that will probably break when someone uses
Commit 62b5c25 rebased the codesize tests, it looks like this change saved a few bytes. |
62b5c25
to
fbcd6ea
Compare
... according to https://developers.google.com/closure/compiler/docs/api-tutorial3, Closure Compiler will only do DCE when using the $ echo -e 'int main(void){return 0;}' | emcc -xc -Oz -sSINGLE_FILE --closure=1 -
$ stat --format='%s' a.out.js
6750
$ grep -o '=require("fs")' a.out.js
=require("fs")
$ grep -o '=require("path")' a.out.js
=require("path") (I also tried using In this case, it probably doesn't hurt that these Node modules are imported without being used. Either way, I just modified the PR description and commit. PTAL. |
@kleisauke I was wondering if you wanted any help in pushing this along? I'm waiting on this PR and #17489 so I can submit a fix for #17829. I can probably fix the merge conflicts here if you're busy. |
Remove `requireNodeFS()` in favor of always importing these Node modules. These `require()`'s will always be used on Node.js, except when linking with `-sSINGLE_FILE`. But in that case, `stdin` usage, or using the `-sMAIN_MODULE` and/or `-sNODERAWFS` options would still depend on these imports.
This change was generated using: $ ./test/runner other.*code_size* other.*metadce* --rebase
fbcd6ea
to
217334b
Compare
@rchiodo Just rebased this PR to resolve the merge conflicts. I don't control the merging process as an external contributor. |
I do wonder if folks are going to complain about these imports not being done unconditionally. Maybe we can follow up by somehow making them included only when needed? |
The whole thing does need to be reworked for ES modules anyway... |
Lines 189 to 202 in 84ad56f
We could exclude this for #if !SINGLE_FILE && (!MAIN_MODULE || !NODERAWFS)
#include "node_shell_read.js"
#endif But I think that's a bit fragile, and doesn't cover the use-case when someone reads the Line 115 in 84ad56f
Is |
Yes I agree that For now this seems reasonable, we can revisit later if needed. |
Great! Failures in |
I restarted the failed browser tests. (BTW do you have permission to do that?) |
I do see the rerun button on CircleCI, so I suppose that would work. |
This may have broken Binaryen's emscripten tests, e.g. https://github.com/WebAssembly/binaryen/actions/runs/3101768285/jobs/5023446794 (WebAssembly/binaryen#5071)
Those tests wrap the output into an |
I suggest we revert for now, and add a test for this... I assumed we had a bunch of tests for .mjs modularization, but I guess binaryen must be doing something that none of our tests are.. |
This PR seems to fix binaryen, However, I'm still not sure why the breakage happened. So not sure if we should or should not revert this. |
I think the breakage happend because the use of |
Sorry for causing this breakage. I think this issue is tracked in #11792, i.e. the Prepending: import { createRequire } from 'module';
const require = createRequire(import.meta.url); is probably a feasible solution for now, but eventually we need to solve this in Emscripten. FWIW, wasm-vips is currently doing this post-processing: |
It seems to me that the problem extends to Binaryen.js in browsers. Previously |
I think we should revert this change given that it breaks users of EXPORT_ES6. Previously it seems that not all users of EXPORT_ES6 ran into the issue of (@dcodeIO, this code is all only run if ENVIRONMENT_IS_NODE I think). |
Feel free to revert.
|
I see. If it is behind a feature check still, then I guess the |
It looks like Binaryen already had a workaround for So, perhaps reverting this is not the right way to resolve this. For example, applying this patch: --- a/test/test_other.py
+++ b/test/test_other.py
@@ -234,12 +234,11 @@ class other(RunnerCore):
os.remove(config_path)
def test_emcc_output_mjs(self):
- self.run_process([EMCC, '-o', 'hello_world.mjs', test_file('hello_world.c')])
+ create_file('extern-post.js', 'await Module();')
+ self.run_process([EMCC, '-o', 'hello_world.mjs', test_file('hello_world.c'), '--extern-post-js', 'extern-post.js'])
output = read_file('hello_world.mjs')
self.assertContained('export default Module;', output)
- # TODO(sbc): Test that this is actually runnable. We currently don't have
- # any tests for EXPORT_ES6 but once we do this should be enabled.
- # self.assertContained('hello, world!', self.run_js('hello_world.mjs'))
+ self.assertContained('hello, world!', self.run_js('hello_world.mjs'))
@parameterized({
'': (True, [],), Will cause a runtime error on that |
Indeed, there are additional challenges to make this work in any case. The general picture I've seen is that producing ESM with Emscripten still uses some CommonJS things. where |
If you want to propose a fix, and enable that test that would be fine too. But this issue has been around for a while which makes me think fixing my be non-trivial. Do you want to propose a fix foward? I will this we should revert unless such as fix can be found in the next day or so. |
Thats exactly how the old code worked.. it only used |
Hmm, perhaps Binaryen.js is somewhat special in using ESM + filesystem, while actually not utilizing the filesystem so this issue didn't surface until |
Yes, I believe that binaryen.js actually never uses the filesystem... so when this was on-demand we never reached the error. So this PR can break code that is just pure computation, but happens to be run in node, and happens to be pasted into an Perhaps one solution here is to wrap the require in a Ideally perhaps such pure computational code would have a "none" environment, so it doesn't try to use node APIs. But that's a larger question. |
One could also wrap in |
Overall it looks like the shell code should replace |
It looks like I suppose building with |
Ah, nice,
What is the connection to |
Previously when linking with Long term solution would indeed be that Emscripten emit proper |
Ok, I think I see, thanks @kleisauke For fixing binaryen CI right now, I think we can pin the latest stable version (WebAssembly/binaryen#5077). But we should undo that and resolve this issue before a new emscripten release so users don't get broken. My sense atm is that since top-level await isn't universal yet, perhaps the best options are to either
I'd be ok with either. (Long-term, a "none" environment for pure computational code might be a good idea, and eventually we will be able to use top-level await.) |
Regarding
this is expected when using top-level await in a function. One could say that async function someFunc() {
return await someOtherFunc();
}
await someFunc(); Not necessarily a blocker, as long as all such code is under ones control, but easily leading to extensive refactoring. In Emscripten, I guess this leads to complications if both ESM and CommonJS are targeted, with the ESM one requiring |
See #5062 Also add a require() workaround, see emscripten-core/emscripten#17851
Remove
requireNodeFS()
in favor of always importing these Node modules.These
require()
's will always be used on Node.js, except when linking with-sSINGLE_FILE
. But in that case,stdin
usage, or using the-sMAIN_MODULE
and/or-sNODERAWFS
options would still depend on these imports.Split from: #17849.