Skip to content

[esm-integration] Allow JS library symbols to be exported #24061

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

Merged
merged 1 commit into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/jsifier.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions src/modules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
2 changes: 2 additions & 0 deletions test/js_optimizer/JSDCE-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions test/js_optimizer/JSDCE.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'))

Expand Down
12 changes: 10 additions & 2 deletions tools/acorn-optimizer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
11 changes: 9 additions & 2 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down