diff --git a/test/test_other.py b/test/test_other.py index 5285cd18ec8c4..27074b707d19c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3984,10 +3984,7 @@ def test_file_packager_modularize(self): create_file('post.js', 'MyModule(Module).then(() => console.log("done"));') - self.run_process([EMCC, 'main.c', '--extern-pre-js=embed.js', '--extern-post-js=post.js', '-sMODULARIZE', '-sEXPORT_NAME=MyModule', '-sFORCE_FILESYSTEM']) - - result = self.run_js('a.out.js') - self.assertContained('|hello world|', result) + self.do_runf('main.c', '|hello world|', cflags=['--extern-pre-js=embed.js', '--extern-post-js=post.js', '-sMODULARIZE', '-sEXPORT_NAME=MyModule', '-sFORCE_FILESYSTEM']) def test_preprocess(self): # Pass -Werror to prevent regressions such as https://github.com/emscripten-core/emscripten/pull/9661 diff --git a/tools/file_packager.py b/tools/file_packager.py index ed00417709a22..ad61f0634acdd 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -635,11 +635,11 @@ def generate_js(data_target, data_files, metadata): if options.support_node: ret += " var isNode = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';\n" - ret += ' function loadPackage(metadata) {\n' + ret += ' async function loadPackage(metadata) {\n' code = ''' function assert(check, msg) { - if (!check) throw msg + new Error().stack; + if (!check) throw new Error(msg); }\n''' # Set up folders @@ -808,7 +808,7 @@ def generate_js(data_target, data_files, metadata): async function openDatabase() { if (typeof indexedDB == 'undefined') { - throw 'using IndexedDB to cache data can only be done on a web page or in a web worker'; + throw new Error('using IndexedDB to cache data can only be done on a web page or in a web worker'); } return new Promise((resolve, reject) => { var openRequest = indexedDB.open(DB_NAME, DB_VERSION); @@ -953,62 +953,58 @@ def generate_js(data_target, data_files, metadata): if options.support_node: node_support_code = ''' if (isNode) { - require('fs/promises').readFile(packageName).then((contents) => callback(contents.buffer)); - return; + var fsPromises = require('fs/promises'); + var contents = await fsPromises.readFile(packageName); + return contents.buffer; }'''.strip() ret += ''' - function fetchRemotePackage(packageName, packageSize, callback) { + async function fetchRemotePackage(packageName, packageSize) { %(node_support_code)s Module['dataFileDownloads'] ??= {}; - fetch(packageName) - .catch((cause) => Promise.reject(new Error(`Network Error: ${packageName}`, {cause}))) // If fetch fails, rewrite the error to include the failing URL & the cause. - .then((response) => { - if (!response.ok) { - return Promise.reject(new Error(`${response.status}: ${response.url}`)); - } + try { + var response = await fetch(packageName); + } catch (e) { + throw new Error(`Network Error: ${packageName}`, {e}); + } + if (!response.ok) { + throw new Error(`${response.status}: ${response.url}`); + } - const reader = response.body.getReader(); - const iterate = () => reader.read().then(handleChunk).catch((cause) => { - return Promise.reject(new Error(`Unexpected error while handling : ${response.url} ${cause}`, {cause})); - }); + const chunks = []; + const headers = response.headers; + const total = Number(headers.get('Content-Length') ?? packageSize); + let loaded = 0; - const chunks = []; - const headers = response.headers; - const total = Number(headers.get('Content-Length') ?? packageSize); - let loaded = 0; + Module['setStatus']?.('Downloading data...'); + const reader = response.body.getReader(); - const handleChunk = ({done, value}) => { - if (!done) { - chunks.push(value); - loaded += value.length; - Module['dataFileDownloads'][packageName] = {loaded, total}; + while (1) { + var {done, value} = await reader.read(); + if (done) break; + chunks.push(value); + loaded += value.length; + Module['dataFileDownloads'][packageName] = {loaded, total}; - let totalLoaded = 0; - let totalSize = 0; + let totalLoaded = 0; + let totalSize = 0; - for (const download of Object.values(Module['dataFileDownloads'])) { - totalLoaded += download.loaded; - totalSize += download.total; - } + for (const download of Object.values(Module['dataFileDownloads'])) { + totalLoaded += download.loaded; + totalSize += download.total; + } - Module['setStatus']?.(`Downloading data... (${totalLoaded}/${totalSize})`); - return iterate(); - } else { - const packageData = new Uint8Array(chunks.map((c) => c.length).reduce((a, b) => a + b, 0)); - let offset = 0; - for (const chunk of chunks) { - packageData.set(chunk, offset); - offset += chunk.length; - } - callback(packageData.buffer); - } - }; + Module['setStatus']?.(`Downloading data... (${totalLoaded}/${totalSize})`); + } - Module['setStatus']?.('Downloading data...'); - return iterate(); - }); - };\n''' % {'node_support_code': node_support_code} + const packageData = new Uint8Array(chunks.map((c) => c.length).reduce((a, b) => a + b, 0)); + let offset = 0; + for (const chunk of chunks) { + packageData.set(chunk, offset); + offset += chunk.length; + } + return packageData.buffer; + }\n''' % {'node_support_code': node_support_code} code += ''' function processPackageData(arrayBuffer) { @@ -1017,7 +1013,7 @@ def generate_js(data_target, data_files, metadata): var byteArray = new Uint8Array(arrayBuffer); var curr; %s - }; + } Module['addRunDependency']('datafile_%s');\n''' % (use_data, js_manipulation.escape_for_js_string(data_target)) # use basename because from the browser's point of view, # we need to find the datafile in the same dir as the html file @@ -1027,32 +1023,31 @@ def generate_js(data_target, data_files, metadata): if options.use_preload_cache: code += ''' - function preloadFallback(error) { + async function preloadFallback(error) { console.error(error); console.error('falling back to default preload behavior'); - fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, processPackageData); - }; - - openDatabase() - .then((db) => { - checkCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME) - .then((cachedData) => { - Module['preloadResults'][PACKAGE_NAME] = {fromCache: !!cachedData}; - if (cachedData) { - fetchCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME, cachedData).then(processPackageData); - } else { - fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, - (packageData) => { - cacheRemotePackage(db, PACKAGE_PATH + PACKAGE_NAME, packageData, {uuid:PACKAGE_UUID}) - .then(processPackageData) - .catch((error) => { - console.error(error); - processPackageData(packageData); - }); - }); - } - }) - }).catch(preloadFallback); + processPackageData(await fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE)); + } + + try { + var db = await openDatabase(); + var pkgMetadata = await checkCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME); + var useCached = !!pkgMetadata; + Module['preloadResults'][PACKAGE_NAME] = {fromCache: useCached}; + if (useCached) { + processPackageData(await fetchCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME, pkgMetadata)); + } else { + var packageData = await fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE); + try { + processPackageData(await cacheRemotePackage(db, PACKAGE_PATH + PACKAGE_NAME, packageData, {uuid:PACKAGE_UUID})) + } catch (error) { + console.error(error); + processPackageData(packageData); + } + } + } catch(e) { + await preloadFallback(e); + } Module['setStatus']?.('Downloading...');\n''' else: @@ -1064,14 +1059,18 @@ def generate_js(data_target, data_files, metadata): var fetchedCallback = null; var fetched = Module['getPreloadedPackage'] ? Module['getPreloadedPackage'](REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE) : null; - if (!fetched) fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, (data) => { - if (fetchedCallback) { - fetchedCallback(data); - fetchedCallback = null; - } else { - fetched = data; - } - });\n''' + if (!fetched) { + // Note that we don't use await here because we want to execute the + // the rest of this function immediately. + fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE).then((data) => { + if (fetchedCallback) { + fetchedCallback(data); + fetchedCallback = null; + } else { + fetched = data; + } + }) + }\n''' code += ''' Module['preloadResults'][PACKAGE_NAME] = {fromCache: false}; @@ -1083,7 +1082,7 @@ def generate_js(data_target, data_files, metadata): }\n''' ret += ''' - function runWithFS(Module) {\n''' + async function runWithFS(Module) {\n''' ret += code ret += ''' }