Skip to content

Commit 1cb178b

Browse files
authored
[esm-integration] Allow modules to be runnable even without main (#24321)
Also, ensure the output format defaults to `MJS` in esm integration and modularize=instance modes.
1 parent 7666902 commit 1cb178b

File tree

3 files changed

+21
-12
lines changed

3 files changed

+21
-12
lines changed

.circleci/config.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,6 @@ jobs:
802802
core0.test_pthread_join_and_asyncify
803803
core0.test_async_ccall_promise_jspi*
804804
core0.test_cubescript_jspi
805-
esm_integration.test_fs_js_api*
806805
instance.test_hello_world
807806
instance.test_dylink_basics
808807
instance.test_cube2hash*
@@ -812,8 +811,10 @@ jobs:
812811
instance.test_iostream_and_determinism
813812
instance.test_fannkuch
814813
instance.test_fasta
814+
esm_integration.test_fs_js_api*
815815
esm_integration.test_inlinejs3
816816
esm_integration.test_embind_val_basics
817+
esm_integration.test_undefined_main
817818
"
818819
# Run some basic tests with the minimum version of node that we currently
819820
# support in the generated code.

test/core/test_esm_integration.expected.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import * as unused from './hello_world.wasm';
44
export { default, _foo, _main, err, stringToNewUTF8 } from './hello_world.support.mjs';
55

6-
// When run as the main module under node, execute main directly here
6+
// When run as the main module under node, create the module directly. This will
7+
// execute any startup code along with main (if it exists).
78
import init from './hello_world.support.mjs';
89
const isNode = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string' && process.type != 'renderer';
910
if (isNode) {

tools/link.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,11 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
749749
if s in user_settings:
750750
diagnostics.warning('deprecated', f'{s} is deprecated ({reason}). Please open a bug if you have a continuing need for this setting')
751751

752+
# Set the EXPORT_ES6 default early since it affects the setting of the
753+
# default oformat below.
754+
if settings.WASM_ESM_INTEGRATION or settings.MODULARIZE == 'instance':
755+
default_setting('EXPORT_ES6', 1)
756+
752757
# If no output format was specified we try to deduce the format based on
753758
# the output filename extension
754759
if not options.oformat and (options.relocatable or (options.shared and not settings.SIDE_MODULE)):
@@ -766,10 +771,10 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
766771
if not options.oformat:
767772
if settings.SIDE_MODULE or final_suffix == '.wasm':
768773
options.oformat = OFormat.WASM
769-
elif final_suffix == '.mjs':
770-
options.oformat = OFormat.MJS
771774
elif final_suffix == '.html':
772775
options.oformat = OFormat.HTML
776+
elif final_suffix == '.mjs' or settings.EXPORT_ES6:
777+
options.oformat = OFormat.MJS
773778
else:
774779
options.oformat = OFormat.JS
775780

@@ -786,10 +791,11 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
786791

787792
if settings.WASM_ESM_INTEGRATION:
788793
diagnostics.warning('experimental', '-sWASM_ESM_INTEGRATION is still experimental and not yet supported in browsers')
789-
default_setting('EXPORT_ES6', 1)
790794
default_setting('MODULARIZE', 'instance')
791-
if not settings.EXPORT_ES6 or settings.MODULARIZE != 'instance':
792-
exit_with_error('WASM_ESM_INTEGRATION requires EXPORT_ES6 and MODULARIZE=instance')
795+
if options.oformat != OFormat.MJS:
796+
exit_with_error('WASM_ESM_INTEGRATION is only compatible with EM module output format')
797+
if settings.MODULARIZE != 'instance':
798+
exit_with_error('WASM_ESM_INTEGRATION requires MODULARIZE=instance')
793799
if settings.RELOCATABLE:
794800
exit_with_error('WASM_ESM_INTEGRATION is not compatible with dynamic linking')
795801

@@ -806,11 +812,11 @@ def limit_incoming_module_api():
806812
if settings.MODULARIZE == 'instance':
807813
diagnostics.warning('experimental', '-sMODULARIZE=instance is still experimental. Many features may not work or will change.')
808814
if options.oformat != OFormat.MJS:
809-
exit_with_error('emcc: MODULARIZE instance is only compatible with .mjs output files')
815+
exit_with_error('MODULARIZE instance is only compatible with ES module output format')
810816
limit_incoming_module_api()
811817
for s in ['wasmMemory', 'INITIAL_MEMORY']:
812818
if s in settings.INCOMING_MODULE_JS_API:
813-
exit_with_error(f'emcc: {s} cannot be in INCOMING_MODULE_JS_API in MODULARIZE=instance mode')
819+
exit_with_error(f'{s} cannot be in INCOMING_MODULE_JS_API in MODULARIZE=instance mode')
814820

815821
if options.oformat in (OFormat.WASM, OFormat.BARE):
816822
if options.emit_tsd:
@@ -826,7 +832,7 @@ def limit_incoming_module_api():
826832
wasm_target = get_secondary_target(target, '.wasm')
827833

828834
if settings.SAFE_HEAP not in [0, 1, 2]:
829-
exit_with_error('emcc: SAFE_HEAP must be 0, 1 or 2')
835+
exit_with_error('SAFE_HEAP must be 0, 1 or 2')
830836

831837
if not settings.WASM:
832838
# When the user requests non-wasm output, we enable wasm2js. that is,
@@ -2130,9 +2136,10 @@ def create_esm_wrapper(wrapper_file, support_target, wasm_target):
21302136
else:
21312137
wrapper.append(f"export {{ default }} from '{support_url}';")
21322138

2133-
if settings.ENVIRONMENT_MAY_BE_NODE and settings.INVOKE_RUN and settings.EXPECT_MAIN:
2139+
if settings.ENVIRONMENT_MAY_BE_NODE:
21342140
wrapper.append(f'''
2135-
// When run as the main module under node, execute main directly here
2141+
// When run as the main module under node, create the module directly. This will
2142+
// execute any startup code along with main (if it exists).
21362143
import init from '{support_url}';
21372144
const isNode = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string' && process.type != 'renderer';
21382145
if (isNode) {{

0 commit comments

Comments
 (0)