Skip to content

Commit 7bf2342

Browse files
authored
Simplify MODULARIZE code to always use async factory function (emscripten-core#24727)
The docs here were wrong. We have the `addRunDependency` system that can delay module's readiness for an arbitrary amount of time, even if async compilation is disabled. This `addRunDependency` system does not exist in `MINUMAL_RUTTIME`, so in some cases we can avoid the ready promise in `MINIMAL_RUNTIME` mode, but that is a pretty subtle distinction that only applies to `MINIMAL_RUNTIME`. Also even in this mode we were still marking the factory function as async (note the lack of `USE_READY_PROMISE` in the existing condition).
1 parent afb59ff commit 7bf2342

File tree

5 files changed

+22
-24
lines changed

5 files changed

+22
-24
lines changed

ChangeLog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ See docs/process.md for more on how version tagging works.
2020

2121
4.0.12 (in development)
2222
-----------------------
23+
- In `-sMODULARIZE` mode the factory function will now always return a promise,
24+
even when `WASM_ASYNC_COMPILATION` is disabled. This is because emscripten
25+
has other features that might also return async module creation (e.g. loading
26+
files over the network, or other users of the `addRunDependency` API). For
27+
consistency and simplicity we now *always* return a promise here. (#24727)
2328
- libcxx, libcxxabi, libunwind, and compiler-rt were updated to LLVM 20.1.8.
2429
(#24757)
2530
- The `fsblkcnt_t` and `fsfilcnt_t` types used by `statfs`/`statvfs` were

site/source/docs/tools_reference/settings_reference.rst

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,14 +1863,9 @@ MODULARIZE
18631863
By default we emit all code in a straightforward way into the output
18641864
.js file. That means that if you load that in a script tag in a web
18651865
page, it will use the global scope. With ``MODULARIZE`` set, we instead emit
1866-
the code wrapped in a function that returns a promise. The promise is
1867-
resolved with the module instance when it is safe to run the compiled code,
1868-
similar to the ``onRuntimeInitialized`` callback. You do not need to use the
1869-
``onRuntimeInitialized`` callback when using ``MODULARIZE``.
1870-
1871-
(If WASM_ASYNC_COMPILATION is off, that is, if compilation is
1872-
*synchronous*, then it would not make sense to return a Promise, and instead
1873-
the Module object itself is returned, which is ready to be used.)
1866+
the code wrapped in an async function. This function returns a promise that
1867+
resolves to a module instance once it is safe to run the compiled code
1868+
(similar to the ``onRuntimeInitialized`` callback).
18741869

18751870
The default name of the function is ``Module``, but can be changed using the
18761871
``EXPORT_NAME`` option. We recommend renaming it to a more typical name for a

src/modularize.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var {{{ EXPORT_NAME }}} = (() => {
1919
// after document.currentScript is gone, so we save it.
2020
// In EXPORT_ES6 mode we can just use 'import.meta.url'.
2121
var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
22-
return {{{ asyncIf(WASM_ASYNC_COMPILATION || (EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE)) }}}function(moduleArg = {}) {
22+
return async function(moduleArg = {}) {
2323
var moduleRtn;
2424

2525
"<<< INNER_JS_CODE >>>"
@@ -30,7 +30,7 @@ var {{{ EXPORT_NAME }}} = (() => {
3030
#else
3131
// When targetting node and ES6 we use `await import ..` in the generated code
3232
// so the outer function needs to be marked as async.
33-
{{{ asyncIf(WASM_ASYNC_COMPILATION || (EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE)) }}}function {{{ EXPORT_NAME }}}(moduleArg = {}) {
33+
async function {{{ EXPORT_NAME }}}(moduleArg = {}) {
3434
var moduleRtn;
3535

3636
"<<< INNER_JS_CODE >>>"

src/settings.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,14 +1257,9 @@ var DETERMINISTIC = false;
12571257
// By default we emit all code in a straightforward way into the output
12581258
// .js file. That means that if you load that in a script tag in a web
12591259
// page, it will use the global scope. With ``MODULARIZE`` set, we instead emit
1260-
// the code wrapped in a function that returns a promise. The promise is
1261-
// resolved with the module instance when it is safe to run the compiled code,
1262-
// similar to the ``onRuntimeInitialized`` callback. You do not need to use the
1263-
// ``onRuntimeInitialized`` callback when using ``MODULARIZE``.
1264-
//
1265-
// (If WASM_ASYNC_COMPILATION is off, that is, if compilation is
1266-
// *synchronous*, then it would not make sense to return a Promise, and instead
1267-
// the Module object itself is returned, which is ready to be used.)
1260+
// the code wrapped in an async function. This function returns a promise that
1261+
// resolves to a module instance once it is safe to run the compiled code
1262+
// (similar to the ``onRuntimeInitialized`` callback).
12681263
//
12691264
// The default name of the function is ``Module``, but can be changed using the
12701265
// ``EXPORT_NAME`` option. We recommend renaming it to a more typical name for a

test/test_other.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7243,16 +7243,19 @@ def test_EXPORT_NAME_with_html(self):
72437243
self.assertContained('error: customizing EXPORT_NAME requires that the HTML be customized to use that name', err)
72447244

72457245
def test_modularize_sync_compilation(self):
7246+
# Verify that, even when WASM_ASYNC_COMPILATION is disabled, the module factory
7247+
# still returns a promise. This behaviour was changed in #24727.
72467248
create_file('post.js', r'''
72477249
console.log('before');
72487250
var result = Module();
72497251
// It should be an object.
72507252
console.log('typeof result: ' + typeof result);
7251-
// And it should have the exports that Module has, showing it is Module in fact.
7252-
console.log('typeof _main: ' + typeof result._main);
7253-
// And it should not be a Promise.
72547253
console.log('typeof result.then: ' + typeof result.then);
7255-
console.log('after');
7254+
result.then((inst) => {
7255+
// And it should have the exports that Module has, showing it is Module in fact.
7256+
console.log('typeof inst._main: ' + typeof inst._main);
7257+
console.log('after');
7258+
});
72567259
''')
72577260
self.run_process([EMCC, test_file('hello_world.c'),
72587261
'-sMODULARIZE',
@@ -7262,8 +7265,8 @@ def test_modularize_sync_compilation(self):
72627265
before
72637266
hello, world!
72647267
typeof result: object
7265-
typeof _main: function
7266-
typeof result.then: undefined
7268+
typeof result.then: function
7269+
typeof inst._main: function
72677270
after
72687271
''', self.run_js('a.out.js'))
72697272

0 commit comments

Comments
 (0)