Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: emscripten-core/emscripten
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: emscripten-core/emscripten
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: vite_pthreads
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Feb 19, 2025

  1. Fix for vite bundling with pthreads enabled

    Replaces #23607
    Fixes: #22394
    sbc100 committed Feb 19, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    1186900 View commit details
Showing with 32 additions and 26 deletions.
  1. +28 −23 src/lib/libpthread.js
  2. +2 −1 test/test_browser.py
  3. +2 −2 test/test_other.py
51 changes: 28 additions & 23 deletions src/lib/libpthread.js
Original file line number Diff line number Diff line change
@@ -29,6 +29,30 @@ globalThis.MAX_PTR = Number((2n ** 64n) - 1n);
#else
globalThis.MAX_PTR = (2 ** 32) - 1
#endif
// Use a macro to avoid duplicating pthread worker options.
// We cannot use normal JS variable since the vite bundler requires that worker
// options be inline.
// See https://github.com/emscripten-core/emscripten/issues/22394
globalThis.pthreadWorkerOptions = `{
#if EXPORT_ES6
'type': 'module',
#endif
#if ENVIRONMENT_MAY_BE_NODE
// This is the way that we signal to the node worker that it is hosting
// a pthread.
'workerData': 'em-pthread',
#endif
#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER
// This is the way that we signal to the Web Worker that it is hosting
// a pthread.
#if ASSERTIONS
'name': 'em-pthread-' + PThread.nextWorkerID,
#else
'name': 'em-pthread',
#endif
#endif
}`;
null
}}}

var LibraryPThread = {
@@ -394,25 +418,6 @@ var LibraryPThread = {
// Creates a new web Worker and places it in the unused worker pool to wait for its use.
allocateUnusedWorker() {
var worker;
var workerOptions = {
#if EXPORT_ES6
'type': 'module',
#endif
#if ENVIRONMENT_MAY_BE_NODE
// This is the way that we signal to the node worker that it is hosting
// a pthread.
'workerData': 'em-pthread',
#endif
#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER
// This is the way that we signal to the Web Worker that it is hosting
// a pthread.
#if ASSERTIONS
'name': 'em-pthread-' + PThread.nextWorkerID,
#else
'name': 'em-pthread',
#endif
#endif
};
#if EXPORT_ES6 && USE_ES6_IMPORT_META
// If we're using module output, use bundler-friendly pattern.
#if PTHREADS_DEBUG
@@ -427,14 +432,14 @@ var LibraryPThread = {
createScriptURL: (ignored) => new URL("{{{ TARGET_JS_NAME }}}", import.meta.url)
}
);
worker = new Worker(p.createScriptURL('ignored'), workerOptions);
worker = new Worker(p.createScriptURL('ignored'), {{{ pthreadWorkerOptions }}});
} else
#endif
// We need to generate the URL with import.meta.url as the base URL of the JS file
// instead of just using new URL(import.meta.url) because bundler's only recognize
// the first case in their bundling step. The latter ends up producing an invalid
// URL to import from the server (e.g., for webpack the file:// path).
worker = new Worker(new URL('{{{ TARGET_JS_NAME }}}', import.meta.url), workerOptions);
worker = new Worker(new URL('{{{ TARGET_JS_NAME }}}', import.meta.url), {{{ pthreadWorkerOptions }}});
#else
var pthreadMainJs = _scriptName;
#if expectToReceiveOnModule('mainScriptUrlOrBlob')
@@ -454,10 +459,10 @@ var LibraryPThread = {
// Use Trusted Types compatible wrappers.
if (typeof trustedTypes != 'undefined' && trustedTypes.createPolicy) {
var p = trustedTypes.createPolicy('emscripten#workerPolicy2', { createScriptURL: (ignored) => pthreadMainJs });
worker = new Worker(p.createScriptURL('ignored'), workerOptions);
worker = new Worker(p.createScriptURL('ignored'), {{{ pthreadWorkerOptions }}});
} else
#endif
worker = new Worker(pthreadMainJs, workerOptions);
worker = new Worker(pthreadMainJs, {{{ pthreadWorkerOptions }}});
#endif // EXPORT_ES6 && USE_ES6_IMPORT_META
PThread.unusedWorkers.push(worker);
},
3 changes: 2 additions & 1 deletion test/test_browser.py
Original file line number Diff line number Diff line change
@@ -5534,10 +5534,11 @@ def test_webpack(self, es6):
shutil.copy('webpack/src/hello.wasm', 'webpack/dist/')
self.run_browser('webpack/dist/index.html', '/report_result?exit:0')

@also_with_threads
def test_vite(self):
shutil.copytree(test_file('vite'), 'vite')
with common.chdir('vite'):
self.compile_btest('hello_world.c', ['-sEXPORT_ES6', '-sEXIT_RUNTIME', '-sMODULARIZE', '-o', 'hello.mjs'])
self.compile_btest('hello_world.c', ['-sEXPORT_ES6', '-sEXIT_RUNTIME', '-sMODULARIZE', '-sENVIRONMENT=web,worker', '-o', 'hello.mjs'])
self.run_process(shared.get_npm_cmd('vite') + ['build'])
self.run_browser('vite/dist/index.html', '/report_result?exit:0')

4 changes: 2 additions & 2 deletions test/test_other.py
Original file line number Diff line number Diff line change
@@ -380,7 +380,7 @@ def test_emcc_output_worker_mjs(self, args):
test_file('hello_world.c')] + args)
src = read_file('subdir/hello_world.mjs')
self.assertContained("new URL('hello_world.wasm', import.meta.url)", src)
self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), workerOptions)", src)
self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), {", src)
self.assertContained('export default Module;', src)
self.assertContained('hello, world!', self.run_js('subdir/hello_world.mjs'))

@@ -391,7 +391,7 @@ def test_emcc_output_worker_mjs_single_file(self):
test_file('hello_world.c'), '-sSINGLE_FILE'])
src = read_file('hello_world.mjs')
self.assertNotContained("new URL('data:", src)
self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), workerOptions)", src)
self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), {", src)
self.assertContained('hello, world!', self.run_js('hello_world.mjs'))

def test_emcc_output_mjs_closure(self):