File size: 5,782 Bytes
84c1942 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | // In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
const isHttp = Boolean(window.location.protocol === 'http:');
interface SWOptions {
onUpdated?: () => void;
onInstalled?: () => void;
}
export default function register(swUrl, opts: SWOptions = {}) {
if ('serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
// @ts-ignore
const publicUrl = new URL(process.env.PUBLIC_URL || '/', window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
// window.addEventListener('load', () => {
if (!isLocalhost && !isHttp) {
// It's neither localhost nor http. Just register service worker
registerValidSW(swUrl, opts);
} else if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl, opts);
}
}
}
function registerValidSW(
swUrl: string,
{ onUpdated, onInstalled }: SWOptions = {}
) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
if (onUpdated) {
onUpdated();
}
} else if (onInstalled) {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
onInstalled();
}
} else if (installingWorker.state === 'redundant') {
if ('storage' in navigator && 'estimate' in navigator.storage) {
navigator.storage.estimate().then(results => {
const percentUsed = results.usage / results.quota;
// Let's assume that if we're using 95% of our quota, then this failure
// was due to quota exceeded errors.
// TODO: Hardcoding a threshold stinks.
if (percentUsed >= 0.95) {
// Get rid of the existing SW so that we're not stuck
// with the previously cached content.
registration.unregister();
// Let's assume that we have some way of doing this without inadvertantly
// blowing away storage being used on the origin by something other than
// our service worker.
// I don't think that the Clear-Site-Data: header helps here, unfortunately.
self.caches.keys().then(names => {
names.forEach(name => {
self.caches.delete(name);
});
});
// TODO clear indexeddb
}
});
} else {
// What about browsers that don't support navigator.storage.estimate()?
// There's no way of guessing why the service worker is redundant.
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, { onUpdated, onInstalled }: SWOptions) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, { onUpdated, onInstalled });
}
})
.catch(e => {
// eslint-disable-next-line no-console
console.log(
'No internet connection found. App is running in offline mode.',
e
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
|