Skip to content

Commit 7802705

Browse files
buu700kripken
authored andcommitted
SINGLE_FILE html and worker fixes + tests (#5736)
Fix some broken cases, and make SINGLE_FILE embed everything in the html when emitting html
1 parent 68fb8ae commit 7802705

File tree

3 files changed

+69
-34
lines changed

3 files changed

+69
-34
lines changed

emcc.py

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,16 +2413,16 @@ def generate_html(target, options, js_target, target_basename,
24132413
asm_mods = []
24142414

24152415
if options.proxy_to_worker:
2416-
proxy_worker_filename = shared.Settings.PROXY_TO_WORKER_FILENAME or target_basename
2416+
proxy_worker_filename = (shared.Settings.PROXY_TO_WORKER_FILENAME or target_basename) + '.js'
24172417
worker_js = worker_js_script(proxy_worker_filename)
2418-
script.inline = '''
2418+
script.inline = ('''
2419+
var filename = '%s';
24192420
if ((',' + window.location.search.substr(1) + ',').indexOf(',noProxy,') < 0) {
24202421
console.log('running code in a web worker');
2421-
''' + worker_js + '''
2422+
''' % shared.JS.get_subresource_location(proxy_worker_filename)) + worker_js + '''
24222423
} else {
24232424
// note: no support for code mods (PRECISE_F32==2)
24242425
console.log('running code on the main thread');
2425-
var filename = '%s';
24262426
var fileBytes = tryParseAsDataURI(filename);
24272427
var script = document.createElement('script');
24282428
if (fileBytes) {
@@ -2432,7 +2432,7 @@ def generate_html(target, options, js_target, target_basename,
24322432
}
24332433
document.body.appendChild(script);
24342434
}
2435-
''' % shared.JS.get_subresource_location(proxy_worker_filename + '.js')
2435+
'''
24362436
else:
24372437
# Normal code generation path
24382438
script.src = base_js_target
@@ -2442,10 +2442,11 @@ def generate_html(target, options, js_target, target_basename,
24422442
minified = 'minifyNames' in optimizer.queue_history,
24432443
separate_asm = options.separate_asm)
24442444

2445-
if shared.Settings.EMTERPRETIFY_FILE:
2446-
# We need to load the emterpreter file before anything else, it has to be synchronously ready
2447-
script.un_src()
2448-
script.inline = '''
2445+
if not shared.Settings.SINGLE_FILE:
2446+
if shared.Settings.EMTERPRETIFY_FILE:
2447+
# We need to load the emterpreter file before anything else, it has to be synchronously ready
2448+
script.un_src()
2449+
script.inline = '''
24492450
var emterpretURL = '%s';
24502451
var emterpretXHR = new XMLHttpRequest();
24512452
emterpretXHR.open('GET', emterpretURL, true);
@@ -2464,10 +2465,10 @@ def generate_html(target, options, js_target, target_basename,
24642465
emterpretXHR.send(null);
24652466
''' % (shared.JS.get_subresource_location(shared.Settings.EMTERPRETIFY_FILE), script.inline)
24662467

2467-
if options.memory_init_file:
2468-
# start to load the memory init file in the HTML, in parallel with the JS
2469-
script.un_src()
2470-
script.inline = ('''
2468+
if options.memory_init_file:
2469+
# start to load the memory init file in the HTML, in parallel with the JS
2470+
script.un_src()
2471+
script.inline = ('''
24712472
var memoryInitializer = '%s';
24722473
if (typeof Module['locateFile'] === 'function') {
24732474
memoryInitializer = Module['locateFile'](memoryInitializer);
@@ -2481,15 +2482,15 @@ def generate_html(target, options, js_target, target_basename,
24812482
meminitXHR.send(null);
24822483
''' % shared.JS.get_subresource_location(memfile)) + script.inline
24832484

2484-
# Download .asm.js if --separate-asm was passed in an asm.js build, or if 'asmjs' is one
2485-
# of the wasm run methods.
2486-
if not options.separate_asm or (shared.Settings.BINARYEN and 'asmjs' not in shared.Settings.BINARYEN_METHOD):
2487-
assert len(asm_mods) == 0, 'no --separate-asm means no client code mods are possible'
2488-
else:
2489-
script.un_src()
2490-
if len(asm_mods) == 0:
2491-
# just load the asm, then load the rest
2492-
script.inline = '''
2485+
# Download .asm.js if --separate-asm was passed in an asm.js build, or if 'asmjs' is one
2486+
# of the wasm run methods.
2487+
if not options.separate_asm or (shared.Settings.BINARYEN and 'asmjs' not in shared.Settings.BINARYEN_METHOD):
2488+
assert len(asm_mods) == 0, 'no --separate-asm means no client code mods are possible'
2489+
else:
2490+
script.un_src()
2491+
if len(asm_mods) == 0:
2492+
# just load the asm, then load the rest
2493+
script.inline = '''
24932494
var filename = '%s';
24942495
var fileBytes = tryParseAsDataURI(filename);
24952496
var script = document.createElement('script');
@@ -2505,9 +2506,9 @@ def generate_html(target, options, js_target, target_basename,
25052506
};
25062507
document.body.appendChild(script);
25072508
''' % (shared.JS.get_subresource_location(asm_target), script.inline)
2508-
else:
2509-
# may need to modify the asm code, load it as text, modify, and load asynchronously
2510-
script.inline = '''
2509+
else:
2510+
# may need to modify the asm code, load it as text, modify, and load asynchronously
2511+
script.inline = '''
25112512
var codeURL = '%s';
25122513
var codeXHR = new XMLHttpRequest();
25132514
codeXHR.open('GET', codeURL, true);
@@ -2538,10 +2539,10 @@ def generate_html(target, options, js_target, target_basename,
25382539
codeXHR.send(null);
25392540
''' % (shared.JS.get_subresource_location(asm_target), '\n'.join(asm_mods), script.inline)
25402541

2541-
if shared.Settings.BINARYEN and not shared.Settings.BINARYEN_ASYNC_COMPILATION:
2542-
# We need to load the wasm file before anything else, it has to be synchronously ready TODO: optimize
2543-
script.un_src()
2544-
script.inline = '''
2542+
if shared.Settings.BINARYEN and not shared.Settings.BINARYEN_ASYNC_COMPILATION:
2543+
# We need to load the wasm file before anything else, it has to be synchronously ready TODO: optimize
2544+
script.un_src()
2545+
script.inline = '''
25452546
var wasmURL = '%s';
25462547
var wasmXHR = new XMLHttpRequest();
25472548
wasmXHR.open('GET', wasmURL, true);
@@ -2567,6 +2568,17 @@ def generate_html(target, options, js_target, target_basename,
25672568
script.inline = f.read() + script.inline
25682569
f.close()
25692570

2571+
# inline script for SINGLE_FILE output
2572+
if shared.Settings.SINGLE_FILE:
2573+
js_contents = script.inline or ''
2574+
if script.src:
2575+
js = open(js_target, 'r')
2576+
js_contents += js.read()
2577+
js.close()
2578+
shared.try_delete(js_target)
2579+
script.src = None
2580+
script.inline = js_contents
2581+
25702582
html = open(target, 'wb')
25712583
html_contents = shell.replace('{{{ SCRIPT }}}', script.replacement())
25722584
html_contents = tools.line_endings.convert_line_endings(html_contents, '\n', options.output_eol)
@@ -2575,9 +2587,16 @@ def generate_html(target, options, js_target, target_basename,
25752587

25762588

25772589
def generate_worker_js(target, js_target, target_basename):
2578-
shutil.move(js_target, unsuffixed(js_target) + '.worker.js') # compiler output goes in .worker.js file
2579-
worker_target_basename = target_basename + '.worker'
2580-
proxy_worker_filename = shared.Settings.PROXY_TO_WORKER_FILENAME or worker_target_basename
2590+
# compiler output is embedded as base64
2591+
if shared.Settings.SINGLE_FILE:
2592+
proxy_worker_filename = shared.JS.get_subresource_location(js_target)
2593+
2594+
# compiler output goes in .worker.js file
2595+
else:
2596+
shutil.move(js_target, unsuffixed(js_target) + '.worker.js')
2597+
worker_target_basename = target_basename + '.worker'
2598+
proxy_worker_filename = (shared.Settings.PROXY_TO_WORKER_FILENAME or worker_target_basename) + '.js'
2599+
25812600
target_contents = worker_js_script(proxy_worker_filename)
25822601
open(target, 'w').write(target_contents)
25832602

src/proxyClient.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ var SUPPORT_BASE64_EMBEDDING;
101101

102102
// Worker
103103

104-
var filename = '{{{ filename }}}.js';
104+
var filename;
105+
if (!filename) {
106+
filename = '{{{ filename }}}';
107+
}
105108

106109
var workerURL = filename;
107110
if (SUPPORT_BASE64_EMBEDDING) {
@@ -110,7 +113,7 @@ if (SUPPORT_BASE64_EMBEDDING) {
110113
workerURL = URL.createObjectURL(new Blob([fileBytes], {type: 'application/javascript'}));
111114
}
112115
}
113-
var worker = new Worker(filename);
116+
var worker = new Worker(workerURL);
114117

115118
WebGLClient.prefetch();
116119

tests/test_browser.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3707,3 +3707,16 @@ def test_base64_atob_fallback(self):
37073707
</script>
37083708
''')
37093709
self.run_browser('a.html', '...', '/report_result?0')
3710+
3711+
# Tests that SINGLE_FILE works as intended in generated HTML (with and without Worker)
3712+
def test_single_file_html(self):
3713+
self.btest('emscripten_main_loop_setimmediate.cpp', '1', args=['-s', 'SINGLE_FILE=1', '-s', 'WASM=1', '-s', "BINARYEN_METHOD='native-wasm'"], also_proxied=True)
3714+
assert os.path.exists('test.html') and not os.path.exists('test.js') and not os.path.exists('test.worker.js')
3715+
3716+
# Tests that SINGLE_FILE works as intended in a Worker in JS output
3717+
def test_single_file_worker_js(self):
3718+
open('src.cpp', 'w').write(self.with_report_result(open(path_from_root('tests', 'browser_test_hello_world.c')).read()))
3719+
Popen([PYTHON, EMCC, 'src.cpp', '-o', 'test.js', '--proxy-to-worker', '-s', 'SINGLE_FILE=1', '-s', 'WASM=1', '-s', "BINARYEN_METHOD='native-wasm'"]).communicate()
3720+
open('test.html', 'w').write('<script src="test.js"></script>')
3721+
self.run_browser('test.html', None, '/report_result?0')
3722+
assert os.path.exists('test.js') and not os.path.exists('test.worker.js')

0 commit comments

Comments
 (0)