Skip to content

Commit d5af780

Browse files
Bartek Wronaclaude
andcommitted
Replace require() with library symbols in EXPORT_ES6 library files
Library functions run in synchronous context where await is unavailable. Define top-level library symbols that use await import() at module init time, then reference them via __deps from synchronous functions. - Add libnode_imports.js with shared $nodeOs symbol, register in modules.mjs when EXPORT_ES6 is enabled. - libatomic.js, libwasm_worker.js: Use $nodeOs for os.cpus().length instead of require('node:os'). - libwasi.js: Define $nodeCrypto for crypto.randomFillSync in $initRandomFill. Combine conditional __deps to avoid override. - libcore.js: Define $nodeChildProcess for _emscripten_system. - libnodepath.js: Switch $nodePath initializer to await import(). - libsockfs.js: Define $nodeWs ((await import('ws')).default) for WebSocket constructor in connect() and Server in listen(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 40cecec commit d5af780

8 files changed

Lines changed: 74 additions & 1 deletion

File tree

src/lib/libatomic.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,16 @@ addToLibrary({
159159

160160
emscripten_has_threading_support: () => !!globalThis.SharedArrayBuffer,
161161

162+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE
163+
emscripten_num_logical_cores__deps: ['$nodeOs'],
164+
#endif
162165
emscripten_num_logical_cores: () =>
163166
#if ENVIRONMENT_MAY_BE_NODE
167+
#if EXPORT_ES6
168+
ENVIRONMENT_IS_NODE ? nodeOs.cpus().length :
169+
#else
164170
ENVIRONMENT_IS_NODE ? require('node:os').cpus().length :
171+
#endif
165172
#endif
166173
navigator['hardwareConcurrency'],
167174
});

src/lib/libcore.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ addToLibrary({
343343
},
344344
#endif
345345

346+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE
347+
$nodeChildProcess: "ENVIRONMENT_IS_NODE ? await import('node:child_process') : undefined",
348+
_emscripten_system__deps: ['$nodeChildProcess'],
349+
#endif
346350
_emscripten_system: (command) => {
347351
#if ENVIRONMENT_MAY_BE_NODE
348352
if (ENVIRONMENT_IS_NODE) {
@@ -351,7 +355,11 @@ addToLibrary({
351355
var cmdstr = UTF8ToString(command);
352356
if (!cmdstr.length) return 0; // this is what glibc seems to do (shell works test?)
353357

358+
#if EXPORT_ES6
359+
var cp = nodeChildProcess;
360+
#else
354361
var cp = require('node:child_process');
362+
#endif
355363
var ret = cp.spawnSync(cmdstr, [], {shell:true, stdio:'inherit'});
356364

357365
var _W_EXITCODE = (ret, sig) => ((ret) << 8 | (sig));

src/lib/libnode_imports.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* @license
3+
* Copyright 2025 The Emscripten Authors
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
// Shared Node.js module imports for use by library functions when EXPORT_ES6
8+
// is enabled. These are initialized at module top level (async context) so
9+
// they can use `await import()`, and then referenced by synchronous library
10+
// functions via __deps.
11+
12+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE
13+
addToLibrary({
14+
$nodeOs: "ENVIRONMENT_IS_NODE ? await import('node:os') : undefined",
15+
});
16+
#endif

src/lib/libnodepath.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
// operations. Hence, using `nodePath` should be safe here.
1313

1414
addToLibrary({
15+
#if EXPORT_ES6
16+
$nodePath: "await import('node:path')",
17+
#else
1518
$nodePath: "require('node:path')",
19+
#endif
1620
$PATH__deps: ['$nodePath'],
1721
$PATH: `{
1822
isAbs: nodePath.isAbsolute,

src/lib/libsockfs.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@
55
*/
66

77
addToLibrary({
8+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE
9+
$nodeWs: "ENVIRONMENT_IS_NODE ? (await import('ws')).default : undefined",
10+
#endif
811
$SOCKFS__postset: () => {
912
addAtInit('SOCKFS.root = FS.mount(SOCKFS, {}, null);');
1013
},
14+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE
15+
$SOCKFS__deps: ['$FS', '$nodeWs'],
16+
#else
1117
$SOCKFS__deps: ['$FS'],
18+
#endif
1219
$SOCKFS: {
1320
#if expectToReceiveOnModule('websocket')
1421
websocketArgs: {},
@@ -216,7 +223,11 @@ addToLibrary({
216223
var WebSocketConstructor;
217224
#if ENVIRONMENT_MAY_BE_NODE
218225
if (ENVIRONMENT_IS_NODE) {
226+
#if EXPORT_ES6
227+
WebSocketConstructor = /** @type{(typeof WebSocket)} */(nodeWs);
228+
#else
219229
WebSocketConstructor = /** @type{(typeof WebSocket)} */(require('ws'));
230+
#endif
220231
} else
221232
#endif // ENVIRONMENT_MAY_BE_NODE
222233
{
@@ -522,7 +533,11 @@ addToLibrary({
522533
if (sock.server) {
523534
throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); // already listening
524535
}
536+
#if EXPORT_ES6
537+
var WebSocketServer = nodeWs.Server;
538+
#else
525539
var WebSocketServer = require('ws').Server;
540+
#endif
526541
var host = sock.saddr;
527542
#if SOCKET_DEBUG
528543
dbg(`websocket: listen: ${host}:${sock.sport}`);

src/lib/libwasi.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,15 +569,27 @@ var WasiLibrary = {
569569

570570
// random.h
571571

572-
#if ENVIRONMENT_MAY_BE_SHELL
572+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
573+
$nodeCrypto: "ENVIRONMENT_IS_NODE ? await import('node:crypto') : undefined",
574+
#endif
575+
576+
#if ENVIRONMENT_MAY_BE_SHELL && EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
577+
$initRandomFill__deps: ['$base64Decode', '$nodeCrypto'],
578+
#elif ENVIRONMENT_MAY_BE_SHELL
573579
$initRandomFill__deps: ['$base64Decode'],
580+
#elif EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
581+
$initRandomFill__deps: ['$nodeCrypto'],
574582
#endif
575583
$initRandomFill: () => {
576584
#if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
577585
// This block is not needed on v19+ since crypto.getRandomValues is builtin
578586
if (ENVIRONMENT_IS_NODE) {
587+
#if EXPORT_ES6
588+
return (view) => nodeCrypto.randomFillSync(view);
589+
#else
579590
var nodeCrypto = require('node:crypto');
580591
return (view) => nodeCrypto.randomFillSync(view);
592+
#endif
581593
}
582594
#endif // ENVIRONMENT_MAY_BE_NODE
583595

src/lib/libwasm_worker.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,16 @@ if (ENVIRONMENT_IS_WASM_WORKER
289289
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': readEmAsmArgs(sigPtr, varargs) });
290290
},
291291

292+
#if EXPORT_ES6 && ENVIRONMENT_MAY_BE_NODE
293+
emscripten_navigator_hardware_concurrency__deps: ['$nodeOs'],
294+
#endif
292295
emscripten_navigator_hardware_concurrency: () => {
293296
#if ENVIRONMENT_MAY_BE_NODE
297+
#if EXPORT_ES6
298+
if (ENVIRONMENT_IS_NODE) return nodeOs.cpus().length;
299+
#else
294300
if (ENVIRONMENT_IS_NODE) return require('node:os').cpus().length;
301+
#endif
295302
#endif
296303
return navigator['hardwareConcurrency'];
297304
},

src/modules.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ function calculateLibraries() {
166166
libraries.push('libatomic.js');
167167
}
168168

169+
if (EXPORT_ES6) {
170+
libraries.push('libnode_imports.js');
171+
}
172+
169173
if (MAX_WEBGL_VERSION >= 2) {
170174
// libwebgl2.js must be included only after libwebgl.js, so if we are
171175
// about to include libwebgl2.js, first squeeze in libwebgl.js.

0 commit comments

Comments
 (0)