diff --git a/src/jsifier.mjs b/src/jsifier.mjs index c9f2d207e6460..030e575362771 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -735,6 +735,13 @@ function(${args}) { } contentText = `var ${mangled} = ${snippet};`; } + + if (WASM_ESM_INTEGRATION && (EXPORT_ALL || EXPORTED_FUNCTIONS.has(mangled)) && !isStub) { + // It ESM integration mode we mark JS library symbols are exported at + // the point of declaration. + contentText = 'export ' + contentText; + } + // Relocatable code needs signatures to create proper wrappers. if (sig && RELOCATABLE) { if (!WASM_BIGINT) { diff --git a/src/modules.mjs b/src/modules.mjs index f7b4478f29dde..d058037cc87c0 100644 --- a/src/modules.mjs +++ b/src/modules.mjs @@ -558,6 +558,9 @@ function exportLibrarySymbols() { } function exportJSSymbols() { + // In WASM_ESM_INTEGRATION mode JS library symbols are marked with `export` + // at the point of declaration. + if (WASM_ESM_INTEGRATION) return ''; return exportRuntimeSymbols() + ' ' + exportLibrarySymbols(); } diff --git a/test/js_optimizer/JSDCE-output.js b/test/js_optimizer/JSDCE-output.js index 3bfd04c4e8eab..af06b213d1160 100644 --- a/test/js_optimizer/JSDCE-output.js +++ b/test/js_optimizer/JSDCE-output.js @@ -47,6 +47,8 @@ export default function l(a) { return a + 1; } +export var m = a => a + 1; + (function() { var z = fleefl(); var zz = fleefl(); diff --git a/test/js_optimizer/JSDCE.js b/test/js_optimizer/JSDCE.js index 9c80fa8df5bba..7dc301d2a0d2f 100644 --- a/test/js_optimizer/JSDCE.js +++ b/test/js_optimizer/JSDCE.js @@ -48,6 +48,11 @@ export default function l(a) { return a+1; } +// ES6 exported var +export var m = (a) => { + return a+1; +} + // inner workings (function() { var x; diff --git a/test/test_core.py b/test/test_core.py index 900e9a7d66d6e..3930d231c9bf8 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9568,10 +9568,11 @@ def test_esm_integration(self): # TODO(sbc): WASM_ESM_INTEGRATION doesn't currently work with closure. # self.maybe_closure() self.node_args += ['--experimental-wasm-modules', '--no-warnings'] - self.run_process([EMCC, '-o', 'hello_world.mjs', '-sWASM_ESM_INTEGRATION', '-Wno-experimental', test_file('hello_world_argv.c')] + self.get_emcc_args()) + self.run_process([EMCC, '-o', 'hello_world.mjs', '-sEXPORTED_FUNCTIONS=_main,stringToNewUTF8', '-sWASM_ESM_INTEGRATION', '-Wno-experimental', test_file('hello_world_argv.c')] + self.get_emcc_args()) create_file('runner.mjs', ''' - import init from "./hello_world.mjs"; + import init, { stringToNewUTF8, main } from "./hello_world.mjs"; await init({arguments: ['foo', 'bar']}); + console.log('this is a pointer:', stringToNewUTF8('hello')); ''') self.assertContained('hello, world! (3)', self.run_js('runner.mjs')) diff --git a/tools/acorn-optimizer.mjs b/tools/acorn-optimizer.mjs index 809fa4664a7d6..b8c4a5fc1c11d 100755 --- a/tools/acorn-optimizer.mjs +++ b/tools/acorn-optimizer.mjs @@ -447,8 +447,16 @@ function JSDCE(ast, aggressive) { }, ExportNamedDeclaration(node, c) { if (node.declaration) { - const name = node.declaration.id.name; - ensureData(scopes[scopes.length - 1], name).use = 1; + if (node.declaration.type == 'FunctionDeclaration') { + const name = node.declaration.id.name; + ensureData(scopes[scopes.length - 1], name).use = 1; + } else { + assert(node.declaration.type == 'VariableDeclaration'); + for (const decl of node.declaration.declarations) { + const name = decl.id.name; + ensureData(scopes[scopes.length - 1], name).use = 1; + } + } c(node.declaration); } else { for (const specifier of node.specifiers) { diff --git a/tools/link.py b/tools/link.py index 605f09de3dc42..d9f8d7c7f4845 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2113,12 +2113,16 @@ def create_worker_file(input_file, target_dir, output_file, options): def create_esm_wrapper(wrapper_file, support_target, wasm_target): wasm_exports = [] + js_exports = [] for f in settings.USER_EXPORTS: if f == '_main' and '__main_argc_argv' in settings.WASM_EXPORTS: wasm_exports.append('__main_argc_argv as main') - else: + elif f in settings.WASM_EXPORTS: wasm_exports.append(shared.demangle_c_symbol_name(f)) + else: + js_exports.append(f) wasm_exports = ', '.join(wasm_exports) + js_exports = ', '.join(js_exports) wrapper = [] if wasm_exports: @@ -2131,7 +2135,10 @@ def create_esm_wrapper(wrapper_file, support_target, wasm_target): wrapper.append('// in order to avoid issues with circullr dependencies.') wrapper.append(f"import * as unused from './{settings.WASM_BINARY_FILE}';") support_url = f'./{os.path.basename(support_target)}' - wrapper.append(f"export {{ default }} from '{support_url}';") + if js_exports: + wrapper.append(f"export {{ default, {js_exports} }} from '{support_url}';") + else: + wrapper.append(f"export {{ default }} from '{support_url}';") write_file(wrapper_file, '\n'.join(wrapper) + '\n') # FIXME(sbc): This is a huge hack to rename the imports in the