Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
86d219c
Replace require() with await import() in EXPORT_ES6 shell/runtime files
Mar 3, 2026
c85c69e
Replace require() with library symbols in EXPORT_ES6 library files
Mar 3, 2026
6d7219d
Add test verifying EXPORT_ES6 output contains no require() calls
Mar 9, 2026
ba0aa88
Add bundler integration tests verifying EXPORT_ES6 output has no requ…
Mar 9, 2026
56b9a6d
Fix dbg() to use lazy-initialized node modules for ESM compatibility
Mar 20, 2026
19d4d53
Fix test_environment assertion to handle ESM dynamic imports
Mar 20, 2026
cb5bec6
Fix test_locate_file_abspath_esm to use dynamic import for path module
Mar 23, 2026
79183e0
Add Closure compiler support for ESM dynamic imports
Mar 23, 2026
d6d7268
Add require() polyfill for EM_ASM tests in ESM modes
Mar 23, 2026
7474309
Fix Babel transpile for EXPORT_ES6 by using sourceType module
Apr 1, 2026
5dd4a01
Add dbg_node_fs/dbg_node_utils declarations to shell_minimal.js
Apr 1, 2026
6221db1
Replace require('node:tty') with library symbol in libnoderawfs.js
Apr 1, 2026
23d0a46
Rename nodeChildProcess to child_process per reviewer feedback
Apr 8, 2026
80e0bd5
Revert child_process rename: use nodeChildProcess to avoid Closure ex…
Apr 8, 2026
44f7423
Merge branch 'main' into bw_eliminate_require
vogel76 Apr 8, 2026
b9075a4
Merge branch 'main' into bw_eliminate_require
vogel76 Apr 9, 2026
2c7e271
Merge branch 'main' into bw_eliminate_require
vogel76 Apr 13, 2026
06b07f2
fixup! Add Closure compiler support for ESM dynamic imports
Apr 15, 2026
4311074
fixup! Add require() polyfill for EM_ASM tests in ESM modes
Apr 15, 2026
2642a5d
fixup! Replace require() with library symbols in EXPORT_ES6 library f…
Apr 16, 2026
f9a9bc8
fixup! Replace require() with library symbols in EXPORT_ES6 library f…
Apr 16, 2026
548e32d
fixup! Replace require() with await import() in EXPORT_ES6 shell/runt…
Apr 16, 2026
c62836c
fixup! Replace require() with await import() in EXPORT_ES6 shell/runt…
Apr 16, 2026
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
5 changes: 4 additions & 1 deletion src/lib/libatomic.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,12 @@ addToLibrary({

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

#if ENVIRONMENT_MAY_BE_NODE
emscripten_num_logical_cores__deps: ['$nodeOs'],
#endif
emscripten_num_logical_cores: () =>
#if ENVIRONMENT_MAY_BE_NODE
ENVIRONMENT_IS_NODE ? require('node:os').cpus().length :
ENVIRONMENT_IS_NODE ? nodeOs.cpus().length :
#endif
navigator['hardwareConcurrency'],

Expand Down
8 changes: 6 additions & 2 deletions src/lib/libcore.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ addToLibrary({
},
#endif

#if ENVIRONMENT_MAY_BE_NODE
$nodeOs: "{{{ makeNodeImport('node:os') }}}",
$nodeChildProcess: "{{{ makeNodeImport('node:child_process') }}}",
_emscripten_system__deps: ['$nodeChildProcess'],
#endif
_emscripten_system: (command) => {
#if ENVIRONMENT_MAY_BE_NODE
if (ENVIRONMENT_IS_NODE) {
Expand All @@ -380,8 +385,7 @@ addToLibrary({
var cmdstr = UTF8ToString(command);
if (!cmdstr.length) return 0; // this is what glibc seems to do (shell works test?)

var cp = require('node:child_process');
var ret = cp.spawnSync(cmdstr, [], {shell:true, stdio:'inherit'});
var ret = nodeChildProcess.spawnSync(cmdstr, [], {shell:true, stdio:'inherit'});
Comment thread
vogel76 marked this conversation as resolved.

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

Expand Down
2 changes: 1 addition & 1 deletion src/lib/libnodepath.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// operations. Hence, using `nodePath` should be safe here.

addToLibrary({
$nodePath: "require('node:path')",
$nodePath: "{{{ makeNodeImport('node:path', false) }}}",
$PATH__deps: ['$nodePath'],
$PATH: `{
isAbs: nodePath.isAbsolute,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/libnoderawfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
*/

addToLibrary({
$NODERAWFS__deps: ['$ERRNO_CODES', '$FS', '$NODEFS', '$mmapAlloc', '$FS_modeStringToFlags', '$NODERAWFS_stream_funcs'],
$nodeTTY: "{{{ makeNodeImport('node:tty', false) }}}",
$NODERAWFS__deps: ['$ERRNO_CODES', '$FS', '$NODEFS', '$mmapAlloc', '$FS_modeStringToFlags', '$NODERAWFS_stream_funcs', '$nodeTTY'],
$NODERAWFS__postset: `
if (!ENVIRONMENT_IS_NODE) {
throw new Error("NODERAWFS is currently only supported on Node.js environment.")
}
var nodeTTY = require('node:tty');
function _wrapNodeError(func) {
return (...args) => {
try {
Expand Down
18 changes: 17 additions & 1 deletion src/lib/libsockfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
*/

addToLibrary({
#if ENVIRONMENT_MAY_BE_NODE && EXPORT_ES6
// In ESM mode, require() is not natively available. When SOCKFS is used,
// we need require() to lazily load the 'ws' npm package for WebSocket
// support on Node.js. Set up a createRequire-based polyfill.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we still need createRequire in this case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sync context requires createRequire, can't use await import()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain more here? How/why does libsocksf require "sync context" whereas other places in the codebase don't?

Do we need to update how we use the ws package maybe?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sync context at connect()/listen() is real (sync syscall callbacks across the JS↔Wasm boundary — no await without ASYNCIFY). More importantly, ws is a user-installed peer-dep: many programs link libsockets transitively without ever calling WebSocket ops, so loading ws at init would regress those programs vs. the CJS build. createRequire gives us a sync require() scoped to import.meta.url; the inner await import('node:module') is a cheap Node builtin that can't fail. The actual ws load stays lazy — same behavior as the CJS build. A bigger refactor (async-friendly WS library, or asyncify the socket syscall layer) could remove createRequire, but that's out of scope here.

You can analyze failures by change addressing your request:
2642a5d

$nodeRequire: `ENVIRONMENT_IS_NODE ? (await import('node:module')).createRequire(import.meta.url) : undefined`,
$SOCKFS__deps: ['$FS', '$nodeRequire'],
#else
$SOCKFS__deps: ['$FS'],
#endif
$SOCKFS__postset: () => {
addAtInit('SOCKFS.root = FS.mount(SOCKFS, {}, null);');
},
$SOCKFS__deps: ['$FS'],
$SOCKFS: {
#if expectToReceiveOnModule('websocket')
websocketArgs: {},
Expand Down Expand Up @@ -216,7 +224,11 @@ addToLibrary({
var WebSocketConstructor;
#if ENVIRONMENT_MAY_BE_NODE
if (ENVIRONMENT_IS_NODE) {
#if EXPORT_ES6
WebSocketConstructor = /** @type{(typeof WebSocket)} */(nodeRequire('ws'));
#else
WebSocketConstructor = /** @type{(typeof WebSocket)} */(require('ws'));
#endif
} else
#endif // ENVIRONMENT_MAY_BE_NODE
{
Expand Down Expand Up @@ -522,7 +534,11 @@ addToLibrary({
if (sock.server) {
throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); // already listening
}
#if EXPORT_ES6
var WebSocketServer = nodeRequire('ws').Server;
#else
var WebSocketServer = require('ws').Server;
Comment thread
vogel76 marked this conversation as resolved.
#endif
var host = sock.saddr;
#if SOCKET_DEBUG
dbg(`websocket: listen: ${host}:${sock.sport}`);
Expand Down
11 changes: 9 additions & 2 deletions src/lib/libwasi.js
Original file line number Diff line number Diff line change
Expand Up @@ -569,14 +569,21 @@ var WasiLibrary = {

// random.h

#if ENVIRONMENT_MAY_BE_SHELL
#if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
$nodeCrypto: "{{{ makeNodeImport('node:crypto') }}}",
#endif

#if ENVIRONMENT_MAY_BE_SHELL && ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
$initRandomFill__deps: ['$base64Decode', '$nodeCrypto'],
#elif ENVIRONMENT_MAY_BE_SHELL
$initRandomFill__deps: ['$base64Decode'],
#elif ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
$initRandomFill__deps: ['$nodeCrypto'],
#endif
$initRandomFill: () => {
#if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 190000
// This block is not needed on v19+ since crypto.getRandomValues is builtin
if (ENVIRONMENT_IS_NODE) {
var nodeCrypto = require('node:crypto');
return (view) => nodeCrypto.randomFillSync(view);
}
#endif // ENVIRONMENT_MAY_BE_NODE
Expand Down
5 changes: 4 additions & 1 deletion src/lib/libwasm_worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,12 @@ if (ENVIRONMENT_IS_WASM_WORKER
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': readEmAsmArgs(sigPtr, varargs) });
},

#if ENVIRONMENT_MAY_BE_NODE
emscripten_navigator_hardware_concurrency__deps: ['$nodeOs'],
#endif
emscripten_navigator_hardware_concurrency: () => {
#if ENVIRONMENT_MAY_BE_NODE
if (ENVIRONMENT_IS_NODE) return require('node:os').cpus().length;
if (ENVIRONMENT_IS_NODE) return nodeOs.cpus().length;
#endif
return navigator['hardwareConcurrency'];
},
Expand Down
23 changes: 23 additions & 0 deletions src/parseTools.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,27 @@ function makeModuleReceiveWithVar(localName, moduleName, defaultValue) {
return ret;
}

function makeNodeImport(module, guard = true) {
assert(ENVIRONMENT_MAY_BE_NODE, 'makeNodeImport called when environment can never be node');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have this assert in makeNodeFilePath too maybe?

var expr;
if (EXPORT_ES6) {
expr = `await import(/* webpackIgnore: true */ /* @vite-ignore */ '${module}')`;
Comment thread
vogel76 marked this conversation as resolved.
Outdated
} else {
expr = `require('${module}')`;
}
if (guard) {
return `ENVIRONMENT_IS_NODE ? ${expr} : undefined`;
}
return expr;
}

function makeNodeFilePath(filename) {
if (EXPORT_ES6) {
return `new URL('${filename}', import.meta.url)`;
}
return `__dirname + '/${filename}'`;
}

function makeRemovedFSAssert(fsName) {
assert(ASSERTIONS);
const lower = fsName.toLowerCase();
Expand Down Expand Up @@ -1243,6 +1264,8 @@ addToCompileTimeContext({
makeModuleReceive,
makeModuleReceiveExpr,
makeModuleReceiveWithVar,
makeNodeFilePath,
makeNodeImport,
makeRemovedFSAssert,
makeRetainedCompilerSettings,
makeReturn64,
Expand Down
2 changes: 1 addition & 1 deletion src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ function instantiateSync(file, info) {
var binary = getBinarySync(file);
#if NODE_CODE_CACHING
if (ENVIRONMENT_IS_NODE) {
var v8 = require('node:v8');
var v8 = {{{ makeNodeImport('node:v8', false) }}};
// Include the V8 version in the cache name, so that we don't try to
// load cached code from another version, which fails silently (it seems
// to load ok, but we do actually recompile the binary every time).
Expand Down
13 changes: 7 additions & 6 deletions src/runtime_debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@
var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times

// Used by XXXXX_DEBUG settings to output debug messages.
#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
// dbg_node_fs and dbg_node_utils are declared and initialized in shell.js
// when node modules (fs/utils) become available.
#endif
function dbg(...args) {
if (!runtimeDebug && typeof runtimeDebug != 'undefined') return;
#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
// Avoid using the console for debugging in multi-threaded node applications
// See https://github.com/emscripten-core/emscripten/issues/14804
if (ENVIRONMENT_IS_NODE) {
// TODO(sbc): Unify with err/out implementation in shell.sh.
var fs = require('node:fs');
var utils = require('node:util');
if (ENVIRONMENT_IS_NODE && dbg_node_fs) {
function stringify(a) {
switch (typeof a) {
case 'object': return utils.inspect(a);
case 'object': return dbg_node_utils.inspect(a);
case 'undefined': return 'undefined';
}
return a;
}
fs.writeSync(2, args.map(stringify).join(' ') + '\n');
dbg_node_fs.writeSync(2, args.map(stringify).join(' ') + '\n');
} else
#endif
// TODO(sbc): Make this configurable somehow. Its not always convenient for
Expand Down
29 changes: 14 additions & 15 deletions src/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,9 @@ if (ENVIRONMENT_IS_PTHREAD) {
#endif
#endif

#if ENVIRONMENT_MAY_BE_NODE && (EXPORT_ES6 || PTHREADS || WASM_WORKERS)
#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
if (ENVIRONMENT_IS_NODE) {
#if EXPORT_ES6
// When building an ES module `require` is not normally available.
// We need to use `createRequire()` to construct the require()` function.
const { createRequire } = await import('node:module');
/** @suppress{duplicate} */
var require = createRequire(import.meta.url);
#endif

#if PTHREADS || WASM_WORKERS
var worker_threads = require('node:worker_threads');
var worker_threads = {{{ makeNodeImport('node:worker_threads', false) }}};
globalThis.Worker = worker_threads.Worker;
ENVIRONMENT_IS_WORKER = !worker_threads.isMainThread;
#if PTHREADS
Expand All @@ -128,7 +119,6 @@ if (ENVIRONMENT_IS_NODE) {
#if WASM_WORKERS
ENVIRONMENT_IS_WASM_WORKER = ENVIRONMENT_IS_WORKER && worker_threads.workerData == 'em-ww'
#endif
#endif // PTHREADS || WASM_WORKERS
}
#endif // ENVIRONMENT_MAY_BE_NODE

Expand Down Expand Up @@ -199,11 +189,13 @@ if (ENVIRONMENT_IS_NODE) {

// These modules will usually be used on Node.js. Load them eagerly to avoid
// the complexity of lazy-loading.
var fs = require('node:fs');
var fs = {{{ makeNodeImport('node:fs', false) }}};

#if EXPORT_ES6
if (_scriptName.startsWith('file:')) {
scriptDirectory = require('node:path').dirname(require('node:url').fileURLToPath(_scriptName)) + '/';
var nodePath = {{{ makeNodeImport('node:path', false) }}};
var nodeUrl = {{{ makeNodeImport('node:url', false) }}};
scriptDirectory = nodePath.dirname(nodeUrl.fileURLToPath(_scriptName)) + '/';
}
#else
scriptDirectory = __dirname + '/';
Expand Down Expand Up @@ -351,10 +343,17 @@ if (!ENVIRONMENT_IS_AUDIO_WORKLET)
var defaultPrint = console.log.bind(console);
var defaultPrintErr = console.error.bind(console);
if (ENVIRONMENT_IS_NODE) {
var utils = require('node:util');
var utils = {{{ makeNodeImport('node:util', false) }}};
var stringify = (a) => typeof a == 'object' ? utils.inspect(a) : a;
defaultPrint = (...args) => fs.writeSync(1, args.map(stringify).join(' ') + '\n');
defaultPrintErr = (...args) => fs.writeSync(2, args.map(stringify).join(' ') + '\n');
#if (ASSERTIONS || RUNTIME_DEBUG || AUTODEBUG) && (PTHREADS || WASM_WORKERS)
// Initialize the lazy-loaded node modules for dbg() now that fs/utils are
// available. Declared here (before runtime_debug.js) to avoid Closure
// Compiler's JSC_REFERENCE_BEFORE_DECLARE warning.
var dbg_node_fs = fs;
var dbg_node_utils = utils;
#endif
}
{{{ makeModuleReceiveWithVar('out', 'print', 'defaultPrint') }}}
{{{ makeModuleReceiveWithVar('err', 'printErr', 'defaultPrintErr') }}}
Expand Down
27 changes: 21 additions & 6 deletions src/shell_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope;

#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
if (ENVIRONMENT_IS_NODE) {
var worker_threads = require('node:worker_threads');
var worker_threads = {{{ makeNodeImport('node:worker_threads', false) }}};
globalThis.Worker = worker_threads.Worker;
ENVIRONMENT_IS_WORKER = !worker_threads.isMainThread;
}
Expand Down Expand Up @@ -104,9 +104,14 @@ if (ENVIRONMENT_IS_NODE && ENVIRONMENT_IS_SHELL) {
var defaultPrint = console.log.bind(console);
var defaultPrintErr = console.error.bind(console);
if (ENVIRONMENT_IS_NODE) {
var fs = require('node:fs');
var fs = {{{ makeNodeImport('node:fs', false) }}};
defaultPrint = (...args) => fs.writeSync(1, args.join(' ') + '\n');
defaultPrintErr = (...args) => fs.writeSync(2, args.join(' ') + '\n');
#if (ASSERTIONS || RUNTIME_DEBUG || AUTODEBUG)
var utils = {{{ makeNodeImport('node:util', false) }}};
var dbg_node_fs = fs;
var dbg_node_utils = utils;
#endif
}
var out = defaultPrint;
var err = defaultPrintErr;
Expand All @@ -115,6 +120,16 @@ var out = (...args) => console.log(...args);
var err = (...args) => console.error(...args);
#endif

#if !PTHREADS && WASM_WORKERS && ENVIRONMENT_MAY_BE_NODE && (ASSERTIONS || RUNTIME_DEBUG || AUTODEBUG)
// Initialize dbg() node module references for WASM_WORKERS without PTHREADS.
// (With PTHREADS these are set in the print setup block above.)
var dbg_node_fs, dbg_node_utils;
if (ENVIRONMENT_IS_NODE) {
dbg_node_fs = {{{ makeNodeImport('node:fs', false) }}};
dbg_node_utils = {{{ makeNodeImport('node:util', false) }}};
}
#endif

// Override this function in a --pre-js file to get a signal for when
// compilation is ready. In that callback, call the function run() to start
// the program.
Expand Down Expand Up @@ -182,13 +197,13 @@ if (!ENVIRONMENT_IS_PTHREAD) {
// Wasm or Wasm2JS loading:

if (ENVIRONMENT_IS_NODE) {
var fs = require('node:fs');
var fs = {{{ makeNodeImport('node:fs', false) }}};
#if WASM == 2
if (globalThis.WebAssembly) Module['wasm'] = fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.wasm');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this code (which uses __dirname) simply not work with EXPORT_EST today?

If not, this seems like maybe a separate fix that we could land in isolation. e.g. Fix for EXPORT_ES6 + MINIMAL_RUNTIME + ???

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The __dirname usage in shell_minimal.js indeed doesn't work with EXPORT_ES6 today — it's the same class of issue as require() not being available in ESM.

The fix uses makeNodeFilePath() which switches between:

  • ESM: new URL('file.wasm', import.meta.url)
  • CJS: __dirname + '/file.wasm'

I kept it in this PR because the changes are on the same lines as the require()makeNodeImport() replacements — splitting them would create merge conflicts between the two PRs for no benefit. But happy to separate if you prefer.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If shell_minimal.js already doesn't work it seems fine to leave it out of this change. shell_minimal.js is not ever used by default, and compatibility with all settings is not important here IMHO.

else eval(fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.wasm.js')+'');
if (globalThis.WebAssembly) Module['wasm'] = fs.readFileSync({{{ makeNodeFilePath(TARGET_BASENAME + '.wasm') }}});
else eval(fs.readFileSync({{{ makeNodeFilePath(TARGET_BASENAME + '.wasm.js') }}})+'');
#else
#if !WASM2JS
Module['wasm'] = fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.wasm');
Module['wasm'] = fs.readFileSync({{{ makeNodeFilePath(TARGET_BASENAME + '.wasm') }}});
#endif
#endif
}
Expand Down
9 changes: 9 additions & 0 deletions test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,12 +596,21 @@ def require_wasm2js(self):
if self.get_setting('WASM_ESM_INTEGRATION'):
self.skipTest('wasm2js is not compatible with WASM_ESM_INTEGRATION')

def is_esm(self):
return self.get_setting('EXPORT_ES6') or self.get_setting('WASM_ESM_INTEGRATION') or self.get_setting('MODULARIZE') == 'instance'

def add_require_polyfill(self):
"""Add a require() polyfill for ESM mode using createRequire (Node 12.2+)."""
if self.is_esm():
self.cflags += ['--pre-js', test_file('require_polyfill.js')]

def setup_nodefs_test(self):
self.require_node()
if self.get_setting('WASMFS'):
# without this the JS setup code in setup_nodefs.js doesn't work
self.set_setting('FORCE_FILESYSTEM')
self.cflags += ['-DNODEFS', '-lnodefs.js', '--pre-js', test_file('setup_nodefs.js'), '-sINCOMING_MODULE_JS_API=onRuntimeInitialized']
self.add_require_polyfill()

def setup_noderawfs_test(self):
self.require_node()
Expand Down
7 changes: 7 additions & 0 deletions test/require_polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Polyfill require() for ESM mode so that EM_ASM/EM_JS code using
// require('fs'), require('path'), etc. works in both CJS and ESM.
// createRequire is available since Node 12.2.0.
if (typeof require === 'undefined') {
var { createRequire } = await import('module');
var require = createRequire(import.meta.url);
}
Loading
Loading