From 7654e56bd7ca1d044fb592947108f0761c252994 Mon Sep 17 00:00:00 2001 From: Nir Maoz <47939921+maoznir@users.noreply.github.com> Date: Thu, 6 Jan 2022 09:43:03 +0200 Subject: [PATCH] Fix transparent video on safari 14.1 by using fetch instead of XHR (#282) --- bundlewatch.config.js | 2 +- src/util/xhr/getBlobFromURL.js | 80 +++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/bundlewatch.config.js b/bundlewatch.config.js index 07f07004..ebbf2cb3 100644 --- a/bundlewatch.config.js +++ b/bundlewatch.config.js @@ -6,7 +6,7 @@ const bundlewatchConfig = { }, { path: './dist/cloudinary-core-shrinkwrap.min.js', - maxSize: '31kb' + maxSize: '32kb' }, { path: './dist/cloudinary-jquery.min.js', diff --git a/src/util/xhr/getBlobFromURL.js b/src/util/xhr/getBlobFromURL.js index 685ffbf0..10978f56 100644 --- a/src/util/xhr/getBlobFromURL.js +++ b/src/util/xhr/getBlobFromURL.js @@ -1,3 +1,18 @@ +/** + * Reject on timeout + * @param maxTimeoutMS + * @param reject + * @returns {number} timerID + */ +function rejectOnTimeout(maxTimeoutMS, reject) { + return setTimeout(() => { + reject({ + status: 'error', + message: 'Timeout loading Blob URL' + }); + }, maxTimeoutMS); +} + /** * @description Converts a URL to a BLOB URL * @param {string} urlToLoad @@ -10,34 +25,67 @@ * } * }>} */ -function getBlobFromURL(urlToLoad, max_timeout_ms) { +function getBlobFromURL(urlToLoad, maxTimeoutMS) { return new Promise((resolve, reject) => { - let timerID = setTimeout(() => { - reject({ - status: 'error', - message: 'Timeout loading Blob URL' - }); - }, max_timeout_ms); + const timerID = rejectOnTimeout(maxTimeoutMS, reject); - let xhr = new XMLHttpRequest(); - xhr.responseType = 'blob'; - xhr.onload = function (response) { - clearTimeout(timerID); // clear timeout reject error + // If fetch exists, use it to fetch blob, otherwise use XHR. + // XHR causes issues on safari 14.1 so we prefer fetch + const fetchBlob = (typeof fetch !== 'undefined' && fetch) ? loadUrlUsingFetch : loadUrlUsingXhr; + + fetchBlob(urlToLoad).then((blob) => { resolve({ status: 'success', payload: { - blobURL: URL.createObjectURL(xhr.response) + blobURL: URL.createObjectURL(blob) } }); - }; - - xhr.onerror = function () { - clearTimeout(timerID); // clear timeout reject error + }).catch(() => { reject({ status: 'error', message: 'Error loading Blob URL' }); + }).finally(() => { + // Clear the timeout timer on fail or success. + clearTimeout(timerID); + }); + }); +} + +/** + * Use fetch function to fetch file + * @param urlToLoad + * @returns {Promise} + */ +function loadUrlUsingFetch(urlToLoad) { + return new Promise((resolve, reject) => { + fetch(urlToLoad).then((response) => { + response.blob().then((blob) => { + resolve(blob); + }); + }).catch(() => { + reject('error'); + }); + }); +} + +/** + * Use XHR to fetch file + * @param urlToLoad + * @returns {Promise} + */ +function loadUrlUsingXhr(urlToLoad) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.responseType = 'blob'; + xhr.onload = function (response) { + resolve(xhr.response); }; + + xhr.onerror = function () { + reject('error'); + }; + xhr.open('GET', urlToLoad, true); xhr.send(); });