Last active
April 7, 2021 05:37
-
-
Save LeonanCarvalho/0527526a6b784b23facf56fa3cc12d22 to your computer and use it in GitHub Desktop.
Cache service worker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* global caches, Promise */ | |
//Arquivo apenas para facilitar a edição do javascript, deve ser colado no .php// Não minificar | |
importScripts('serviceworker-cache-polyfill.js'); | |
// While overkill for this specific sample in which there is only one cache, | |
// this is one best practice that can be followed in general to keep track of | |
// multiple caches used by a given service worker, and keep them all versioned. | |
// It maps a shorthand identifier for a cache to a specific, versioned cache name. | |
// Note that since global state is discarded in between service worker restarts, these | |
// variables will be reinitialized each time the service worker handles an event, and you | |
// should not attempt to change their values inside an event handler. (Treat them as constants.) | |
// If at any point you want to force pages that use this service worker to start using a fresh | |
// cache, then increment the CACHE_VERSION value. It will kick off the service worker update | |
// flow and the old cache(s) will be purged as part of the activate event handler when the | |
// updated service worker is activated. | |
var CACHE_SCOPE = location.origin + "/"; | |
var CACHE_VERSION = 0; | |
var CACHE_VERSION_OLD = 0; | |
var CURRENT_CACHES = { | |
'perma-cache': 'perma-cache', //Cache que não é apagado através das versões. | |
'prefetch-cache': 'prefetch-cache-v' + CACHE_VERSION, //Cache prefetch | |
'general-cache': 'general-cache-v' + CACHE_VERSION, | |
}; | |
var logger = false; | |
self.addEventListener('activate', function (event) { | |
//console.log('Handling activate event:', event); | |
// Delete all caches that aren't named in CURRENT_CACHES. | |
// While there is only one cache in this example, the same logic will handle the case where | |
// there are multiple versioned caches. | |
var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function (key) { | |
return CURRENT_CACHES[key]; | |
}); | |
event.waitUntil( | |
caches.keys().then(function (cacheNames) { | |
return Promise.all( | |
cacheNames.map(function (cacheName) { | |
if (expectedCacheNames.indexOf(cacheName) === -1) { | |
// If this cache name isn't present in the array of "expected" cache names, then delete it. | |
//console.log('Deleting out of date cache:', cacheName); | |
return caches.delete(cacheName); | |
} | |
}) | |
); | |
}) | |
); | |
// `claim()` sets this worker as the active worker for all clients that | |
// match the workers scope and triggers an `oncontrollerchange` event for | |
// the clients. | |
return self.clients.claim(); | |
}); | |
self.addEventListener('message', function (event) { | |
//console.log('Handling message event:', event); | |
var cacheName = (undefined !== event.data.cachename && event.data.cachename in CURRENT_CACHES) ? event.data.cachename : "general-cache"; | |
// //console.log(cacheName); | |
caches.open(CURRENT_CACHES[cacheName]).then(function (cache) { | |
switch (event.data.command) { | |
// This command returns a list of the URLs corresponding to the Request objects | |
// that serve as keys for the current cache. | |
case 'keys': | |
cache.keys().then(function (requests) { | |
var urls = requests.map(function (request) { | |
return request.url; | |
}); | |
// event.ports[0] corresponds to the MessagePort that was transferred as part of the controlled page's | |
// call to controller.postMessage(). Therefore, event.ports[0].postMessage() will trigger the onmessage | |
// handler from the controlled page. | |
// It's up to you how to structure the messages that you send back; this is just one example. | |
event.ports[0].postMessage({ | |
error: null, | |
urls: urls.sort() | |
}); | |
}); | |
break; | |
// This command adds a new request/response pair to the cache. | |
case 'add': | |
// If event.data.url isn't a valid URL, new Request() will throw a TypeError which will be handled | |
// by the outer .catch(). | |
// Hardcode {mode: 'no-cors} since the default for new Requests constructed from strings is to require | |
// CORS, and we don't have any way of knowing whether an arbitrary URL that a user entered supports CORS. | |
var request = new Request(event.data.url, {mode: 'no-cors'}); | |
cache.add(request).then(function () { | |
event.ports[0].postMessage({ | |
error: null | |
}); | |
}); | |
break; | |
// This command removes a request/response pair from the cache (assuming it exists). | |
case 'delete': | |
var request = new Request(event.data.url, {mode: 'no-cors'}); | |
cache.delete(request).then(function (success) { | |
event.ports[0].postMessage({ | |
error: success ? null : 'Item was not found in the cache.' | |
}); | |
}); | |
break; | |
case 'deleteAll': | |
caches.keys().then(function (cacheNames) { | |
return Promise.all( | |
cacheNames.map(function (cacheName) { | |
if (cacheName !== CURRENT_CACHES['perma-cache']) { | |
// If this cache name isn't present in the array of "expected" cache names, then delete it. | |
//console.log('Deleting cache:', cacheName); | |
return caches.delete(cacheName); | |
} | |
}) | |
); | |
}) | |
var request = new Request(event.data.url, {mode: 'no-cors'}); | |
cache.delete(request).then(function (success) { | |
event.ports[0].postMessage({ | |
error: success ? null : 'Item was not found in the cache.' | |
}); | |
}); | |
break; | |
case 'rev': | |
var isSame = true; | |
if ((CACHE_VERSION != CACHE_VERSION_OLD) || (CACHE_VERSION != event.data.rev)) { | |
isSame = false; | |
CACHE_VERSION = event.data.rev; | |
CURRENT_CACHES = { | |
'perma-cache': 'perma-cache', | |
'general-cache': 'general-cache-v' + CACHE_VERSION | |
}; | |
var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function (key) { | |
return CURRENT_CACHES[key]; | |
}); | |
caches.keys().then(function (cacheNames) { | |
return Promise.all( | |
cacheNames.map(function (cacheName) { | |
if (expectedCacheNames.indexOf(cacheName) === -1) { | |
// If this cache name isn't present in the array of "expected" cache names, then delete it. | |
//console.log('Deleting old cache:', cacheName); | |
return caches.delete(cacheName); | |
} | |
}) | |
); | |
}); | |
} | |
event.ports[0].postMessage({ | |
error: null, | |
isSame: isSame | |
}); | |
break; | |
default: | |
// This will be handled by the outer .catch(). | |
throw 'Unknown command: ' + event.data.command; | |
} | |
}).catch(function (error) { | |
// If the promise rejects, handle it by returning a standardized error message to the controlled page. | |
console.error('Message handling failed:', error); | |
event.ports[0].postMessage({ | |
error: error.toString() | |
}); | |
}); | |
}); | |
// Urls to Prefetch :) | |
var urlsToPrefetch = [ | |
//JS | |
"plugin/angular/angular.min.js", "plugin/requirejs/require.min.js","app/main.js","app/app.js","app/includes.js" | |
//CSS | |
,"styles/css/print.css","styles/css/bootstrap.css","styles/css/fixes.css", | |
//Html | |
,"app/layout/partials/menu.tpl.html", "app/layout/public.tpl.html", | |
//JSON | |
,"app/i18n/languages.json","app/i18n/pt-br.json", "app/i18n/en.json" | |
]; | |
self.addEventListener('sync', function (event) { | |
logger && console.log('Handling sync event:', event); | |
}); | |
self.addEventListener('install', function (event) { | |
logger && console.log('Handling install event:', event); | |
//var now = Date.now(); | |
// All of these logging statements should be visible via the "Inspect" interface | |
// for the relevant SW accessed via chrome://serviceworker-internals | |
if (urlsToPrefetch.length > 0) { | |
logger && console.log('Handling install event. Resources to prefetch:', urlsToPrefetch.length , "resources"); | |
event.waitUntil( | |
caches.open(CURRENT_CACHES['prefetch-cache']).then(function (cache) { | |
var cachePromises = urlsToPrefetch.map(function (urlToPrefetch) { | |
urlToPrefetch += '?v=' + CACHE_VERSION; | |
// This constructs a new URL object using the service worker's script location as the base | |
// for relative URLs. | |
//var url = new URL(urlToPrefetch + '?v=' + CACHE_VERSION, location.href); | |
var url = new URL(urlToPrefetch, location.href); | |
// Append a cache-bust=TIMESTAMP URL parameter to each URL's query string. | |
// This is particularly important when precaching resources that are later used in the | |
// fetch handler as responses directly, without consulting the network (i.e. cache-first). | |
// If we were to get back a response from the HTTP browser cache for this precaching request | |
// then that stale response would be used indefinitely, or at least until the next time | |
// the service worker script changes triggering the install flow. | |
//url.search += (url.search ? '&' : '?') + 'v=' + CACHE_VERSION; | |
// It's very important to use {mode: 'no-cors'} if there is any chance that | |
// the resources being fetched are served off of a server that doesn't support | |
// CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). | |
// In this example, www.chromium.org doesn't support CORS, and the fetch() | |
// would fail if the default mode of 'cors' was used for the fetch() request. | |
// The drawback of hardcoding {mode: 'no-cors'} is that the response from all | |
// cross-origin hosts will always be opaque | |
// (https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cross-origin-resources) | |
// and it is not possible to determine whether an opaque response represents a success or failure | |
// (https://github.com/whatwg/fetch/issues/14). | |
var request = new Request(url, {mode: 'no-cors'}); | |
return fetch(request).then(function (response) { | |
logger && console.log('Add to Cache (Prefetch)', url.href); | |
if (!response || response.status !== 200 || response.type !== 'basic') { | |
throw new Error('request for ' + urlToPrefetch + | |
' failed with status ' + response.statusText); | |
} | |
//var responseToCache = response.clone(); | |
// Use the original URL without the cache-busting parameter as the key for cache.put(). | |
// return cache.put(urlToPrefetch, responseToCache); | |
return cache.put(urlToPrefetch, response); | |
}).catch(function (error) { | |
logger && console.error('Not caching ' + urlToPrefetch + ' due to ' + error); | |
}); | |
}); | |
return Promise.all(cachePromises).then(function () { | |
logger && console.log('Pre-fetching complete.'); | |
}); | |
}).catch(function (error) { | |
logger && console.error('Pre-fetching failed:', error); | |
})); | |
} | |
// Perform install steps | |
// if (urlsToPrefetch.length > 0) { | |
// event.waitUntil( | |
// caches.open(CURRENT_CACHES['perma-cache']) | |
// .then(function (cache) { | |
// return cache.addAll(urlsToPrefetch); | |
// }) | |
// ); | |
// } | |
// `skipWaiting()` forces the waiting ServiceWorker to become the | |
// active ServiceWorker, triggering the `onactivate` event. | |
// Together with `Clients.claim()` this allows a worker to take effect | |
// immediately in the client(s). | |
return self.skipWaiting(); | |
}); | |
//self.addEventListener('fetch', function(event) { | |
// //console.log(event.request); | |
// event.respondWith( | |
// caches.match(event.request) | |
// .then(function(response) { | |
// if (response) { | |
// //console.log('From Service Worker:',response); | |
// return response; | |
// } | |
// | |
// return fetch(event.request); | |
// } | |
// ) | |
// ); | |
//}); | |
self.addEventListener('fetch', function (event) { | |
//console.log(event); | |
if (event.request.method === "GET") { | |
var qSFilter = "" + ((event.request.url).split('?'))[0];//Filtrar Quetry Stirng | |
//console.log(event.request.url, qSFilter, qSFilter.split(CACHE_SCOPE), CACHE_SCOPE); | |
var leUrl = (qSFilter.split(CACHE_SCOPE))[1]; | |
//Adiciona os arquivos selecionados ao cache | |
//console.log(leUrl, /^(app|style|plugin).*(js|css|html|jpe?g|png|gif|json|woff2?)$/.test(leUrl)); | |
if (/^(app|style|plugin).*(js|css|html|jpe?g|png|gif|json|woff2?)$/.test(leUrl) | |
|| /^backend\/server\/file\/i18n\/((?!client).+)\//.test(leUrl) | |
|| /^backend\/server\/static\/images\/.*$/.test(leUrl) | |
|| /^backend\/server\/static\/style.*$/.test(leUrl) | |
) { | |
var url = new URL(leUrl + '?v=' + CACHE_VERSION, location.href); | |
var synthetic = new Request(url, {mode: 'no-cors'}); | |
//console.log(event.request,response.clone(),synthetic); | |
event.respondWith( | |
// caches.match(event.request) | |
caches.match(synthetic) | |
.then(function (response) { | |
// Cache hit - return response | |
if (response) { | |
logger && console.log('From Cache', event.request.url); | |
return response; | |
} | |
// IMPORTANT: Clone the request. A request is a stream and | |
// can only be consumed once. Since we are consuming this | |
// once by cache and once by the browser for fetch, we need | |
// to clone the response | |
var fetchRequest = event.request.clone(); | |
return fetch(fetchRequest).then( | |
function (response) { | |
// Check if we received a valid response | |
if (!response || response.status !== 200 || response.type !== 'basic') { | |
return response; | |
} | |
// IMPORTANT: Clone the response. A response is a stream | |
// and because we want the browser to consume the response | |
// as well as the cache consuming the response, we need | |
// to clone it so we have 2 stream. | |
var responseToCache = response.clone(); | |
caches.open(CURRENT_CACHES['general-cache']) | |
.then(function (cache) { | |
try { | |
logger && console.log('Add to Cache', event.request.url, qSFilter,leUrl); | |
cache.put(event.request, responseToCache); | |
} catch (e) { | |
console.error(e); | |
} | |
}); | |
return response; | |
} | |
); | |
}) | |
); | |
} | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2015 Google Inc. All rights reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
*/ | |
if (!Cache.prototype.addAll) { | |
Cache.prototype.addAll = function addAll(requests) { | |
var cache = this; | |
// Since DOMExceptions are not constructable: | |
function NetworkError(message) { | |
this.name = 'NetworkError'; | |
this.code = 19; | |
this.message = message; | |
} | |
NetworkError.prototype = Object.create(Error.prototype); | |
return Promise.resolve().then(function() { | |
if (arguments.length < 1) throw new TypeError(); | |
// Simulate sequence<(Request or USVString)> binding: | |
var sequence = []; | |
requests = requests.map(function(request) { | |
if (request instanceof Request) { | |
return request; | |
} | |
else { | |
return String(request); // may throw TypeError | |
} | |
}); | |
return Promise.all( | |
requests.map(function(request) { | |
if (typeof request === 'string') { | |
request = new Request(request); | |
} | |
var scheme = new URL(request.url).protocol; | |
if (scheme !== 'http:' && scheme !== 'https:') { | |
throw new NetworkError("Invalid scheme"); | |
} | |
return fetch(request.clone()); | |
}) | |
); | |
}).then(function(responses) { | |
// TODO: check that requests don't overwrite one another | |
// (don't think this is possible to polyfill due to opaque responses) | |
return Promise.all( | |
responses.map(function(response, i) { | |
return cache.put(requests[i], response); | |
}) | |
); | |
}).then(function() { | |
return undefined; | |
}); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment