Comparing version 1.0.4 to 1.1.0
220
dsw.js
@@ -10,2 +10,3 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
var bestMatchingGroup = Number.MAX_SAFE_INTEGER; | ||
var rx = []; // list of regular expressions | ||
rx.forEach(function (currentRX) { | ||
@@ -26,3 +27,3 @@ var regex = new RegExp(currentRX); | ||
},{}],2:[function(require,module,exports){ | ||
"use strict"; | ||
'use strict'; | ||
@@ -37,6 +38,6 @@ Object.defineProperty(exports, "__esModule", { | ||
function getObjectStore(dbName) { | ||
var mode = arguments.length <= 1 || arguments[1] === undefined ? "readwrite" : arguments[1]; | ||
var mode = arguments.length <= 1 || arguments[1] === undefined ? 'readwrite' : arguments[1]; | ||
var db = dbs[dbName]; | ||
var tx = db.transaction(dbName, mode); | ||
var db = dbs[dbName], | ||
tx = db.transaction(dbName, mode); | ||
return tx.objectStore(dbName); | ||
@@ -54,3 +55,3 @@ } | ||
db.close(); | ||
console.log("There is a new version of the database(IndexedDB) for " + config.name); | ||
console.log('There is a new version of the database(IndexedDB) for ' + config.name); | ||
}; | ||
@@ -128,3 +129,3 @@ | ||
(function (global){ | ||
"use strict"; | ||
'use strict'; | ||
@@ -137,7 +138,7 @@ Object.defineProperty(exports, "__esModule", { | ||
var _bestMatchingRx = require("./best-matching-rx.js"); | ||
var _bestMatchingRx = require('./best-matching-rx.js'); | ||
var _bestMatchingRx2 = _interopRequireDefault(_bestMatchingRx); | ||
var _indexeddbManager = require("./indexeddb-Manager.js"); | ||
var _indexeddbManager = require('./indexeddb-Manager.js'); | ||
@@ -148,4 +149,4 @@ var _indexeddbManager2 = _interopRequireDefault(_indexeddbManager); | ||
// TODO: add support to keepItHot: use a strategy with promise.race to always fetch the latest data and update the cache | ||
// TODO: add support to send the fetch options | ||
// TODO: should pre-cache or cache in the first load, some of the page's already sources (like css, js or images), or tell the user it supports offline usage, only in the next reload | ||
// TODO: add support to keepItWarm: use a strategy with promise.race() to always fetch the latest data and update the cache | ||
@@ -171,2 +172,18 @@ var isInSWScope = false; | ||
var treatBadPage = function treatBadPage(response, pathName, event) { | ||
var result = void 0; | ||
DSWManager.rules[response.status || 404].some(function (cur, idx) { | ||
var matching = pathName.match(cur.rx); | ||
if (matching) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = cacheManager.get(cur, new Request(cur.action.fetch), event, matching); | ||
return true; // stopping the loop | ||
} | ||
} | ||
}); | ||
return result || response; | ||
}; | ||
var cacheManager = { | ||
@@ -186,8 +203,8 @@ add: function add(req) { | ||
}, | ||
get: function get(rule, request, event) { | ||
get: function get(rule, request, event, matching) { | ||
var actionType = Object.keys(rule.action)[0], | ||
url = request.url, | ||
url = request.url || request, | ||
pathName = new URL(url).pathname; | ||
if (pathName == '/' || pathName.match(/\/index\.([a-z0-9]+)/i)) { | ||
if (pathName == '/' || pathName.match(/^\/index\.([a-z0-9]+)/i)) { | ||
// requisitions to / should | ||
@@ -210,3 +227,2 @@ actionType = 'cache'; | ||
switch (actionType) { | ||
// TODO: look for other kinds of cached data | ||
case 'idb': | ||
@@ -217,3 +233,17 @@ case 'IDB': | ||
return new Promise(function (resolve, reject) { | ||
// aqui | ||
// function to be used after fetching | ||
function treatFetch(response) { | ||
if (response && response.status == 200) { | ||
var done = function done(_) { | ||
resolve(response); | ||
}; | ||
// store it in the indexedDB | ||
_indexeddbManager2.default.save(rule.name, response.clone()).then(done).catch(done); // if failed saving, we still have the reponse to deliver | ||
} else { | ||
// TODO: treat the not found requests | ||
} | ||
} | ||
_indexeddbManager2.default.get(rule.name, request).then(function (result) { | ||
@@ -223,23 +253,7 @@ // if we did have it in the indexedDB | ||
// we use it | ||
debugger; | ||
console.log('found something'); | ||
// TODO: use it | ||
} else { | ||
// if it was not stored, let's fetch it | ||
var treatFetch = function treatFetch(response) { | ||
if (response && response.status == 200) { | ||
var done = function done(_) { | ||
resolve(response); | ||
}; | ||
// store it in the indexedDB | ||
_indexeddbManager2.default.save(rule.name, response.clone()).then(done).catch(done); // if failed saving, we still have the reponse to deliver | ||
} else { | ||
// TODO: treat the not found requests | ||
} | ||
}; | ||
// fetching | ||
result = fetch(request, opts).then(treatFetch).catch(treatFetch); | ||
@@ -250,19 +264,32 @@ } | ||
}); | ||
break; | ||
} | ||
case 'sessionStorage': | ||
{ | ||
//break; // TODO: see if there is support, somehow! | ||
} | ||
case 'redirect': | ||
case 'fetch': | ||
{ | ||
request = new Request(rule.action.fetch || rule.action.redirect); | ||
url = request.url; | ||
pathName = new URL(url).pathname; | ||
// keep going to be treated with the cache case | ||
(function () { | ||
var tmpUrl = rule.action.fetch || rule.action.redirect; | ||
if (matching.length > 2) { | ||
// applying variables | ||
matching.forEach(function (cur, idx) { | ||
tmpUrl = tmpUrl.replace(new RegExp('\\$' + idx, 'i'), cur); | ||
}); | ||
} | ||
request = new Request(tmpUrl, { | ||
method: opts.method || request.method, | ||
headers: opts || request.headers, | ||
mode: 'same-origin', // need to set this properly | ||
credentials: request.credentials, | ||
redirect: 'manual' // let browser handle redirects | ||
}); | ||
url = request.url; | ||
pathName = new URL(url).pathname; | ||
// keep going to be treated with the cache case | ||
})(); | ||
} | ||
case 'cache': | ||
{ | ||
var _ret2 = function () { | ||
var _ret3 = function () { | ||
@@ -304,10 +331,2 @@ var cacheId = DEFAULT_CACHE_NAME + '::' + DEFAULT_CACHE_VERSION; | ||
console.log('[ dsw ] :: Result was not in cache, was loaded and added to cache now', url); | ||
// if the rule told us to redirect it | ||
// we say that using the header status | ||
if (actionType == 'redirect') { | ||
response.statusText = 'Redirected'; | ||
response.status = 302; | ||
} | ||
return response; | ||
@@ -321,21 +340,43 @@ }); | ||
// for the 404 requisition | ||
DSWManager.rules[response.status].some(function (cur, idx) { | ||
if (pathName.match(cur.rx)) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = cacheManager.get(cur, event.request, event); | ||
return true; // stopping the loop | ||
} | ||
} | ||
}); | ||
return result || response; | ||
return treatBadPage(response, pathName, event); | ||
} | ||
}; | ||
// we will return the result, if successful, or | ||
// We will return the result, if successful, or | ||
// fetch an anternative resource(or redirect) | ||
// and treat both success and failure with the | ||
// same "callback" | ||
return result || fetch(request, opts).then(treatFetch).catch(treatFetch); | ||
// In case it is a redirect, we also set the header to 302 | ||
// and really change the url of the response. | ||
if (result) { | ||
// TODO: here, when it is from a redirect, it should let the browser know about it! | ||
if (request.url == event.request.url) { | ||
return result; | ||
} else { | ||
// coming from a redirect | ||
return Response.redirect(request.url, 302); | ||
// let req = new Request(request.url, { | ||
// method: opts.method || request.method, | ||
// headers: opts || request.headers, | ||
// mode: 'same-origin', // need to set this properly | ||
// credentials: request.credentials, | ||
// redirect: 'manual' // let browser handle redirects | ||
// }); | ||
// return fetch(req, opts) | ||
// .then(treatFetch) | ||
// .catch(treatFetch); | ||
} | ||
} else if (actionType == 'redirect') { | ||
return Response.redirect(request.url, 302); | ||
} else { | ||
var req = new Request(request.url, { | ||
method: opts.method || request.method, | ||
headers: opts || request.headers, | ||
mode: 'same-origin', // need to set this properly | ||
credentials: request.credentials, | ||
redirect: 'manual' // let browser handle redirects | ||
}); | ||
return fetch(req, opts).then(treatFetch).catch(treatFetch); | ||
} | ||
} | ||
@@ -346,3 +387,3 @@ }) | ||
if ((typeof _ret2 === "undefined" ? "undefined" : _typeof(_ret2)) === "object") return _ret2.v; | ||
if ((typeof _ret3 === 'undefined' ? 'undefined' : _typeof(_ret3)) === "object") return _ret3.v; | ||
} | ||
@@ -375,3 +416,3 @@ default: | ||
// easier to deal with, latelly on each requisition | ||
var preCache = [], | ||
var preCache = PWASettings.appShell || [], | ||
dbs = []; | ||
@@ -390,6 +431,6 @@ | ||
if (Array.isArray(extensions)) { | ||
var ending = "([\/\&\?]|$)"; | ||
var ending = '([\/\&\?]|$)'; | ||
extensions = '(' + extensions.join(ending + '|') + ending + ')'; | ||
} else { | ||
extensions = ".+"; | ||
extensions = '.+'; | ||
} | ||
@@ -401,7 +442,8 @@ | ||
// and now we "build" the regular expression itself! | ||
var rx = new RegExp(path + "(\\.)?((" + extensions + ")([\\?\&\/].+)?)", 'i'); | ||
var rx = new RegExp(path + '(\\.)?((' + extensions + ')([\\?\&\/].+)?)', 'i'); | ||
// if it fetches something, and this something is not dynamic | ||
// also, if it will redirect to some static url | ||
if (appl.fetch && !appl.fetch.match(/\$\{.+\}/) || appl.redirect && !appl.redirect.match(/\$\{.+\}/)) { | ||
var noVars = /\$[0-9]+/; | ||
if (appl.fetch && !appl.fetch.match(noVars) || appl.redirect && !appl.redirect.match(noVars)) { | ||
preCache.push(appl.fetch || appl.redirect); | ||
@@ -430,16 +472,18 @@ } | ||
// adding the dsw itself to cache | ||
_this.addRule("*", { | ||
_this.addRule('*', { | ||
name: 'serviceWorker', | ||
match: { path: location.href }, | ||
"apply": { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
match: { path: /^\/dsw.js(\?=dsw-manager)?$/ }, | ||
'apply': { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
}, location.href); | ||
// addinf the root path to be also cached by default | ||
var rootMatchingRX = /http(s)?\:\/\/[^\/]+\/([^\/]+)?$/i; | ||
_this.addRule("*", { | ||
var rootMatchingRX = /^(\/|\/index(\.[0-1a-z]+)?)$/; | ||
_this.addRule('*', { | ||
name: 'rootDir', | ||
match: { path: rootMatchingRX }, | ||
"apply": { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
'apply': { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
}, rootMatchingRX); | ||
preCache.unshift('/'); | ||
// if we've got urls to pre-store, let's cache them! | ||
@@ -466,3 +510,2 @@ // also, if there is any database to be created, this is the time | ||
self.addEventListener('fetch', function (event) { | ||
debugger; | ||
@@ -477,9 +520,19 @@ var url = new URL(event.request.url); | ||
var rule = DSWManager.rules['*'][i]; | ||
if (pathName.match(rule.rx)) { | ||
var matching = pathName.match(rule.rx); | ||
if (matching) { | ||
// if there is a rule that matches the url | ||
return event.respondWith(cacheManager.get(rule, event.request, event)); | ||
return event.respondWith(cacheManager.get(rule, event.request, event, matching)); | ||
} | ||
} | ||
// if no rule is applied, we simple request it | ||
return event.respondWith(fetch(event.request.url, {})); | ||
var defaultTreatment = function defaultTreatment(response) { | ||
if (response && response.status == 200) { | ||
return response; | ||
} else { | ||
return treatBadPage(response, pathName, event); | ||
} | ||
}; | ||
return event.respondWith(fetch(event.request.url, {}) | ||
// but we will still treat the error pages | ||
.then(defaultTreatment).catch(defaultTreatment)); | ||
}); | ||
@@ -490,4 +543,2 @@ } | ||
self.addEventListener('activate', function (event) { | ||
debugger; | ||
if (PWASettings.applyImmediately) { | ||
@@ -499,6 +550,3 @@ event.waitUntil(self.clients.claim()); | ||
self.addEventListener('install', function (event) { | ||
debugger; | ||
// TODO: maybe remove older cache, here? | ||
if (PWASettings.applyImmediately) { | ||
@@ -515,3 +563,2 @@ event.waitUntil(self.skipWaiting().then(function (_) { | ||
// TODO: add support to message event | ||
debugger; | ||
}); | ||
@@ -521,3 +568,2 @@ | ||
// TODO: add support to sync event | ||
debugger; | ||
}); | ||
@@ -541,3 +587,3 @@ | ||
} else { | ||
reject("Service worker not supported"); | ||
reject('Service worker not supported'); | ||
} | ||
@@ -544,0 +590,0 @@ }); |
@@ -30,3 +30,3 @@ #!/usr/bin/env node | ||
let jsonData = JSON.parse(settings); | ||
let vrs = parseFloat(jsonData.dswVersion || 0); | ||
let vrs = parseFloat(jsonData.dswVersion || 0).toFixed(1); | ||
if (vrs%1 !== 0) { | ||
@@ -33,0 +33,0 @@ vrs+= .1; |
{ | ||
"name": "dsw", | ||
"version": "1.0.4", | ||
"description": "Dynamic Service Worker", | ||
"version": "1.1.0", | ||
"description": "Dynamic Service Worker, offline Progressive Web Apps much easier", | ||
"bin": { | ||
@@ -12,11 +12,13 @@ "dsw": "./index.js" | ||
"scripts": { | ||
"test": "mocha tests/ --compilers js:babel-core/register", | ||
"build:js": "browserify src/main.js -o dsw.js -t [ babelify --presets [ es2015 ] ]", | ||
"build": "npm run build:js", | ||
"watch": "watch 'npm run build && echo Done' src", | ||
"try": "node index.js sandbox && http-server ./sandbox -p 8888" | ||
"test": "echo ':: Running tests:' && mocha tests/ --compilers js:babel-core/register", | ||
"lint": "echo ':: Linting the source files:' && eslint src/* && echo 'Done linting'", | ||
"docs": "echo ':: Generating documentation:' && docco -m -o docs/ docs/config-example.js", | ||
"build": "browserify src/main.js -o dsw.js -t [ babelify --presets [ es2015 ] ] && npm run docs && echo 'Done building'", | ||
"prepublish": "npm run lint", | ||
"watch": "watch 'npm run build' src", | ||
"try": "echo ':: Trying the sandbox sample:' && node index.js sandbox && http-server ./sandbox -p 8888" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/felipenmoura/dsw-dynamic-service-worker.git" | ||
"url": "git+https://github.com/NascHQ/dsw.git" | ||
}, | ||
@@ -35,5 +37,5 @@ "keywords": [ | ||
"bugs": { | ||
"url": "https://github.com/felipenmoura/dsw-dynamic-service-worker/issues" | ||
"url": "https://github.com/NascHQ/dsw/issues" | ||
}, | ||
"homepage": "https://github.com/felipenmoura/dsw-dynamic-service-worker#readme", | ||
"homepage": "https://github.com/NascHQ/dsw", | ||
"devDependencies": { | ||
@@ -48,8 +50,11 @@ "babel-core": "latest", | ||
"chai": "^3.5.0", | ||
"http-server": "latest", | ||
"jshint": "~2.9.1-rc1", | ||
"docco": "^0.7.0", | ||
"eslint": "^3.0.1", | ||
"minifier": "^0.7.1", | ||
"mocha": "latest", | ||
"watch": "latest" | ||
}, | ||
"dependencies": { | ||
"http-server": "latest" | ||
} | ||
} |
122
readme.md
@@ -0,4 +1,9 @@ | ||
[![Version](https://img.shields.io/npm/v/dsw.svg?label=Version&maxAge=2592000)](https://www.npmjs.com/package/dsw) | ||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/bb589aedc04b445d9633ddf66b55da06)](https://www.codacy.com/app/felipenmoura/dsw?utm_source=github.com&utm_medium=referral&utm_content=NascHQ/dsw/&utm_campaign=Badge_Grade) | ||
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/NascHQ/dsw/master/license.txt) | ||
[![GitHub issues](https://img.shields.io/github/issues/NascHQ/dsw.svg)](https://github.com/NascHQ/dsw/issues) | ||
[![Build Status](https://travis-ci.org/NascHQ/dsw.svg?branch=variables)](https://travis-ci.org/NascHQ/dsw) | ||
# Dynamic Service Worker | ||
DSW allows you to enable and use Service Workers in a much easier way, also helping you to create and maintain your Progressive Web Apps working offline. | ||
@@ -29,5 +34,5 @@ | ||
``` | ||
< script src="dsw.js"></script> | ||
< script> | ||
```html | ||
<script src="dsw.js"></script> | ||
<script> | ||
DSW.setup() | ||
@@ -68,3 +73,3 @@ .then(function(){ | ||
``` | ||
```js | ||
{ | ||
@@ -124,3 +129,3 @@ "dswVersion": 2.2, | ||
``` | ||
```js | ||
{ | ||
@@ -150,3 +155,3 @@ "dswVersion": 2.2, | ||
``` | ||
```js | ||
{ | ||
@@ -174,3 +179,3 @@ "dswVersion": 2.2, | ||
``` | ||
```js | ||
{ | ||
@@ -206,3 +211,3 @@ "dswVersion": 2.2, | ||
``` | ||
```js | ||
{ | ||
@@ -223,2 +228,49 @@ "dswVersion": 2.2, | ||
#### Caching EVERYTHING | ||
Maybe you want to cache everything. Every single request (that is successful) will be cached as soon as it is loaded the first time: | ||
```js | ||
{ | ||
"dswVersion": 2.2, | ||
"dswRules": { | ||
"secretPath": { | ||
"match": { | ||
"path": "\/.*" | ||
}, | ||
"apply": { | ||
"cache": { | ||
"name": "cached-files" | ||
"version": 1 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
#### Caching your static files | ||
Most of times you will want to cache all your static files, like _javascript_ files or _css_: | ||
```js | ||
{ | ||
"dswVersion": 2.2, | ||
"dswRules": { | ||
"secretPath": { | ||
"match": { | ||
"extension": ["js", "css"] | ||
}, | ||
"apply": { | ||
"cache": { | ||
"name": "page-static-files" | ||
"version": 1 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
# Contributing | ||
@@ -232,11 +284,61 @@ | ||
```git clone | ||
```git clone https://github.com/NascHQ/dsw``` | ||
2 - Enter the project directory | ||
```cd dsw``` | ||
3 - Start watching it | ||
```npm run watch``` | ||
4 - Use the sandbox to test it (run this command in another terminal window or tab, so the watch command can continue running) | ||
```npm run try``` | ||
5 - Access in the browser, the address in the right port, as provided by the previous command, something like: | ||
`http://localhost:8888/` | ||
Please notice we use `eslint` to validate the code styles. You can see the rules in the `.eslintrc.js` file. | ||
### Testing your changes | ||
Whenever you change any files inside the `src` directory, the _watch_ will re-build it for you (wait until you see the **"DONE"** output). | ||
This is automatic, but you stillneed to reload the _try_ command in the other tab: | ||
``` | ||
^C # ctrl+C to stop the previous try, and then... | ||
npm run try | ||
``` | ||
### Tips | ||
In the browser, though, you may face some boring situations, so, to make sure you will not fall into a trap debugging unchanged things, here goes some tips: | ||
- Go to the settings of your browser console and enable the "disable cache(when console is open)". This way, you will not be tricked by some unwanted caches. | ||
- Go to the _"Application"_ tab in your console (in chrome, it is in canary by now) and: | ||
1 - Click in _"Service workers"_ | ||
2 - Mark the box _"Show All"_ (and when there is more than one, you may click in "Unregister") | ||
3 - You can also check the box "Update on reload" to keep the latest service worker in command. | ||
4 - When you want to test how things are working offline, simply check the "Offline" box. | ||
5 - You can use the "Cache Storage" in the left panel to verify everything that has been cached. | ||
6 - You can use the Lighthouse to validate the service worker situation: | ||
[Lighthoust](https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=en) | ||
@@ -1,2 +0,2 @@ | ||
const PWASettings = {"dswVersion":2.3000000000000003,"applyImmediately":true,"dswRules":{"imageNotFound":{"match":{"status":[404,500],"extension":["jpg","gif","png","jpeg","webp"]},"apply":{"fetch":"/images/public/404.jpg"}},"redirectOlderPage":{"match":{"path":"/legacy-images/.*"},"apply":{"fetch":"/images/public/gizmo.jpg"}},"pageNotFound":{"match":{"status":[404]},"apply":{"fetch":"/404.html"}},"imageNotCached":{"match":{"path":"/images/not-cached"},"apply":{"cache":false}},"images":{"match":{"extension":["jpg","gif","png","jpeg","webp"]},"apply":{"cache":{"name":"cachedImages","version":"1"}}},"statics":{"match":{"extension":["js","css"]},"apply":{"cache":{"name":"static-files","version":"1"}}},"userData":{"match":{"path":"/api/user/.*"},"options":{"credentials":"same-origin"},"apply":{"indexedDB":{"name":"userData","version":"1","indexes":["name"]}}},"updates":{"match":{"path":"/api/updates/"},"keepItHot":true,"apply":{"indexedDB":{"name":"shownUpdates","version":"1"}}},"articles":{"match":{"path":"/api/updates/"},"apply":{"cache":{"name":"cachedArticles","version":"1"}}},"events":{"match":{"path":"/api/events/"},"apply":{"indexedDB":{"name":"eventsList","version":"1"}}},"lineup":{"match":{"path":"/api/events/(.*)/"},"apply":{"indexedDB":{"name":"eventLineup-$1","version":"1"}}}}}; | ||
const PWASettings = {"dswVersion":"2.20.1","applyImmediately":true,"appShell":[],"dswRules":{"moved-pages":{"match":{"path":"/old-site/(.*)"},"apply":{"redirect":"/redirected.html?$1"}},"imageNotFound":{"match":{"status":[404,500],"extension":["jpg","gif","png","jpeg","webp"]},"apply":{"fetch":"/images/public/404.jpg"}},"redirectOlderPage":{"match":{"path":"/legacy-images/.*"},"apply":{"fetch":"/images/public/gizmo.jpg"}},"pageNotFound":{"match":{"status":[404]},"apply":{"fetch":"/404.html"}},"imageNotCached":{"match":{"path":"/images/not-cached"},"apply":{"cache":false}},"images":{"match":{"extension":["jpg","gif","png","jpeg","webp"]},"apply":{"cache":{"name":"cachedImages","version":"1"}}},"statics":{"match":{"extension":["js","css"]},"apply":{"cache":{"name":"static-files","version":"1"}}},"static-html":{"match":{"extension":["html"]},"apply":{"cache":{"name":"static-html-files","version":"1"}}},"userData":{"match":{"path":"/api/user/.*"},"options":{"credentials":"same-origin"},"apply":{"indexedDB":{"name":"userData","version":"1","indexes":["name"]}}},"updates":{"match":{"path":"/api/updates/"},"keepItWarm":true,"apply":{"indexedDB":{"name":"shownUpdates","version":"1"}}},"articles":{"match":{"path":"/api/updates/"},"apply":{"cache":{"name":"cachedArticles","version":"1"}}},"events":{"match":{"path":"/api/events/"},"apply":{"indexedDB":{"name":"eventsList","version":"1"}}},"lineup":{"match":{"path":"/api/events/(.*)/"},"apply":{"indexedDB":{"name":"eventLineup-$1","version":"1"}}}}}; | ||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
@@ -11,2 +11,3 @@ "use strict"; | ||
var bestMatchingGroup = Number.MAX_SAFE_INTEGER; | ||
var rx = []; // list of regular expressions | ||
rx.forEach(function (currentRX) { | ||
@@ -27,3 +28,3 @@ var regex = new RegExp(currentRX); | ||
},{}],2:[function(require,module,exports){ | ||
"use strict"; | ||
'use strict'; | ||
@@ -38,6 +39,6 @@ Object.defineProperty(exports, "__esModule", { | ||
function getObjectStore(dbName) { | ||
var mode = arguments.length <= 1 || arguments[1] === undefined ? "readwrite" : arguments[1]; | ||
var mode = arguments.length <= 1 || arguments[1] === undefined ? 'readwrite' : arguments[1]; | ||
var db = dbs[dbName]; | ||
var tx = db.transaction(dbName, mode); | ||
var db = dbs[dbName], | ||
tx = db.transaction(dbName, mode); | ||
return tx.objectStore(dbName); | ||
@@ -55,3 +56,3 @@ } | ||
db.close(); | ||
console.log("There is a new version of the database(IndexedDB) for " + config.name); | ||
console.log('There is a new version of the database(IndexedDB) for ' + config.name); | ||
}; | ||
@@ -129,3 +130,3 @@ | ||
(function (global){ | ||
"use strict"; | ||
'use strict'; | ||
@@ -138,7 +139,7 @@ Object.defineProperty(exports, "__esModule", { | ||
var _bestMatchingRx = require("./best-matching-rx.js"); | ||
var _bestMatchingRx = require('./best-matching-rx.js'); | ||
var _bestMatchingRx2 = _interopRequireDefault(_bestMatchingRx); | ||
var _indexeddbManager = require("./indexeddb-Manager.js"); | ||
var _indexeddbManager = require('./indexeddb-Manager.js'); | ||
@@ -149,4 +150,4 @@ var _indexeddbManager2 = _interopRequireDefault(_indexeddbManager); | ||
// TODO: add support to keepItHot: use a strategy with promise.race to always fetch the latest data and update the cache | ||
// TODO: add support to send the fetch options | ||
// TODO: should pre-cache or cache in the first load, some of the page's already sources (like css, js or images), or tell the user it supports offline usage, only in the next reload | ||
// TODO: add support to keepItWarm: use a strategy with promise.race() to always fetch the latest data and update the cache | ||
@@ -168,2 +169,17 @@ var isInSWScope = false; | ||
(function () { | ||
var treatBadPage = function treatBadPage(response, pathName, event) { | ||
var result = void 0; | ||
DSWManager.rules[response.status || 404].some(function (cur, idx) { | ||
var matching = pathName.match(cur.rx); | ||
if (matching) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = cacheManager.get(cur, new Request(cur.action.fetch), event, matching); | ||
return true; // stopping the loop | ||
} | ||
} | ||
}); | ||
return result || response; | ||
}; | ||
@@ -187,8 +203,8 @@ var DEFAULT_CACHE_NAME = 'defaultDSWCached'; | ||
}, | ||
get: function get(rule, request, event) { | ||
get: function get(rule, request, event, matching) { | ||
var actionType = Object.keys(rule.action)[0], | ||
url = request.url, | ||
url = request.url || request, | ||
pathName = new URL(url).pathname; | ||
if (pathName == '/' || pathName.match(/\/index\.([a-z0-9]+)/i)) { | ||
if (pathName == '/' || pathName.match(/^\/index\.([a-z0-9]+)/i)) { | ||
// requisitions to / should | ||
@@ -211,3 +227,2 @@ actionType = 'cache'; | ||
switch (actionType) { | ||
// TODO: look for other kinds of cached data | ||
case 'idb': | ||
@@ -218,3 +233,17 @@ case 'IDB': | ||
return new Promise(function (resolve, reject) { | ||
// aqui | ||
// function to be used after fetching | ||
function treatFetch(response) { | ||
if (response && response.status == 200) { | ||
var done = function done(_) { | ||
resolve(response); | ||
}; | ||
// store it in the indexedDB | ||
_indexeddbManager2.default.save(rule.name, response.clone()).then(done).catch(done); // if failed saving, we still have the reponse to deliver | ||
} else { | ||
// TODO: treat the not found requests | ||
} | ||
} | ||
_indexeddbManager2.default.get(rule.name, request).then(function (result) { | ||
@@ -224,23 +253,7 @@ // if we did have it in the indexedDB | ||
// we use it | ||
debugger; | ||
console.log('found something'); | ||
// TODO: use it | ||
} else { | ||
// if it was not stored, let's fetch it | ||
var treatFetch = function treatFetch(response) { | ||
if (response && response.status == 200) { | ||
var done = function done(_) { | ||
resolve(response); | ||
}; | ||
// store it in the indexedDB | ||
_indexeddbManager2.default.save(rule.name, response.clone()).then(done).catch(done); // if failed saving, we still have the reponse to deliver | ||
} else { | ||
// TODO: treat the not found requests | ||
} | ||
}; | ||
// fetching | ||
result = fetch(request, opts).then(treatFetch).catch(treatFetch); | ||
@@ -251,19 +264,32 @@ } | ||
}); | ||
break; | ||
} | ||
case 'sessionStorage': | ||
{ | ||
//break; // TODO: see if there is support, somehow! | ||
} | ||
case 'redirect': | ||
case 'fetch': | ||
{ | ||
request = new Request(rule.action.fetch || rule.action.redirect); | ||
url = request.url; | ||
pathName = new URL(url).pathname; | ||
// keep going to be treated with the cache case | ||
(function () { | ||
var tmpUrl = rule.action.fetch || rule.action.redirect; | ||
if (matching.length > 2) { | ||
// applying variables | ||
matching.forEach(function (cur, idx) { | ||
tmpUrl = tmpUrl.replace(new RegExp('\\$' + idx, 'i'), cur); | ||
}); | ||
} | ||
request = new Request(tmpUrl, { | ||
method: opts.method || request.method, | ||
headers: opts || request.headers, | ||
mode: 'same-origin', // need to set this properly | ||
credentials: request.credentials, | ||
redirect: 'manual' // let browser handle redirects | ||
}); | ||
url = request.url; | ||
pathName = new URL(url).pathname; | ||
// keep going to be treated with the cache case | ||
})(); | ||
} | ||
case 'cache': | ||
{ | ||
var _ret2 = function () { | ||
var _ret3 = function () { | ||
@@ -305,10 +331,2 @@ var cacheId = DEFAULT_CACHE_NAME + '::' + DEFAULT_CACHE_VERSION; | ||
console.log('[ dsw ] :: Result was not in cache, was loaded and added to cache now', url); | ||
// if the rule told us to redirect it | ||
// we say that using the header status | ||
if (actionType == 'redirect') { | ||
response.statusText = 'Redirected'; | ||
response.status = 302; | ||
} | ||
return response; | ||
@@ -322,21 +340,43 @@ }); | ||
// for the 404 requisition | ||
DSWManager.rules[response.status].some(function (cur, idx) { | ||
if (pathName.match(cur.rx)) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = cacheManager.get(cur, event.request, event); | ||
return true; // stopping the loop | ||
} | ||
} | ||
}); | ||
return result || response; | ||
return treatBadPage(response, pathName, event); | ||
} | ||
}; | ||
// we will return the result, if successful, or | ||
// We will return the result, if successful, or | ||
// fetch an anternative resource(or redirect) | ||
// and treat both success and failure with the | ||
// same "callback" | ||
return result || fetch(request, opts).then(treatFetch).catch(treatFetch); | ||
// In case it is a redirect, we also set the header to 302 | ||
// and really change the url of the response. | ||
if (result) { | ||
// TODO: here, when it is from a redirect, it should let the browser know about it! | ||
if (request.url == event.request.url) { | ||
return result; | ||
} else { | ||
// coming from a redirect | ||
return Response.redirect(request.url, 302); | ||
// let req = new Request(request.url, { | ||
// method: opts.method || request.method, | ||
// headers: opts || request.headers, | ||
// mode: 'same-origin', // need to set this properly | ||
// credentials: request.credentials, | ||
// redirect: 'manual' // let browser handle redirects | ||
// }); | ||
// return fetch(req, opts) | ||
// .then(treatFetch) | ||
// .catch(treatFetch); | ||
} | ||
} else if (actionType == 'redirect') { | ||
return Response.redirect(request.url, 302); | ||
} else { | ||
var req = new Request(request.url, { | ||
method: opts.method || request.method, | ||
headers: opts || request.headers, | ||
mode: 'same-origin', // need to set this properly | ||
credentials: request.credentials, | ||
redirect: 'manual' // let browser handle redirects | ||
}); | ||
return fetch(req, opts).then(treatFetch).catch(treatFetch); | ||
} | ||
} | ||
@@ -347,3 +387,3 @@ }) | ||
if ((typeof _ret2 === "undefined" ? "undefined" : _typeof(_ret2)) === "object") return _ret2.v; | ||
if ((typeof _ret3 === 'undefined' ? 'undefined' : _typeof(_ret3)) === "object") return _ret3.v; | ||
} | ||
@@ -376,3 +416,3 @@ default: | ||
// easier to deal with, latelly on each requisition | ||
var preCache = [], | ||
var preCache = PWASettings.appShell || [], | ||
dbs = []; | ||
@@ -391,6 +431,6 @@ | ||
if (Array.isArray(extensions)) { | ||
var ending = "([\/\&\?]|$)"; | ||
var ending = '([\/\&\?]|$)'; | ||
extensions = '(' + extensions.join(ending + '|') + ending + ')'; | ||
} else { | ||
extensions = ".+"; | ||
extensions = '.+'; | ||
} | ||
@@ -402,7 +442,8 @@ | ||
// and now we "build" the regular expression itself! | ||
var rx = new RegExp(path + "(\\.)?((" + extensions + ")([\\?\&\/].+)?)", 'i'); | ||
var rx = new RegExp(path + '(\\.)?((' + extensions + ')([\\?\&\/].+)?)', 'i'); | ||
// if it fetches something, and this something is not dynamic | ||
// also, if it will redirect to some static url | ||
if (appl.fetch && !appl.fetch.match(/\$\{.+\}/) || appl.redirect && !appl.redirect.match(/\$\{.+\}/)) { | ||
var noVars = /\$[0-9]+/; | ||
if (appl.fetch && !appl.fetch.match(noVars) || appl.redirect && !appl.redirect.match(noVars)) { | ||
preCache.push(appl.fetch || appl.redirect); | ||
@@ -431,16 +472,18 @@ } | ||
// adding the dsw itself to cache | ||
_this.addRule("*", { | ||
_this.addRule('*', { | ||
name: 'serviceWorker', | ||
match: { path: location.href }, | ||
"apply": { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
match: { path: /^\/dsw.js(\?=dsw-manager)?$/ }, | ||
'apply': { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
}, location.href); | ||
// addinf the root path to be also cached by default | ||
var rootMatchingRX = /http(s)?\:\/\/[^\/]+\/([^\/]+)?$/i; | ||
_this.addRule("*", { | ||
var rootMatchingRX = /^(\/|\/index(\.[0-1a-z]+)?)$/; | ||
_this.addRule('*', { | ||
name: 'rootDir', | ||
match: { path: rootMatchingRX }, | ||
"apply": { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
'apply': { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION } } | ||
}, rootMatchingRX); | ||
preCache.unshift('/'); | ||
// if we've got urls to pre-store, let's cache them! | ||
@@ -467,3 +510,2 @@ // also, if there is any database to be created, this is the time | ||
self.addEventListener('fetch', function (event) { | ||
debugger; | ||
@@ -478,9 +520,19 @@ var url = new URL(event.request.url); | ||
var rule = DSWManager.rules['*'][i]; | ||
if (pathName.match(rule.rx)) { | ||
var matching = pathName.match(rule.rx); | ||
if (matching) { | ||
// if there is a rule that matches the url | ||
return event.respondWith(cacheManager.get(rule, event.request, event)); | ||
return event.respondWith(cacheManager.get(rule, event.request, event, matching)); | ||
} | ||
} | ||
// if no rule is applied, we simple request it | ||
return event.respondWith(fetch(event.request.url, {})); | ||
var defaultTreatment = function defaultTreatment(response) { | ||
if (response && response.status == 200) { | ||
return response; | ||
} else { | ||
return treatBadPage(response, pathName, event); | ||
} | ||
}; | ||
return event.respondWith(fetch(event.request.url, {}) | ||
// but we will still treat the error pages | ||
.then(defaultTreatment).catch(defaultTreatment)); | ||
}); | ||
@@ -491,4 +543,2 @@ } | ||
self.addEventListener('activate', function (event) { | ||
debugger; | ||
if (PWASettings.applyImmediately) { | ||
@@ -500,6 +550,3 @@ event.waitUntil(self.clients.claim()); | ||
self.addEventListener('install', function (event) { | ||
debugger; | ||
// TODO: maybe remove older cache, here? | ||
if (PWASettings.applyImmediately) { | ||
@@ -516,3 +563,2 @@ event.waitUntil(self.skipWaiting().then(function (_) { | ||
// TODO: add support to message event | ||
debugger; | ||
}); | ||
@@ -522,3 +568,2 @@ | ||
// TODO: add support to sync event | ||
debugger; | ||
}); | ||
@@ -542,3 +587,3 @@ | ||
} else { | ||
reject("Service worker not supported"); | ||
reject('Service worker not supported'); | ||
} | ||
@@ -545,0 +590,0 @@ }); |
{ | ||
"dswVersion": 2.2, | ||
"applyImmediately": true, | ||
"appShell": [], | ||
"dswRules": { | ||
"moved-pages": { | ||
"match": { "path": "\/old-site\/(.*)" }, | ||
"apply": { | ||
"redirect": "/redirected.html?$1" | ||
} | ||
}, | ||
"imageNotFound": { | ||
@@ -54,2 +61,11 @@ "match": { | ||
}, | ||
"static-html": { | ||
"match": { "extension": ["html"] }, | ||
"apply": { | ||
"cache": { | ||
"name": "static-html-files", | ||
"version": "1" | ||
} | ||
} | ||
}, | ||
"userData": { | ||
@@ -68,3 +84,3 @@ "match": { "path": "\/api\/user\/.*" }, | ||
"match": { "path": "\/api\/updates/" }, | ||
"keepItHot": true, | ||
"keepItWarm": true, | ||
"apply": { | ||
@@ -71,0 +87,0 @@ "indexedDB": { |
@@ -5,34 +5,59 @@ console.log('LOADED THE SCRIPT'); | ||
function set (el, attr, src) { | ||
el[attr] = ''; | ||
el[attr] = src; | ||
} | ||
document.getElementById('btn-img-1').addEventListener('click', function(){ | ||
document.getElementById('test-image').setAttribute('src', 'images/public/gears.png'); | ||
set(document.getElementById('test-1-image'), 'src', 'images/public/gears.png'); | ||
}); | ||
document.getElementById('btn-img-2').addEventListener('click', function(){ | ||
document.getElementById('test-image').setAttribute('src', 'images/public/something.png'); | ||
set(document.getElementById('test-2-image'), 'src', 'images/public/something.png'); | ||
}); | ||
document.getElementById('btn-img-3').addEventListener('click', function(){ | ||
document.getElementById('test-image').setAttribute('src', 'images/legacy-images/foo.png'); | ||
set(document.getElementById('test-3-image'), 'src', 'images/legacy-images/foo.png'); | ||
}); | ||
document.getElementById('btn-img-4').addEventListener('click', function(){ | ||
document.getElementById('test-image').setAttribute('src', 'images/not-cached.jpg'); | ||
set(document.getElementById('test-4-image'), 'src', 'images/not-cached.jpg'); | ||
}); | ||
document.getElementById('btn-img-5').addEventListener('click', function(){ | ||
fetch('/api/user/1.json').then(function(response){ | ||
response.text().then(function(text){ | ||
document.getElementById('fetch-result').innerHTML = text; | ||
}); | ||
}); | ||
document.getElementById('btn-5-page').addEventListener('click', function(){ | ||
set(document.getElementById('test-5-iframe'), 'src', '/foo.html'); | ||
}); | ||
document.getElementById('btn-6-data').addEventListener('click', function(){ | ||
set(document.getElementById('test-6-iframe'), 'src', '/api/user/1.json'); | ||
}); | ||
document.getElementById('btn-7-page').addEventListener('click', function(){ | ||
let listOfOlderPages = [ | ||
'index.html', | ||
'page-1.html', | ||
'about.html', | ||
'articles.html', | ||
'contact.html' | ||
]; | ||
let idx = Math.ceil(Math.random() * 5) -1; | ||
console.log(idx); | ||
set(document.getElementById('test-7-iframe'), 'src', '/old-site/' + | ||
listOfOlderPages[idx]); | ||
}); | ||
/* | ||
document.getElementById('btn-img-6').addEventListener('click', function(){ | ||
fetch('/api/user/2.json').then(function(response){ | ||
// fetch('/api/user/2.json').then(function(response){ | ||
// response.text().then(function(text){ | ||
// document.getElementById('fetch-result').innerHTML = text; | ||
// }); | ||
// }); | ||
}); | ||
document.getElementById('btn-7').addEventListener('click', function(){ | ||
fetch('/api/user/1.json').then(function(response){ | ||
response.text().then(function(text){ | ||
document.getElementById('fetch-result').innerHTML = text; | ||
document.getElementById('test-5-iframe').innerHTML = text; | ||
}); | ||
}); | ||
}); | ||
*/ | ||
}); |
function getBestMatchingRX(str){ | ||
let bestMatchingRX; | ||
let bestMatchingGroup = Number.MAX_SAFE_INTEGER; | ||
let rx = []; // list of regular expressions | ||
rx.forEach(function(currentRX){ | ||
@@ -5,0 +6,0 @@ const regex = new RegExp(currentRX); |
@@ -5,5 +5,5 @@ | ||
function getObjectStore(dbName, mode="readwrite") { | ||
let db = dbs[dbName] | ||
var tx = db.transaction(dbName, mode); | ||
function getObjectStore(dbName, mode='readwrite') { | ||
let db = dbs[dbName], | ||
tx = db.transaction(dbName, mode); | ||
return tx.objectStore(dbName); | ||
@@ -22,3 +22,3 @@ } | ||
db.close(); | ||
console.log("There is a new version of the database(IndexedDB) for "+ | ||
console.log('There is a new version of the database(IndexedDB) for '+ | ||
config.name); | ||
@@ -25,0 +25,0 @@ }; |
378
src/main.js
@@ -1,3 +0,3 @@ | ||
// TODO: add support to keepItHot: use a strategy with promise.race to always fetch the latest data and update the cache | ||
// TODO: add support to send the fetch options | ||
// TODO: should pre-cache or cache in the first load, some of the page's already sources (like css, js or images), or tell the user it supports offline usage, only in the next reload | ||
// TODO: add support to keepItWarm: use a strategy with promise.race() to always fetch the latest data and update the cache | ||
@@ -7,4 +7,4 @@ var isInSWScope = false; | ||
import getBestMatchingRX from "./best-matching-rx.js"; | ||
import indexedDBManager from "./indexeddb-Manager.js"; | ||
import getBestMatchingRX from './best-matching-rx.js'; | ||
import indexedDBManager from './indexeddb-Manager.js'; | ||
@@ -26,2 +26,21 @@ const DSW = {}; | ||
let treatBadPage = function (response, pathName, event) { | ||
let result; | ||
DSWManager.rules[response.status || 404].some((cur, idx)=>{ | ||
let matching = pathName.match(cur.rx); | ||
if (matching) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = cacheManager.get(cur, | ||
new Request(cur.action.fetch), | ||
event, | ||
matching); | ||
return true; // stopping the loop | ||
} | ||
} | ||
}); | ||
return result || response; | ||
}; | ||
const cacheManager = { | ||
@@ -39,8 +58,8 @@ add: (req, cacheId = DEFAULT_CACHE_NAME + '::' + DEFAULT_CACHE_VERSION) => { | ||
}, | ||
get: (rule, request, event)=>{ | ||
get: (rule, request, event, matching)=>{ | ||
let actionType = Object.keys(rule.action)[0], | ||
url = request.url, | ||
pathName = new URL(url).pathname; | ||
url = request.url || request, | ||
pathName = (new URL(url)).pathname; | ||
if (pathName == '/' || pathName.match(/\/index\.([a-z0-9]+)/i)) { | ||
if (pathName == '/' || pathName.match(/^\/index\.([a-z0-9]+)/i)) { | ||
// requisitions to / should | ||
@@ -58,3 +77,3 @@ actionType = 'cache'; | ||
url = request.url + (request.url.indexOf('?') > 0 ? '&' : '?') + (new Date).getTime(); | ||
pathName = new URL(url).pathname; | ||
pathName = (new URL(url)).pathname; | ||
request = new Request(url); | ||
@@ -64,138 +83,165 @@ } | ||
switch (actionType) { | ||
// TODO: look for other kinds of cached data | ||
case 'idb': | ||
case 'IDB': | ||
case 'indexedDB': { | ||
return new Promise((resolve, reject)=>{ | ||
// aqui | ||
indexedDBManager.get(rule.name, request) | ||
.then(result=>{ | ||
// if we did have it in the indexedDB | ||
if (result) { | ||
// we use it | ||
debugger; | ||
// TODO: use it | ||
}else{ | ||
// if it was not stored, let's fetch it | ||
function treatFetch (response) { | ||
if (response && response.status == 200) { | ||
let done = _=>{ | ||
resolve(response); | ||
}; | ||
// store it in the indexedDB | ||
indexedDBManager.save(rule.name, response.clone()) | ||
.then(done) | ||
.catch(done); // if failed saving, we still have the reponse to deliver | ||
}else{ | ||
// TODO: treat the not found requests | ||
} | ||
} | ||
// fetching | ||
result = fetch(request, | ||
opts) | ||
.then(treatFetch) | ||
.catch(treatFetch); | ||
} | ||
}); | ||
//indexedDBManager.save(rule.name, request); | ||
}); | ||
break; | ||
} | ||
case 'sessionStorage': { | ||
//break; // TODO: see if there is support, somehow! | ||
} | ||
case 'redirect': | ||
case 'fetch': { | ||
request = new Request(rule.action.fetch || rule.action.redirect); | ||
url = request.url; | ||
pathName = new URL(url).pathname; | ||
// keep going to be treated with the cache case | ||
} | ||
case 'cache': { | ||
case 'idb': | ||
case 'IDB': | ||
case 'indexedDB': { | ||
return new Promise((resolve, reject)=>{ | ||
let cacheId = DEFAULT_CACHE_NAME + '::' + DEFAULT_CACHE_VERSION; | ||
if(rule.action.cache){ | ||
cacheId = (rule.action.cache.name || DEFAULT_CACHE_NAME) + | ||
'::' + | ||
(rule.action.cache.version || DEFAULT_CACHE_VERSION); | ||
// function to be used after fetching | ||
function treatFetch (response) { | ||
if (response && response.status == 200) { | ||
let done = _=>{ | ||
resolve(response); | ||
}; | ||
// store it in the indexedDB | ||
indexedDBManager.save(rule.name, response.clone()) | ||
.then(done) | ||
.catch(done); // if failed saving, we still have the reponse to deliver | ||
}else{ | ||
// TODO: treat the not found requests | ||
} | ||
} | ||
return caches.match(request) | ||
indexedDBManager.get(rule.name, request) | ||
.then(result=>{ | ||
// if we did have it in the indexedDB | ||
if (result) { | ||
// we use it | ||
console.log('found something'); | ||
// TODO: use it | ||
}else{ | ||
// if it was not stored, let's fetch it | ||
// fetching | ||
result = fetch(request, | ||
opts) | ||
.then(treatFetch) | ||
.catch(treatFetch); | ||
} | ||
}); | ||
//indexedDBManager.save(rule.name, request); | ||
}); | ||
} | ||
case 'redirect': | ||
case 'fetch': { | ||
let tmpUrl = rule.action.fetch || rule.action.redirect; | ||
if (matching.length > 2) { | ||
// applying variables | ||
matching.forEach(function(cur, idx){ | ||
tmpUrl = tmpUrl.replace(new RegExp('\\$' + idx, 'i'), cur); | ||
}); | ||
} | ||
request = new Request(tmpUrl, { | ||
method: opts.method || request.method, | ||
headers: opts || request.headers, | ||
mode: 'same-origin', // need to set this properly | ||
credentials: request.credentials, | ||
redirect: 'manual' // let browser handle redirects | ||
}); | ||
url = request.url; | ||
pathName = new URL(url).pathname; | ||
// keep going to be treated with the cache case | ||
} | ||
case 'cache': { | ||
// if it does not exist (cache could not be verified) | ||
if (result && result.status != 200) { | ||
DSWManager.rules[result.status].some((cur, idx)=>{ | ||
if (pathName.match(cur.rx)) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = fetch(cur.action.fetch, | ||
cur.action.options); | ||
return true; // stopping the loop | ||
} | ||
let cacheId = DEFAULT_CACHE_NAME + '::' + DEFAULT_CACHE_VERSION; | ||
if(rule.action.cache){ | ||
cacheId = (rule.action.cache.name || DEFAULT_CACHE_NAME) + | ||
'::' + | ||
(rule.action.cache.version || DEFAULT_CACHE_VERSION); | ||
} | ||
return caches.match(request) | ||
.then(result=>{ | ||
// if it does not exist (cache could not be verified) | ||
if (result && result.status != 200) { | ||
DSWManager.rules[result.status].some((cur, idx)=>{ | ||
if (pathName.match(cur.rx)) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = fetch(cur.action.fetch, | ||
cur.action.options); | ||
return true; // stopping the loop | ||
} | ||
}); | ||
return result; | ||
}else{ | ||
let treatFetch = function (response) { | ||
if(!response.status){ | ||
response.status = 404; | ||
} | ||
// after retrieving it, we cache it | ||
// if it was ok | ||
if (response.status == 200) { | ||
// if cache is not false, it will be added to cache | ||
if (rule.action.cache !== false) { | ||
return caches.open(cacheId).then(function(cache) { | ||
cache.put(request, response.clone()); | ||
console.log('[ dsw ] :: Result was not in cache, was loaded and added to cache now', url); | ||
// if the rule told us to redirect it | ||
// we say that using the header status | ||
if (actionType == 'redirect') { | ||
response.statusText = 'Redirected'; | ||
response.status = 302; | ||
} | ||
return response; | ||
}); | ||
}else{ | ||
} | ||
}); | ||
return result; | ||
}else{ | ||
let treatFetch = function (response) { | ||
if(!response.status){ | ||
response.status = 404; | ||
} | ||
// after retrieving it, we cache it | ||
// if it was ok | ||
if (response.status == 200) { | ||
// if cache is not false, it will be added to cache | ||
if (rule.action.cache !== false) { | ||
return caches.open(cacheId).then(function(cache) { | ||
cache.put(request, response.clone()); | ||
console.log('[ dsw ] :: Result was not in cache, was loaded and added to cache now', url); | ||
return response; | ||
} | ||
} else { | ||
// otherwise...let's see if there is a fallback | ||
// for the 404 requisition | ||
DSWManager.rules[response.status].some((cur, idx)=>{ | ||
if (pathName.match(cur.rx)) { | ||
if (cur.action.fetch) { | ||
// not found requisitions should | ||
// fetch a different resource | ||
result = cacheManager.get(cur, event.request, event); | ||
return true; // stopping the loop | ||
} | ||
} | ||
}); | ||
return result || response; | ||
}else{ | ||
return response; | ||
} | ||
}; | ||
} else { | ||
// otherwise...let's see if there is a fallback | ||
// for the 404 requisition | ||
return treatBadPage(response, pathName, event); | ||
} | ||
}; | ||
// we will return the result, if successful, or | ||
// fetch an anternative resource(or redirect) | ||
// and treat both success and failure with the | ||
// same "callback" | ||
return result || fetch(request, opts) | ||
// We will return the result, if successful, or | ||
// fetch an anternative resource(or redirect) | ||
// and treat both success and failure with the | ||
// same "callback" | ||
// In case it is a redirect, we also set the header to 302 | ||
// and really change the url of the response. | ||
if (result) { | ||
// TODO: here, when it is from a redirect, it should let the browser know about it! | ||
if (request.url == event.request.url) { | ||
return result; | ||
} else { | ||
// coming from a redirect | ||
return Response.redirect(request.url, 302); | ||
// let req = new Request(request.url, { | ||
// method: opts.method || request.method, | ||
// headers: opts || request.headers, | ||
// mode: 'same-origin', // need to set this properly | ||
// credentials: request.credentials, | ||
// redirect: 'manual' // let browser handle redirects | ||
// }); | ||
// return fetch(req, opts) | ||
// .then(treatFetch) | ||
// .catch(treatFetch); | ||
} | ||
} else if (actionType == 'redirect') { | ||
return Response.redirect(request.url, 302); | ||
} else { | ||
let req = new Request(request.url, { | ||
method: opts.method || request.method, | ||
headers: opts || request.headers, | ||
mode: 'same-origin', // need to set this properly | ||
credentials: request.credentials, | ||
redirect: 'manual' // let browser handle redirects | ||
}); | ||
return fetch(req, opts) | ||
.then(treatFetch) | ||
.catch(treatFetch); | ||
} | ||
}); | ||
} | ||
default: { | ||
// also used in fetch actions | ||
return fetch(url); | ||
} | ||
} | ||
}); | ||
} | ||
default: { | ||
// also used in fetch actions | ||
return fetch(url); | ||
} | ||
} | ||
} | ||
@@ -219,3 +265,3 @@ }; | ||
// easier to deal with, latelly on each requisition | ||
let preCache = [], | ||
let preCache = PWASettings.appShell || [], | ||
dbs = []; | ||
@@ -234,6 +280,6 @@ | ||
if(Array.isArray(extensions)){ | ||
let ending = "([\/\&\?]|$)"; | ||
let ending = '([\/\&\?]|$)'; | ||
extensions = '(' + extensions.join(ending+'|') + ending + ')'; | ||
}else{ | ||
extensions = ".+" | ||
extensions = '.+'; | ||
} | ||
@@ -245,9 +291,10 @@ | ||
// and now we "build" the regular expression itself! | ||
let rx = new RegExp(path + "(\\.)?(("+ extensions +")([\\?\&\/].+)?)", 'i'); | ||
let rx = new RegExp(path + '(\\.)?(('+ extensions +')([\\?\&\/].+)?)', 'i'); | ||
// if it fetches something, and this something is not dynamic | ||
// also, if it will redirect to some static url | ||
if ( (appl.fetch && !appl.fetch.match(/\$\{.+\}/)) | ||
let noVars = /\$[0-9]+/; | ||
if ( (appl.fetch && !appl.fetch.match(noVars)) | ||
|| | ||
(appl.redirect && !appl.redirect.match(/\$\{.+\}/))) { | ||
(appl.redirect && !appl.redirect.match(noVars))) { | ||
preCache.push(appl.fetch || appl.redirect); | ||
@@ -276,16 +323,18 @@ } | ||
// adding the dsw itself to cache | ||
this.addRule("*", { | ||
this.addRule('*', { | ||
name: 'serviceWorker', | ||
match: { path: location.href }, | ||
"apply": { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION} } | ||
match: { path: /^\/dsw.js(\?=dsw-manager)?$/ }, | ||
'apply': { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION} } | ||
}, location.href); | ||
// addinf the root path to be also cached by default | ||
let rootMatchingRX = /http(s)?\:\/\/[^\/]+\/([^\/]+)?$/i; | ||
this.addRule("*", { | ||
let rootMatchingRX = /^(\/|\/index(\.[0-1a-z]+)?)$/; | ||
this.addRule('*', { | ||
name: 'rootDir', | ||
match: { path: rootMatchingRX }, | ||
"apply": { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION} } | ||
'apply': { cache: { name: DEFAULT_CACHE_NAME, version: DEFAULT_CACHE_VERSION} } | ||
}, rootMatchingRX); | ||
preCache.unshift('/'); | ||
// if we've got urls to pre-store, let's cache them! | ||
@@ -300,6 +349,5 @@ // also, if there is any database to be created, this is the time | ||
}).concat(dbs.map(function(cur) { | ||
return indexedDBManager.create(cur); | ||
}) | ||
) | ||
).then(resolve); | ||
return indexedDBManager.create(cur); | ||
}) | ||
)).then(resolve); | ||
}else{ | ||
@@ -318,6 +366,5 @@ resolve(); | ||
self.addEventListener('fetch', event=>{ | ||
debugger; | ||
const url = new URL(event.request.url); | ||
const pathName = new URL(url).pathname | ||
const pathName = (new URL(url)).pathname; | ||
@@ -329,9 +376,27 @@ let i = 0, | ||
let rule = DSWManager.rules['*'][i]; | ||
if (pathName.match(rule.rx)) { | ||
let matching = pathName.match(rule.rx); | ||
if (matching) { | ||
// if there is a rule that matches the url | ||
return event.respondWith(cacheManager.get(rule, event.request, event)); | ||
return event.respondWith( | ||
cacheManager.get(rule, | ||
event.request, | ||
event, | ||
matching) | ||
); | ||
} | ||
} | ||
// if no rule is applied, we simple request it | ||
return event.respondWith(fetch(event.request.url, {})); | ||
let defaultTreatment = function (response) { | ||
if (response && response.status == 200) { | ||
return response; | ||
} else { | ||
return treatBadPage(response, pathName, event); | ||
} | ||
}; | ||
return event.respondWith( | ||
fetch(event.request.url, {}) | ||
// but we will still treat the error pages | ||
.then(defaultTreatment) | ||
.catch(defaultTreatment) | ||
); | ||
}); | ||
@@ -342,4 +407,2 @@ } | ||
self.addEventListener('activate', function(event) { | ||
debugger; | ||
if (PWASettings.applyImmediately) { | ||
@@ -351,6 +414,3 @@ event.waitUntil(self.clients.claim()); | ||
self.addEventListener('install', function(event) { | ||
debugger; | ||
// TODO: maybe remove older cache, here? | ||
if (PWASettings.applyImmediately) { | ||
@@ -367,3 +427,2 @@ event.waitUntil(self.skipWaiting().then(_=>{ | ||
// TODO: add support to message event | ||
debugger; | ||
}); | ||
@@ -373,3 +432,2 @@ | ||
// TODO: add support to sync event | ||
debugger; | ||
}); | ||
@@ -395,3 +453,3 @@ | ||
}else{ | ||
reject("Service worker not supported"); | ||
reject('Service worker not supported'); | ||
} | ||
@@ -398,0 +456,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 12 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
1543284
60
3925
1
0
337
1
33
+ Addedhttp-server@latest
+ Addedansi-styles@4.3.0(transitive)
+ Addedasync@2.6.4(transitive)
+ Addedbasic-auth@2.0.1(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addedchalk@4.1.2(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedcorser@2.0.1(transitive)
+ Addeddebug@3.2.7(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedeventemitter3@4.0.7(transitive)
+ Addedfollow-redirects@1.15.9(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhe@1.2.0(transitive)
+ Addedhtml-encoding-sniffer@3.0.0(transitive)
+ Addedhttp-proxy@1.18.1(transitive)
+ Addedhttp-server@14.1.1(transitive)
+ Addediconv-lite@0.6.3(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedmime@1.6.0(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addedms@2.1.3(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedopener@1.5.2(transitive)
+ Addedportfinder@1.0.32(transitive)
+ Addedqs@6.13.1(transitive)
+ Addedrequires-port@1.0.0(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsecure-compare@3.0.1(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedside-channel@1.0.6(transitive)
+ Addedsupports-color@7.2.0(transitive)
+ Addedunion@0.5.0(transitive)
+ Addedurl-join@4.0.1(transitive)
+ Addedwhatwg-encoding@2.0.0(transitive)