Skip to content

MODULARIZE / scriptDirectory improvements #6914

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 8 commits into from
Jul 28, 2018
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
41 changes: 30 additions & 11 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2604,24 +2604,43 @@ def modularize():
final = final + '.modular.js'
f = open(final, 'w')

# Included code may refer to Module (e.g. from file packager), so alias it
f.write('''var %(EXPORT_NAME)s = function(%(EXPORT_NAME)s) {
src = '''
function(%(EXPORT_NAME)s) {
%(EXPORT_NAME)s = %(EXPORT_NAME)s || {};

%(src)s

return %(EXPORT_NAME)s;
};
// When MODULARIZE, this JS may be executed later, after document.currentScript
// is gone, so we save it.
%(EXPORT_NAME)s = %(EXPORT_NAME)s.bind({
_scriptDir: typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined
})%(instantiate)s;
}
''' % {
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
'src': src,
'instantiate': '()' if shared.Settings.MODULARIZE_INSTANCE else ''
})
'src': src
}

if not shared.Settings.MODULARIZE_INSTANCE:
# When MODULARIZE this JS may be executed later,
# after document.currentScript is gone, so we save it.
# (when MODULARIZE_INSTANCE, an instance is created
# immediately anyhow, like in non-modularize mode)
src = '''
var %(EXPORT_NAME)s = (function() {
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
return (%(src)s);
})();
''' % {
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
'src': src
}
else:
# Create the MODULARIZE_INSTANCE instance
src = '''
var %(EXPORT_NAME)s = (%(src)s)();
''' % {
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
'src': src
}

f.write(src)

# Export using a UMD style export, or ES6 exports if selected
if shared.Settings.EXPORT_ES6:
Expand Down
4 changes: 4 additions & 0 deletions src/closure-externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,10 @@ var wakaUnknownAfter;
* @suppress {undefinedVars}
*/
var wakaUnknownBefore;
/**
* @suppress {undefinedVars}
*/
var _scriptDir;
/**
* @suppress {duplicate}
*/
Expand Down
8 changes: 5 additions & 3 deletions src/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,13 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
scriptDirectory = self.location.href;
}
#if MODULARIZE
// When MODULARIZE, this JS may be executed later, after document.currentScript
#if MODULARIZE_INSTANCE == 0
// When MODULARIZE (and not _INSTANCE), this JS may be executed later, after document.currentScript
// is gone, so we saved it, and we use it here instead of any other info.
if (this['_scriptDir']) {
scriptDirectory = this['_scriptDir'];
if (_scriptDir) {
scriptDirectory = _scriptDir;
}
#endif
#endif
// blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
// otherwise, slice off the final part of the url to find the script directory.
Expand Down
59 changes: 33 additions & 26 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3950,46 +3950,53 @@ def test_browser_run_from_different_directory(self):
src = open('test.html').read()
# Make sure JS is loaded from subdirectory
open('test-subdir.html', 'w').write(src.replace('test.js', 'subdir/test.js'))

self.run_browser('test-subdir.html', None, '/report_result?0')

# Similar to `test_browser_run_from_different_directory`, but asynchronous because of `-s MODULARIZE=1`
def test_browser_run_from_different_directory_async(self):
src = open(path_from_root('tests', 'browser_test_hello_world.c')).read()
open('test.c', 'w').write(self.with_report_result(src))
# compile the code with the modularize feature and the preload-file option enabled
Popen([PYTHON, EMCC, 'test.c', '-o', 'test.js', '-s', 'MODULARIZE=1', '-O3']).communicate()
if not os.path.exists('subdir'):
os.mkdir('subdir')
shutil.move('test.js', os.path.join('subdir', 'test.js'))
shutil.move('test.wasm', os.path.join('subdir', 'test.wasm'))
# Make sure JS is loaded from subdirectory
open('test-subdir.html', 'w').write('''
<script src="subdir/test.js"></script>
<script>
Module();
</script>
''')

self.run_browser('test-subdir.html', None, '/report_result?0')
for args, creations in [
(['-s', 'MODULARIZE=1'], [
'Module();', # documented way for using modularize
'new Module();' # not documented as working, but we support it
]),
(['-s', 'MODULARIZE_INSTANCE=1'], ['']) # instance: no need to create anything
]:
print(args)
# compile the code with the modularize feature and the preload-file option enabled
Popen([PYTHON, EMCC, 'test.c', '-o', 'test.js', '-O3'] + args).communicate()
if not os.path.exists('subdir'):
os.mkdir('subdir')
shutil.move('test.js', os.path.join('subdir', 'test.js'))
shutil.move('test.wasm', os.path.join('subdir', 'test.wasm'))
for creation in creations:
print(creation)
# Make sure JS is loaded from subdirectory
open('test-subdir.html', 'w').write('''
<script src="subdir/test.js"></script>
<script>
%s
</script>
''' % creation)
self.run_browser('test-subdir.html', None, '/report_result?0')

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