@mstange/offline-plugin
Version:
offline-plugin for webpack
246 lines (205 loc) • 6.89 kB
JavaScript
var appCacheIframe;
function hasSW() {
<% if (typeof ServiceWorker === 'object' && ServiceWorker.force) { %>
// Forced install
return 'serviceWorker' in navigator;
<% } else { %>
return 'serviceWorker' in navigator && (
window.location.protocol === 'https:' ||
window.location.hostname === 'localhost' ||
window.location.hostname.indexOf('127.') === 0
);
<% } %>
}
function install(options) {
options || (options = {});
<% if (typeof ServiceWorker !== 'undefined') { %>
if (hasSW()) {
var registration = navigator.serviceWorker
.register(
<%- JSON.stringify(ServiceWorker.location) %>, {
<% if (ServiceWorker.scope) { %>
scope: <%- JSON.stringify(ServiceWorker.scope) %>,
<% } %>
<% if (
ServiceWorker.updateViaCache &&
ServiceWorker.updateViaCache !== 'imports'
) { %>
updateViaCache: <%- JSON.stringify(ServiceWorker.updateViaCache) %>,
<% } %>
}
);
<% if (ServiceWorker.events) { %>
var handleUpdating = function(registration) {
var sw = registration.installing || registration.waiting;
var ignoreInstalling;
var ignoreWaiting;
// No SW or already handled
if (!sw || sw.onstatechange) return;
var stateChangeHandler;
// Already has SW
if (registration.active) {
onUpdateStateChange();
stateChangeHandler = onUpdateStateChange;
} else {
onInstallStateChange();
stateChangeHandler = onInstallStateChange;
}
ignoreInstalling = true;
if (registration.waiting) {
ignoreWaiting = true;
}
sw.onstatechange = stateChangeHandler;
function onUpdateStateChange() {
switch (sw.state) {
case 'redundant': {
sendEvent('onUpdateFailed');
sw.onstatechange = null;
} break;
case 'installing': {
if (!ignoreInstalling) {
sendEvent('onUpdating');
}
} break;
case 'installed': {
if (!ignoreWaiting) {
sendEvent('onUpdateReady');
}
} break;
case 'activated': {
sendEvent('onUpdated');
sw.onstatechange = null;
} break;
}
}
function onInstallStateChange() {
switch (sw.state) {
case 'redundant': {
// Failed to install, ignore
sw.onstatechange = null;
} break;
case 'installing': {
// Installing, ignore
} break;
case 'installed': {
// Installed, wait activation
} break;
case 'activated': {
sendEvent('onInstalled');
sw.onstatechange = null;
} break;
}
}
};
var sendEvent = function(event) {
if (typeof options[event] === 'function') {
options[event]({
source: 'ServiceWorker'
});
}
};
registration.then(function(reg) {
// WTF no reg?
if (!reg) return;
// Installed but Shift-Reloaded (page is not controller by SW),
// update might be ready at this point (more than one tab opened).
// Anyway, if page is hard-reloaded, then it probably already have latest version
// but it's not controlled by SW yet. Applying update will claim this page
// to be controlled by SW. Maybe set flag to not reload it?
// if (!navigator.serviceWorker.controller) return;
handleUpdating(reg);
reg.onupdatefound = function() {
handleUpdating(reg);
};
}).catch(function(err) {
sendEvent('onError');
return Promise.reject(err);
});
<% } %>
return;
}
<% } %>
<% if (typeof AppCache !== 'undefined' && AppCache.disableInstall !== true) { %>
if (window.applicationCache) {
var directory = <%- JSON.stringify(AppCache.location) %>;
var name = <%- JSON.stringify(AppCache.name) %>;
var doLoad = function() {
var page = directory + name + '.html';
var iframe = document.createElement('iframe');
<% if (AppCache.events) { %>
window.addEventListener('message', function(e) {
if (e.source !== iframe.contentWindow) return;
var match = (e.data + '').match(/__offline-plugin_AppCacheEvent:(\w+)/);
if (!match) return;
var event = match[1];
if (typeof options[event] === 'function') {
options[event]({
source: 'AppCache'
});
}
});
<% } %>
iframe.src = page;
iframe.style.display = 'none';
appCacheIframe = iframe;
document.body.appendChild(iframe);
};
if (document.readyState === 'complete') {
setTimeout(doLoad);
} else {
window.addEventListener('load', doLoad);
}
return;
}
<% } %>
}
function applyUpdate(callback, errback) {
<% if (typeof ServiceWorker !== 'undefined' && ServiceWorker.events) { %>
if (hasSW()) {
navigator.serviceWorker.getRegistration().then(function(registration) {
if (!registration || !registration.waiting) {
errback && errback();
return;
}
registration.waiting.postMessage({
action: 'skipWaiting'
});
callback && callback();
});
return;
}
<% } %>
<% if (typeof AppCache !== 'undefined' && AppCache.events && AppCache.disableInstall !== true) { %>
if (appCacheIframe) {
try {
appCacheIframe.contentWindow.__applyUpdate();
callback && setTimeout(callback);
} catch (e) {
errback && setTimeout(errback);
}
}
<% } %>
}
function update() {
<% if (typeof ServiceWorker !== 'undefined') { %>
if (hasSW()) {
navigator.serviceWorker.getRegistration().then(function(registration) {
if (!registration) return;
return registration.update();
});
}
<% } %>
<% if (typeof AppCache !== 'undefined' && AppCache.disableInstall !== true) { %>
if (appCacheIframe) {
try {
appCacheIframe.contentWindow.applicationCache.update();
} catch (e) {}
}
<% } %>
}
<% if (typeof autoUpdate !== 'undefined') { %>
setInterval(update, <%- autoUpdate %>);
<% } %>
exports.install = install;
exports.applyUpdate = applyUpdate;
exports.update = update;