UNPKG

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
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 };