Skip to content

Commit 02e3c36

Browse files
authored
MODULARIZE / scriptDirectory improvements (#6914)
* Support new Module() (instead of just Module() ) in finding the scriptDirectory. This is done by avoiding .bind(), and saving it in a closure. This seems like a potential common pitfall, so worth supporting even if it isn't the documented use (see #6903). * Don't emit the _scriptDir code for MODULARIZE_INSTANCE - we only need it in MODULARIZE. * Refactor the emcc.py code, do the extra scriptDirectory or instance stuff later, which I think is clearer. * Add testing for MODULARIZE_INSTANCE and scriptDirectory detection.
1 parent 96606ff commit 02e3c36

File tree

4 files changed

+72
-40
lines changed

4 files changed

+72
-40
lines changed

emcc.py

+30-11
Original file line numberDiff line numberDiff line change
@@ -2604,24 +2604,43 @@ def modularize():
26042604
final = final + '.modular.js'
26052605
f = open(final, 'w')
26062606

2607-
# Included code may refer to Module (e.g. from file packager), so alias it
2608-
f.write('''var %(EXPORT_NAME)s = function(%(EXPORT_NAME)s) {
2607+
src = '''
2608+
function(%(EXPORT_NAME)s) {
26092609
%(EXPORT_NAME)s = %(EXPORT_NAME)s || {};
26102610
26112611
%(src)s
26122612
26132613
return %(EXPORT_NAME)s;
2614-
};
2615-
// When MODULARIZE, this JS may be executed later, after document.currentScript
2616-
// is gone, so we save it.
2617-
%(EXPORT_NAME)s = %(EXPORT_NAME)s.bind({
2618-
_scriptDir: typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined
2619-
})%(instantiate)s;
2614+
}
26202615
''' % {
26212616
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
2622-
'src': src,
2623-
'instantiate': '()' if shared.Settings.MODULARIZE_INSTANCE else ''
2624-
})
2617+
'src': src
2618+
}
2619+
2620+
if not shared.Settings.MODULARIZE_INSTANCE:
2621+
# When MODULARIZE this JS may be executed later,
2622+
# after document.currentScript is gone, so we save it.
2623+
# (when MODULARIZE_INSTANCE, an instance is created
2624+
# immediately anyhow, like in non-modularize mode)
2625+
src = '''
2626+
var %(EXPORT_NAME)s = (function() {
2627+
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
2628+
return (%(src)s);
2629+
})();
2630+
''' % {
2631+
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
2632+
'src': src
2633+
}
2634+
else:
2635+
# Create the MODULARIZE_INSTANCE instance
2636+
src = '''
2637+
var %(EXPORT_NAME)s = (%(src)s)();
2638+
''' % {
2639+
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
2640+
'src': src
2641+
}
2642+
2643+
f.write(src)
26252644

26262645
# Export using a UMD style export, or ES6 exports if selected
26272646
if shared.Settings.EXPORT_ES6:

src/closure-externs.js

+4
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,10 @@ var wakaUnknownAfter;
10731073
* @suppress {undefinedVars}
10741074
*/
10751075
var wakaUnknownBefore;
1076+
/**
1077+
* @suppress {undefinedVars}
1078+
*/
1079+
var _scriptDir;
10761080
/**
10771081
* @suppress {duplicate}
10781082
*/

src/shell.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,13 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
237237
scriptDirectory = self.location.href;
238238
}
239239
#if MODULARIZE
240-
// When MODULARIZE, this JS may be executed later, after document.currentScript
240+
#if MODULARIZE_INSTANCE == 0
241+
// When MODULARIZE (and not _INSTANCE), this JS may be executed later, after document.currentScript
241242
// is gone, so we saved it, and we use it here instead of any other info.
242-
if (this['_scriptDir']) {
243-
scriptDirectory = this['_scriptDir'];
243+
if (_scriptDir) {
244+
scriptDirectory = _scriptDir;
244245
}
246+
#endif
245247
#endif
246248
// blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
247249
// otherwise, slice off the final part of the url to find the script directory.

tests/test_browser.py

+33-26
Original file line numberDiff line numberDiff line change
@@ -3950,46 +3950,53 @@ def test_browser_run_from_different_directory(self):
39503950
src = open('test.html').read()
39513951
# Make sure JS is loaded from subdirectory
39523952
open('test-subdir.html', 'w').write(src.replace('test.js', 'subdir/test.js'))
3953-
39543953
self.run_browser('test-subdir.html', None, '/report_result?0')
39553954

39563955
# Similar to `test_browser_run_from_different_directory`, but asynchronous because of `-s MODULARIZE=1`
39573956
def test_browser_run_from_different_directory_async(self):
39583957
src = open(path_from_root('tests', 'browser_test_hello_world.c')).read()
39593958
open('test.c', 'w').write(self.with_report_result(src))
3960-
# compile the code with the modularize feature and the preload-file option enabled
3961-
Popen([PYTHON, EMCC, 'test.c', '-o', 'test.js', '-s', 'MODULARIZE=1', '-O3']).communicate()
3962-
if not os.path.exists('subdir'):
3963-
os.mkdir('subdir')
3964-
shutil.move('test.js', os.path.join('subdir', 'test.js'))
3965-
shutil.move('test.wasm', os.path.join('subdir', 'test.wasm'))
3966-
# Make sure JS is loaded from subdirectory
3967-
open('test-subdir.html', 'w').write('''
3968-
<script src="subdir/test.js"></script>
3969-
<script>
3970-
Module();
3971-
</script>
3972-
''')
3973-
3974-
self.run_browser('test-subdir.html', None, '/report_result?0')
3959+
for args, creations in [
3960+
(['-s', 'MODULARIZE=1'], [
3961+
'Module();', # documented way for using modularize
3962+
'new Module();' # not documented as working, but we support it
3963+
]),
3964+
(['-s', 'MODULARIZE_INSTANCE=1'], ['']) # instance: no need to create anything
3965+
]:
3966+
print(args)
3967+
# compile the code with the modularize feature and the preload-file option enabled
3968+
Popen([PYTHON, EMCC, 'test.c', '-o', 'test.js', '-O3'] + args).communicate()
3969+
if not os.path.exists('subdir'):
3970+
os.mkdir('subdir')
3971+
shutil.move('test.js', os.path.join('subdir', 'test.js'))
3972+
shutil.move('test.wasm', os.path.join('subdir', 'test.wasm'))
3973+
for creation in creations:
3974+
print(creation)
3975+
# Make sure JS is loaded from subdirectory
3976+
open('test-subdir.html', 'w').write('''
3977+
<script src="subdir/test.js"></script>
3978+
<script>
3979+
%s
3980+
</script>
3981+
''' % creation)
3982+
self.run_browser('test-subdir.html', None, '/report_result?0')
39753983

39763984
# Similar to `test_browser_run_from_different_directory`, but
39773985
# also also we eval the initial code, so currentScript is not present. That prevents us
39783986
# from finding the file in a subdir, but here we at least check we do not regress compared to the
39793987
# normal case of finding in the current dir.
3980-
# In addition, check for new Module(), which overrides the bind() and replaces the object
3981-
# which saved the _scriptDir. Again, we can't get the script dir that way, but at least we
3982-
# should not regress compared to the normal case.
39833988
def test_browser_modularize_no_current_script(self):
39843989
src = open(path_from_root('tests', 'browser_test_hello_world.c')).read()
39853990
open('test.c', 'w').write(self.with_report_result(src))
3986-
# compile the code with the modularize feature and the preload-file option enabled
3987-
Popen([PYTHON, EMCC, 'test.c', '-o', 'test.js', '-s', 'MODULARIZE=1']).communicate()
3988-
for creation in (
3989-
'Module();',
3990-
'new Module();'
3991-
):
3992-
print(creation)
3991+
# test both modularize (and creating an instance) and modularize-instance
3992+
# (which creates by itself)
3993+
for args, creation in [
3994+
(['-s', 'MODULARIZE=1'], 'Module();'),
3995+
(['-s', 'MODULARIZE_INSTANCE=1'], '')
3996+
]:
3997+
print(args, creation)
3998+
# compile the code with the modularize feature and the preload-file option enabled
3999+
Popen([PYTHON, EMCC, 'test.c', '-o', 'test.js'] + args).communicate()
39934000
open('test.html', 'w').write('''
39944001
<script>
39954002
setTimeout(function() {

0 commit comments

Comments
 (0)