Skip to content

Use mainScriptUrlOrBlob if present under EXPORT_ES6 #23890

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
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
9 changes: 9 additions & 0 deletions src/lib/libpthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,15 @@ var LibraryPThread = {
var p = trustedTypes.createPolicy('emscripten#workerPolicy1', { createScriptURL: (ignored) => import.meta.url });
worker = new Worker(p.createScriptURL('ignored'), {{{ pthreadWorkerOptions }}});
} else
#endif
#if expectToReceiveOnModule('mainScriptUrlOrBlob')
if (Module['mainScriptUrlOrBlob']) {
var pthreadMainJs = Module['mainScriptUrlOrBlob'];
if (typeof pthreadMainJs != 'string') {
pthreadMainJs = URL.createObjectURL(pthreadMainJs);
}
worker = new Worker(pthreadMainJs, {{{ 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,28 +147,6 @@
};
</script>

<script>

function download(url) {
return fetch(url).then((rsp) => rsp.blob());
}

function addToDom(scriptCodeBlob) {
return new Promise((resolve, reject) => {
var script = document.createElement('script');
var objectUrl = URL.createObjectURL(scriptCodeBlob);
script.src = objectUrl;
script.onload = () => {
Module['mainScriptUrlOrBlob'] = scriptCodeBlob;
URL.revokeObjectURL(objectUrl);
resolve();
}
document.body.appendChild(script);
});
}

download('hello_thread_with_blob_url.js').then(addToDom);

</script>
<script type="module" src="loader.mjs"></script>
</body>
</html>
47 changes: 42 additions & 5 deletions test/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4756,18 +4756,55 @@ def test_pthread_growth(self, emcc_args):
def test_pthread_reltime(self):
self.btest_exit('pthread/test_pthread_reltime.cpp', emcc_args=['-pthread', '-sPTHREAD_POOL_SIZE'])

# Tests that it is possible to load the main .js file of the application manually via a Blob URL,
# Tests that it is possible to load the main .js file of the application manually via mainScriptUrlOrBlob,
# and still use pthreads.
def test_load_js_from_blob_with_pthreads(self):
@parameterized({
'blob': (False, True),
'url': (False, False),
'blob_es6': (True, True),
'url_es6': (True, False),
})
def test_mainScriptUrlOrBlob(self, es6, use_blob):
# TODO: enable this with wasm, currently pthreads/atomics have limitations
self.set_setting('EXIT_RUNTIME')
js_name = 'hello_thread_with_loader.%s' % ('mjs' if es6 else 'js')
if es6:
self.emcc_args += ['-sEXPORT_ES6']
if es6 and use_blob:
create_file('loader.mjs', '''
Module['locateFile'] = (path,_prefix) => path;
let blob = await (await fetch('hello_thread_with_loader.mjs')).blob();
Module['mainScriptUrlOrBlob'] = blob;
(await import(URL.createObjectURL(blob))).default(Module);
''')
elif use_blob:
create_file('loader.mjs', '''
let blob = await (await fetch('hello_thread_with_loader.js')).blob();
Module['mainScriptUrlOrBlob'] = blob;
var script = document.createElement('script');
script.src = URL.createObjectURL(blob);
document.body.appendChild(script);
''')
elif es6:
create_file('loader.mjs', '''
Module['mainScriptUrlOrBlob'] = 'hello_thread_with_loader.mjs';
(await import('./hello_thread_with_loader.mjs')).default(Module);
''')
else:
create_file('loader.mjs', '''
var script = document.createElement('script');
Module['mainScriptUrlOrBlob'] = 'hello_thread_with_loader.js';
script.src = Module['mainScriptUrlOrBlob'];
document.body.appendChild(script);
''')

self.compile_btest('pthread/hello_thread.c', ['-pthread', '-o', 'out.js'], reporting=Reporting.JS_ONLY)

# Now run the test with the JS file renamed and with its content
# stored in Module['mainScriptUrlOrBlob'].
shutil.move('out.js', 'hello_thread_with_blob_url.js')
shutil.copy(test_file('pthread/main_js_as_blob_loader.html'), 'hello_thread_with_blob_url.html')
self.run_browser('hello_thread_with_blob_url.html', '/report_result?exit:0')
shutil.move('out.js', js_name)
shutil.copy(test_file('pthread/main_js_with_loader.html'), 'hello_thread_with_loader.html')
self.run_browser('hello_thread_with_loader.html', '/report_result?exit:0')

# Tests that SINGLE_FILE works as intended in generated HTML (with and without Worker)
@also_with_proxying
Expand Down
29 changes: 20 additions & 9 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -15865,15 +15865,26 @@ def test_rollup(self):
def test_rlimit(self):
self.do_other_test('test_rlimit.c', emcc_args=['-O1'])

def test_mainScriptUrlOrBlob(self):
@parameterized({
'': (False,),
'es6': (True,),
})
def test_mainScriptUrlOrBlob(self, es6):
ext = "js"
args = []
if es6:
ext = "mjs"
args = ['-sEXPORT_ES6', '--extern-post-js', test_file('modularize_post_js.js')]
outfile = ('a.out.%s' % ext)
# Use `foo.js` instead of the current script name when creating new threads
create_file('pre.js', 'Module = { mainScriptUrlOrBlob: "./foo.js" }')
self.run_process([EMCC, test_file('hello_world.c'), '-sEXIT_RUNTIME', '-sPROXY_TO_PTHREAD', '-pthread', '--pre-js=pre.js'])
create_file('pre.js', 'Module = { mainScriptUrlOrBlob: "./foo.%s" }' % ext)

# First run without foo.js present to verify that the pthread creation fails
err = self.run_js('a.out.js', assert_returncode=NON_ZERO)
self.assertContained('Cannot find module.*foo.js', err, regex=True)
self.run_process([EMCC, test_file('hello_world.c'), '-sEXIT_RUNTIME', '-sPROXY_TO_PTHREAD', '-pthread', '--pre-js=pre.js', '-o', outfile] + args)

# First run without foo.[m]js present to verify that the pthread creation fails
err = self.run_js(outfile, assert_returncode=NON_ZERO)
self.assertContained('Cannot find module.*foo\\.', err, regex=True)

# Now create foo.js and the program should run as expected.
shutil.copy('a.out.js', 'foo.js')
self.assertContained('hello, world', self.run_js('a.out.js'))
# Now create foo.[m]js and the program should run as expected.
shutil.copy(outfile, ('foo.%s' % ext))
self.assertContained('hello, world', self.run_js(outfile))