diff --git a/src/proxyClient.js b/src/proxyClient.js index 8987bb6cfea6c..f624fa3976148 100644 --- a/src/proxyClient.js +++ b/src/proxyClient.js @@ -18,7 +18,23 @@ #if ENVIRONMENT_MAY_BE_NODE var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string'; if (ENVIRONMENT_IS_NODE) { - global.Worker = require('worker_threads').Worker; + var NodeWorker = require('worker_threads').Worker; + global.Worker = function(url, options) { + // Special handling for `data:` URL argument, to match the behaviour + // of the Web API. + if (typeof url == 'string' && url.startsWith('data:')) { +#if EXPORT_ES6 + // worker_threads always assume data URLs are ES6 modules + url = new URL(url); +#else + // For class modules we decode the data URL and use `eval: true`. + url = Buffer.from(url.split(",")[1], 'base64').toString(); + options ||= {} + options.eval = true; +#endif + } + return new NodeWorker(url, options); + } var Module = Module || {} } else #endif diff --git a/src/shell.js b/src/shell.js index d3a9e43f88d5b..0e44d5625a5bc 100644 --- a/src/shell.js +++ b/src/shell.js @@ -136,8 +136,12 @@ if (ENVIRONMENT_IS_NODE) { // TODO: Swap all `require()`'s with `import()`'s? #if EXPORT_ES6 && ENVIRONMENT_MAY_BE_WEB const { createRequire } = await import('module'); + let dirname = import.meta.url; + if (dirname.startsWith("data:")) { + dirname = '/'; + } /** @suppress{duplicate} */ - var require = createRequire(import.meta.url); + var require = createRequire(dirname); #endif #if PTHREADS || WASM_WORKERS @@ -235,7 +239,9 @@ if (ENVIRONMENT_IS_NODE) { // EXPORT_ES6 + ENVIRONMENT_IS_NODE always requires use of import.meta.url, // since there's no way getting the current absolute path of the module when // support for that is not available. - scriptDirectory = nodePath.dirname(require('url').fileURLToPath(import.meta.url)) + '/'; + if (!import.meta.url.startsWith('data:')) { + scriptDirectory = nodePath.dirname(require('url').fileURLToPath(import.meta.url)) + '/'; + } #else scriptDirectory = __dirname + '/'; #endif diff --git a/test/test_other.py b/test/test_other.py index 6ada5242d9fcf..96abca1e0f27a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -14722,8 +14722,13 @@ def test_standalone_whole_archive(self): self.emcc_args += ['-sSTANDALONE_WASM', '-pthread', '-Wl,--whole-archive', '-lbulkmemory', '-lstandalonewasm', '-Wl,--no-whole-archive'] self.do_runf('hello_world.c') - def test_proxy_to_worker(self): - self.do_runf('hello_world.c', emcc_args=['--proxy-to-worker']) + @parameterized({ + '': ([],), + '_single_file': (['-sSINGLE_FILE'],), + '_single_file_es6': (['-sSINGLE_FILE', '-sEXPORT_ES6', '--extern-post-js', test_file('modularize_post_js.js')],), + }) + def test_proxy_to_worker(self, args): + self.do_runf('hello_world.c', emcc_args=['--proxy-to-worker'] + args) @also_with_standalone_wasm() def test_console_out(self): diff --git a/tools/link.py b/tools/link.py index 1d78303ee5df4..7b14a75e7cf7e 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2501,7 +2501,7 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam var filename = '%s'; if ((',' + window.location.search.substr(1) + ',').indexOf(',noProxy,') < 0) { console.log('running code in a web worker'); -''' % get_subresource_location(proxy_worker_filename)) + worker_js + ''' +''' % get_subresource_location_js(proxy_worker_filename)) + worker_js + ''' } else { console.log('running code on the main thread'); var fileBytes = tryParseAsDataURI(filename); @@ -2569,7 +2569,7 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam // Current browser supports Wasm, proceed with loading the main JS runtime. loadMainJs(); } -''' % (script.inline, get_subresource_location(wasm_target) + '.js') +''' % (script.inline, get_subresource_location_js(wasm_target + '.js')) shell = do_replace(shell, '{{{ SCRIPT }}}', script.replacement()) shell = shell.replace('{{{ SHELL_CSS }}}', utils.read_file(utils.path_from_root('src/shell.css'))) @@ -2645,7 +2645,7 @@ def generate_html(target, options, js_target, target_basename, wasm_target): def generate_worker_js(target, js_target, target_basename): if settings.SINGLE_FILE: # compiler output is embedded as base64 data URL - proxy_worker_filename = get_subresource_location(js_target) + proxy_worker_filename = get_subresource_location_js(js_target) else: # compiler output goes in .worker.js file move_file(js_target, shared.replace_suffix(js_target, get_worker_js_suffix())) @@ -2958,13 +2958,17 @@ def move_file(src, dst): # Returns the subresource location for run-time access -def get_subresource_location(path): +def get_subresource_location(path, mimetype='application/octet-stream'): if settings.SINGLE_FILE: - return 'data:application/octet-stream;base64,' + base64_encode(path) + return f'data:{mimetype};base64,{base64_encode(path)}' else: return os.path.basename(path) +def get_subresource_location_js(path): + return get_subresource_location(path, 'text/javascript') + + @ToolchainProfiler.profile() def package_files(options, target): rtn = []