cache-buster-react
Version:
This package allows clients to automatically check the new version when a new version is released in the production environment, and if a new version is published, clearing the cache and reload the page.
206 lines (172 loc) • 6.54 kB
JavaScript
import { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
// A type of promise-like that resolves synchronously and supports only one observer
const _iteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.iterator || (Symbol.iterator = Symbol("Symbol.iterator"))) : "@@iterator";
const _asyncIteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.asyncIterator || (Symbol.asyncIterator = Symbol("Symbol.asyncIterator"))) : "@@asyncIterator";
// Asynchronously call a function and send errors to recovery continuation
function _catch(body, recover) {
try {
var result = body();
} catch(e) {
return recover(e);
}
if (result && result.then) {
return result.then(void 0, recover);
}
return result;
}
function CacheBuster(_ref) {
var _ref$children = _ref.children,
children = _ref$children === void 0 ? null : _ref$children,
currentVersion = _ref.currentVersion,
_ref$isEnabled = _ref.isEnabled,
isEnabled = _ref$isEnabled === void 0 ? false : _ref$isEnabled,
_ref$isVerboseMode = _ref.isVerboseMode,
isVerboseMode = _ref$isVerboseMode === void 0 ? false : _ref$isVerboseMode,
_ref$loadingComponent = _ref.loadingComponent,
loadingComponent = _ref$loadingComponent === void 0 ? null : _ref$loadingComponent,
_ref$basePath = _ref.basePath,
basePath = _ref$basePath === void 0 ? '' : _ref$basePath;
var _useState = useState({
loading: true,
isLatestVersion: false
}),
cacheStatus = _useState[0],
setCacheStatus = _useState[1];
var log = function log(message, isError) {
isVerboseMode && (isError ? console.error(message) : console.log(message));
};
useEffect(function () {
isEnabled ? checkCacheStatus() : log('React Cache Buster is disabled.');
}, []);
var checkCacheStatus = function checkCacheStatus() {
try {
var _temp2 = _catch(function () {
return Promise.resolve(fetch(basePath + "/meta.json")).then(function (res) {
return Promise.resolve(res.json()).then(function (_ref2) {
var metaVersion = _ref2.version;
var shouldForceRefresh = isThereNewVersion(metaVersion, currentVersion);
if (shouldForceRefresh) {
log("There is a new version (v" + metaVersion + "). Should force refresh.");
setCacheStatus({
loading: false,
isLatestVersion: false
});
} else {
log('There is no new version. No cache refresh needed.');
setCacheStatus({
loading: false,
isLatestVersion: true
});
}
});
});
}, function (error) {
log('An error occurred while checking cache status.', true);
log(error, true);
!isVerboseMode && setCacheStatus({
loading: false,
isLatestVersion: true
});
});
return Promise.resolve(_temp2 && _temp2.then ? _temp2.then(function () {}) : void 0);
} catch (e) {
return Promise.reject(e);
}
};
var isThereNewVersion = function isThereNewVersion(metaVersion, currentVersion) {
if (!currentVersion) {
return false;
}
var metaVersions = metaVersion.split(/\./g);
var currentVersions = currentVersion.split(/\./g);
while (metaVersions.length || currentVersions.length) {
var a = Number(metaVersions.shift());
var b = Number(currentVersions.shift());
if (a === b) {
continue;
}
return a > b || isNaN(b);
}
return false;
};
var refreshCacheAndReload = function refreshCacheAndReload() {
try {
return Promise.resolve(_catch(function () {
var _temp3 = function () {
var _window;
if ((_window = window) !== null && _window !== void 0 && _window.caches) {
var _window2 = window,
caches = _window2.caches;
return Promise.resolve(caches.keys()).then(function (cacheNames) {
for (var _iterator = _createForOfIteratorHelperLoose(cacheNames), _step; !(_step = _iterator()).done;) {
var cacheName = _step.value;
caches["delete"](cacheName);
}
log('The cache has been deleted.');
window.location.reload(true);
});
}
}();
if (_temp3 && _temp3.then) return _temp3.then(function () {});
}, function (error) {
log('An error occurred while deleting the cache.', true);
log(error, true);
}));
} catch (e) {
return Promise.reject(e);
}
};
if (!isEnabled) {
return children;
} else {
if (cacheStatus.loading) {
return loadingComponent;
}
if (!cacheStatus.loading && !cacheStatus.isLatestVersion) {
refreshCacheAndReload();
return null;
}
return children;
}
}
CacheBuster.propTypes = {
children: PropTypes.element.isRequired,
currentVersion: PropTypes.string.isRequired,
isEnabled: PropTypes.bool.isRequired,
isVerboseMode: PropTypes.bool,
loadingComponent: PropTypes.element,
basePath: PropTypes.string.isRequired
};
export { CacheBuster };