-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Use fetch() for loading packages & shared libraries
#22002
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
Changes from 28 commits
87743d1
3d38841
ffcaa3b
de79ead
139bcd4
893f361
0407112
24761b6
3ead8de
35b593f
5c2a7bb
5631928
ff2d142
9e06ef2
5899d3f
c09f2c5
2f43c20
c5ecce5
7e86b5b
6848055
0bf9b71
3f765bc
316aa8b
366b942
58ab5c6
5899e42
92ffd13
df4e1c3
bb9a69e
c8e9db9
272f093
6432c5a
e870667
ce4089e
4581d90
457ef2c
aeac94e
275388a
d4a6162
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,17 +22,13 @@ | |
| } | ||
|
|
||
| readAsync = (url, onload, onerror) => { | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('GET', url, true); | ||
| xhr.responseType = 'arraybuffer'; | ||
| xhr.onload = () => { | ||
| if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 | ||
| onload(xhr.response); | ||
| return; | ||
| fetch(url) | ||
| .then(response => { | ||
| if(response.ok) { | ||
| return response.arrayBuffer(); | ||
| } | ||
| onerror(); | ||
| }; | ||
| xhr.onerror = onerror; | ||
| xhr.send(null); | ||
| } | ||
|
|
||
| throw new Error(response.statusText + ' : ' + response.url); | ||
|
||
| }) | ||
| .then(onload) | ||
| .catch(onerror) | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 31420 | ||
| 31418 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -359,7 +359,7 @@ def generate_object_file(data_files): | |
|
|
||
| def main(): | ||
| if len(sys.argv) == 1: | ||
| err('''Usage: file_packager TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--indexedDB-name=EM_PRELOAD_CACHE] [--separate-metadata] [--lz4] [--use-preload-plugins] | ||
| err('''Usage: file_packager TARGET [--preload A [B..]] [--embed C [D..]] [--exclude E [F..]]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache] [--indexedDB-name=EM_PRELOAD_CACHE] [--separate-metadata] [--lz4] [--use-preload-plugins] [--no-node] | ||
| See the source for more details.''') | ||
| return 1 | ||
|
|
||
|
|
@@ -775,7 +775,7 @@ def generate_js(data_target, data_files, metadata): | |
| } | ||
| var REMOTE_PACKAGE_NAME = Module['locateFile'] ? Module['locateFile'](REMOTE_PACKAGE_BASE, '') : REMOTE_PACKAGE_BASE;\n''' % (js_manipulation.escape_for_js_string(data_target), js_manipulation.escape_for_js_string(remote_package_name)) | ||
| metadata['remote_package_size'] = remote_package_size | ||
| ret += '''var REMOTE_PACKAGE_SIZE = metadata['remote_package_size'];\n''' | ||
| ret += ''' var REMOTE_PACKAGE_SIZE = metadata['remote_package_size'];\n''' | ||
|
|
||
| if options.use_preload_cache: | ||
| # Set the id to a hash of the preloaded data, so that caches survive over multiple builds | ||
|
|
@@ -965,59 +965,68 @@ def generate_js(data_target, data_files, metadata): | |
| }); | ||
| return; | ||
| }'''.strip() | ||
|
|
||
| ret += ''' | ||
| function fetchRemotePackage(packageName, packageSize, callback, errback) { | ||
| %(node_support_code)s | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('GET', packageName, true); | ||
| xhr.responseType = 'arraybuffer'; | ||
| xhr.onprogress = function(event) { | ||
| var url = packageName; | ||
| var size = packageSize; | ||
| if (event.total) size = event.total; | ||
| if (event.loaded) { | ||
| if (!xhr.addedTotal) { | ||
| xhr.addedTotal = true; | ||
| if (!Module.dataFileDownloads) Module.dataFileDownloads = {}; | ||
| Module.dataFileDownloads[url] = { | ||
| loaded: event.loaded, | ||
| total: size | ||
| }; | ||
| } else { | ||
| Module.dataFileDownloads[url].loaded = event.loaded; | ||
| Module.dataFileDownloads = Module.dataFileDownloads || {}; | ||
| const url = packageName; | ||
| fetch(url) | ||
| .catch(error => { throw new Error(error + ' : ' + url) }) // Do this first so we don't catch errors from then() | ||
|
||
| .then(response => { | ||
|
|
||
| let loaded = 0; | ||
|
|
||
| const reader = response.body.getReader(); | ||
| const headers = response.headers; | ||
|
|
||
| if (!response.ok) { | ||
| throw new Error(response.statusText + ' : ' + response.url); | ||
| } | ||
|
|
||
| const total = headers.get('Content-Length') ?? packageSize; | ||
| const chunks = []; | ||
|
|
||
| const iterate = () => reader.read().then(handleChunk).catch(cause => { | ||
| throw new Error(response.statusText + ' : ' + response.url, {cause}); | ||
| }); | ||
|
|
||
| const handleChunk = ({done, value}) => { | ||
| if (!done) { | ||
| chunks.push(value); | ||
| loaded += value.length; | ||
| Module.dataFileDownloads[url] = Module.dataFileDownloads[url] ?? {}; | ||
| Module.dataFileDownloads[url].loaded = loaded; | ||
| Module.dataFileDownloads[url].total = total; | ||
|
|
||
| if (total) { | ||
| if (Module['setStatus']) Module['setStatus'](`Downloading data... (${loaded}/${total})`); | ||
| } | ||
| else { | ||
| if (Module['setStatus']) Module['setStatus']('Downloading data...'); | ||
| } | ||
| return iterate(); | ||
| } | ||
| var total = 0; | ||
| var loaded = 0; | ||
| var num = 0; | ||
| for (var download in Module.dataFileDownloads) { | ||
| var data = Module.dataFileDownloads[download]; | ||
| total += data.total; | ||
| loaded += data.loaded; | ||
| num++; | ||
| else { | ||
| const size = chunks.map(c => c.length).reduce((a, b) => a + b, 0); | ||
| let index = 0; | ||
| const packageData = new Uint8Array(size); | ||
| for(const chunk of chunks) { | ||
| packageData.set(chunk, index); | ||
| index += chunk.length; | ||
| } | ||
|
|
||
| callback(packageData.buffer); | ||
| } | ||
| total = Math.ceil(total * Module.expectedDataFileDownloads/num); | ||
| if (Module['setStatus']) Module['setStatus'](`Downloading data... (${loaded}/${total})`); | ||
| } else if (!Module.dataFileDownloads) { | ||
| if (Module['setStatus']) Module['setStatus']('Downloading data...'); | ||
| } | ||
| }; | ||
| xhr.onerror = function(event) { | ||
| throw new Error("NetworkError for: " + packageName); | ||
| } | ||
| xhr.onload = function(event) { | ||
| if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 | ||
| var packageData = xhr.response; | ||
| callback(packageData); | ||
| } else { | ||
| throw new Error(xhr.statusText + " : " + xhr.responseURL); | ||
| } | ||
| }; | ||
| xhr.send(null); | ||
| }; | ||
| }; | ||
| return iterate(); | ||
| }); | ||
| };\n''' % {'node_support_code': node_support_code} | ||
|
|
||
| ret += ''' | ||
| function handleError(error) { | ||
| console.error('package error:', error); | ||
| };\n''' % {'node_support_code': node_support_code} | ||
| };\n''' | ||
|
|
||
| code += ''' | ||
| function processPackageData(arrayBuffer) { | ||
|
|
@@ -1113,15 +1122,14 @@ def generate_js(data_target, data_files, metadata): | |
| function runMetaWithFS() { | ||
| Module['addRunDependency']('%(metadata_file)s'); | ||
| var REMOTE_METADATA_NAME = Module['locateFile'] ? Module['locateFile']('%(metadata_file)s', '') : '%(metadata_file)s'; | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.onreadystatechange = function() { | ||
| if (xhr.readyState === 4 && xhr.status === 200) { | ||
| loadPackage(JSON.parse(xhr.responseText)); | ||
| } | ||
| } | ||
| xhr.open('GET', REMOTE_METADATA_NAME, true); | ||
| xhr.overrideMimeType('application/json'); | ||
| xhr.send(null); | ||
| fetch(REMOTE_METADATA_NAME) | ||
| .then(response => { | ||
| if(response.ok) { | ||
| return response.json(); | ||
| } | ||
| throw new Error(response.statusText + ' : ' + response.url); | ||
|
||
| }) | ||
| .then(loadPackage); | ||
| } | ||
|
|
||
| if (Module['calledRun']) { | ||
|
|
@@ -1130,7 +1138,6 @@ def generate_js(data_target, data_files, metadata): | |
| if (!Module['preRun']) Module['preRun'] = []; | ||
| Module["preRun"].push(runMetaWithFS); | ||
| }\n''' % {'metadata_file': os.path.basename(options.jsoutput + '.metadata')} | ||
|
|
||
| else: | ||
| _metadata_template = ''' | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not call
onloadhere?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
response.arrayBuffer();returns a promise that resolves to a buffer, not a literal buffer.