From 0cdd4704a9ec33f5d18c9dadb7bdc06541cc79ce Mon Sep 17 00:00:00 2001 From: David Heidrich Date: Thu, 7 Dec 2017 14:17:39 +0100 Subject: [PATCH 1/6] #324, make networkFirstResponse configurable --- src/index.js | 1 + src/misc/sw-template.js | 2 +- src/service-worker.js | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 6675df0c..8943bb6e 100644 --- a/src/index.js +++ b/src/index.js @@ -50,6 +50,7 @@ const defaultOptions = { cache: void 0 }, minify: null, + shouldServeFromNetwork: (response) => response.ok, navigateFallbackForRedirects: true }, diff --git a/src/misc/sw-template.js b/src/misc/sw-template.js index f3fae77f..0dd7b8cd 100644 --- a/src/misc/sw-template.js +++ b/src/misc/sw-template.js @@ -375,7 +375,7 @@ function WebpackServiceWorker(params, helpers) { function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request) .then((response) => { - if (response.ok) { + if (params.shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', `URL [${ urlString }] from network`); } diff --git a/src/service-worker.js b/src/service-worker.js index 144c1e95..8640a963 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -16,7 +16,7 @@ export default class ServiceWorker { this.minify = options.minify; this.output = options.output.replace(/^\.\/+/, ''); this.publicPath = options.publicPath; - + this.shouldServeFromNetwork = options.shouldServeFromNetwork; this.basePath = null; this.location = null; this.pathRewrite = null; @@ -185,7 +185,7 @@ export default class ServiceWorker { }, externals: externals, - + shouldServeFromNetwork: this.shouldServeFromNetwork, hashesMap: hashesMap, navigateFallbackURL: this.navigateFallbackURL, navigateFallbackForRedirects: this.navigateFallbackURL ? From fe3be2164f3c9dd759c73a7d02c925da80f41030 Mon Sep 17 00:00:00 2001 From: David Heidrich Date: Thu, 7 Dec 2017 14:23:59 +0100 Subject: [PATCH 2/6] #324, added docs --- docs/options.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/options.md b/docs/options.md index 7a480558..5c57de7a 100755 --- a/docs/options.md +++ b/docs/options.md @@ -114,6 +114,10 @@ _Example:_ `{ credentials: 'same-origin' }` * `minify`: `boolean`. If set to `true` or `false`, the `ServiceWorker`'s output will be minified or not accordingly. If set to something else, the `ServiceWorker` output will be minified **if** you are using `webpack.optimize.UglifyJsPlugin` in your configuration. _Default:_ `null` +* `shouldServeFromNetwork`: `(response: Response, urlString: string, cacheUrl: string) => boolean`. +Allows to customize the behaviour when to fallback to a cached version of a resource if `responseStrategy: 'network-first'`. +Defaults to `(response) => response.ok`, meaning a response is only valid when the server returns a 2xx status code (see https://developer.mozilla.org/de/docs/Web/API/Response). + #### `AppCache: Object | null | false` Settings for the `AppCache` cache. Use `null` or `false` to disable `AppCache` generation. From 4850042c4db432c277976d9fd3ac1fbef663f6c4 Mon Sep 17 00:00:00 2001 From: David Heidrich Date: Mon, 11 Dec 2017 13:39:30 +0100 Subject: [PATCH 3/6] #324, added tests, fixed implementation, do not set default shouldServeFromNetwork --- lib/misc/sw-template.js | 9 +++- lib/service-worker.js | 16 ++++-- package.json | 1 + src/index.js | 1 - src/misc/sw-template.js | 9 +++- src/service-worker.js | 17 ++++++- .../basic-wIth-sw-out/__expected/sw.js | 9 +++- .../__expected/sw.js | 9 +++- .../fixtures/cachemaps-basic/__expected/sw.js | 9 +++- .../loaders-externals/__expected/sw.js | 9 +++- .../__expected/main.js | 50 +++++++++++++++++++ .../__expected/sw.js | 24 +++++++++ .../main.js | 0 .../webpack.config.js | 17 +++++++ .../fixtures/sw-minify-false/__expected/sw.js | 9 +++- .../fixtures/sw-minify-true/__expected/sw.js | 2 +- 16 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/main.js create mode 100644 tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/sw.js create mode 100644 tests/legacy/fixtures/network-first-response-should-serve-from-network/main.js create mode 100644 tests/legacy/fixtures/network-first-response-should-serve-from-network/webpack.config.js diff --git a/lib/misc/sw-template.js b/lib/misc/sw-template.js index b4a5495f..fbf64dd2 100644 --- a/lib/misc/sw-template.js +++ b/lib/misc/sw-template.js @@ -358,9 +358,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } diff --git a/lib/service-worker.js b/lib/service-worker.js index 4beaa4ca..8b0122d4 100644 --- a/lib/service-worker.js +++ b/lib/service-worker.js @@ -28,6 +28,8 @@ var _deepExtend2 = _interopRequireDefault(_deepExtend); var _miscUtils = require('./misc/utils'); +var REGEX_MINIFY_FUNC = /(\r\n|\n|\r|\s+)/gm; + var ServiceWorker = (function () { function ServiceWorker(options) { _classCallCheck(this, ServiceWorker); @@ -39,7 +41,7 @@ var ServiceWorker = (function () { this.minify = options.minify; this.output = options.output.replace(/^\.\/+/, ''); this.publicPath = options.publicPath; - + this.shouldServeFromNetwork = options.shouldServeFromNetwork; this.basePath = null; this.location = null; this.pathRewrite = null; @@ -199,7 +201,9 @@ var ServiceWorker = (function () { var loaders = Object.keys(plugin.loaders).length ? plugin.loaders : void 0; - return ('\n var ' + this.SW_DATA_VAR + ' = ' + JSON.stringify({ + var shouldServeFromNetworkPlaceholder = this.shouldServeFromNetwork ? '__func_should_serve_from_network__' : undefined; + var functionResult = this.shouldServeFromNetwork && (minify ? this.shouldServeFromNetwork.toString().replace(REGEX_MINIFY_FUNC, '') : this.shouldServeFromNetwork.toString()); + var result = ('\n var ' + this.SW_DATA_VAR + ' = ' + JSON.stringify({ assets: { main: cache('main'), additional: cache('additional'), @@ -207,7 +211,7 @@ var ServiceWorker = (function () { }, externals: externals, - + shouldServeFromNetwork: shouldServeFromNetworkPlaceholder, hashesMap: hashesMap, navigateFallbackURL: this.navigateFallbackURL, navigateFallbackForRedirects: this.navigateFallbackURL ? this.navigateFallbackForRedirects : void 0, @@ -227,6 +231,12 @@ var ServiceWorker = (function () { preferOnline: plugin.preferOnline, ignoreSearch: plugin.ignoreSearch }, null, minify ? void 0 : ' ') + ';\n ').trim(); + + if (functionResult) { + return result.replace('"' + shouldServeFromNetworkPlaceholder + '"', functionResult.trim()); + } + + return result; } }, { key: 'getConfig', diff --git a/package.json b/package.json index d0bc3d9a..96027048 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "author": "Arthur Stolyar ", "license": "MIT", "dependencies": { + "babel": "^5.8.38", "deep-extend": "^0.4.0", "ejs": "^2.3.4", "loader-utils": "0.2.x", diff --git a/src/index.js b/src/index.js index 8943bb6e..6675df0c 100644 --- a/src/index.js +++ b/src/index.js @@ -50,7 +50,6 @@ const defaultOptions = { cache: void 0 }, minify: null, - shouldServeFromNetwork: (response) => response.ok, navigateFallbackForRedirects: true }, diff --git a/src/misc/sw-template.js b/src/misc/sw-template.js index 0dd7b8cd..0305a988 100644 --- a/src/misc/sw-template.js +++ b/src/misc/sw-template.js @@ -372,10 +372,17 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request) .then((response) => { - if (params.shouldServeFromNetwork(response, urlString, cacheUrl)) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', `URL [${ urlString }] from network`); } diff --git a/src/service-worker.js b/src/service-worker.js index 8640a963..4e84625b 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -4,6 +4,8 @@ import webpack from 'webpack'; import deepExtend from 'deep-extend'; import { getSource, pathToBase, isAbsoluteURL, isAbsolutePath } from './misc/utils'; +const REGEX_MINIFY_FUNC = /(\r\n|\n|\r|\s+)/gm; + export default class ServiceWorker { constructor(options) { if (isAbsolutePath(options.output)) { @@ -176,7 +178,12 @@ export default class ServiceWorker { const loaders = Object.keys(plugin.loaders).length ? plugin.loaders : void 0; - return ` + const shouldServeFromNetworkPlaceholder = + this.shouldServeFromNetwork ? '__func_should_serve_from_network__' : undefined; + const functionResult = this.shouldServeFromNetwork && + (minify ? this.shouldServeFromNetwork.toString().replace(REGEX_MINIFY_FUNC, '') : + this.shouldServeFromNetwork.toString()); + const result = ` var ${ this.SW_DATA_VAR } = ${ JSON.stringify({ assets: { main: cache('main'), @@ -185,7 +192,7 @@ export default class ServiceWorker { }, externals: externals, - shouldServeFromNetwork: this.shouldServeFromNetwork, + shouldServeFromNetwork: shouldServeFromNetworkPlaceholder, hashesMap: hashesMap, navigateFallbackURL: this.navigateFallbackURL, navigateFallbackForRedirects: this.navigateFallbackURL ? @@ -207,6 +214,12 @@ export default class ServiceWorker { ignoreSearch: plugin.ignoreSearch, }, null, minify ? void 0 : ' ') }; `.trim(); + + if (functionResult) { + return result.replace( `"${shouldServeFromNetworkPlaceholder}"`, functionResult.trim()); + } + + return result; } getConfig(plugin) { diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js index 31ed676b..98d9435a 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js @@ -465,9 +465,16 @@ var __wpo = { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (false) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js index 3b3d7d8f..daea0266 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js @@ -465,9 +465,16 @@ var __wpo = { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (false) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js index e0823ef1..bf4588bf 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js @@ -461,9 +461,16 @@ var __wpo = { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (false) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } diff --git a/tests/legacy/fixtures/loaders-externals/__expected/sw.js b/tests/legacy/fixtures/loaders-externals/__expected/sw.js index 72a7f9e4..aedc9f7f 100644 --- a/tests/legacy/fixtures/loaders-externals/__expected/sw.js +++ b/tests/legacy/fixtures/loaders-externals/__expected/sw.js @@ -472,9 +472,16 @@ var __wpo = { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (false) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } diff --git a/tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/main.js b/tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/main.js new file mode 100644 index 00000000..53daa020 --- /dev/null +++ b/tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/main.js @@ -0,0 +1,50 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports) { + + + +/***/ } +/******/ ]); \ No newline at end of file diff --git a/tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/sw.js b/tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/sw.js new file mode 100644 index 00000000..e4126eb4 --- /dev/null +++ b/tests/legacy/fixtures/network-first-response-should-serve-from-network/__expected/sw.js @@ -0,0 +1,24 @@ +var __wpo = { + "assets": { + "main": [ + "./external.js" + ], + "additional": [], + "optional": [] + }, + "externals": [ + "./external.js" + ], + "shouldServeFromNetwork": function (response, urlString, cacheUrl) { + if(urlString.match(/\//)) { + return true; + } + return response.ok; + }, + "hashesMap": {}, + "strategy": "changed", + "responseStrategy": "cache-first", + "version": "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "name": "webpack-offline", + "relativePaths": true +}; \ No newline at end of file diff --git a/tests/legacy/fixtures/network-first-response-should-serve-from-network/main.js b/tests/legacy/fixtures/network-first-response-should-serve-from-network/main.js new file mode 100644 index 00000000..e69de29b diff --git a/tests/legacy/fixtures/network-first-response-should-serve-from-network/webpack.config.js b/tests/legacy/fixtures/network-first-response-should-serve-from-network/webpack.config.js new file mode 100644 index 00000000..89ac3c0a --- /dev/null +++ b/tests/legacy/fixtures/network-first-response-should-serve-from-network/webpack.config.js @@ -0,0 +1,17 @@ +module.exports = __CONFIG__({ + caches: { + main: ['external.js', ':rest:'] + }, + externals: ['external.js'], + excludes: ['main.js'], + version: '[hash]', + AppCache: false, + ServiceWorker: { + shouldServeFromNetwork: function(response, urlString, cacheUrl) { + if(urlString.match(/\//)) { + return true; + } + return response.ok; + } + } +}); \ No newline at end of file diff --git a/tests/legacy/fixtures/sw-minify-false/__expected/sw.js b/tests/legacy/fixtures/sw-minify-false/__expected/sw.js index 31ed676b..98d9435a 100644 --- a/tests/legacy/fixtures/sw-minify-false/__expected/sw.js +++ b/tests/legacy/fixtures/sw-minify-false/__expected/sw.js @@ -465,9 +465,16 @@ var __wpo = { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetch(event.request).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (false) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } diff --git a/tests/legacy/fixtures/sw-minify-true/__expected/sw.js b/tests/legacy/fixtures/sw-minify-true/__expected/sw.js index 6149a89b..3e977986 100644 --- a/tests/legacy/fixtures/sw-minify-true/__expected/sw.js +++ b/tests/legacy/fixtures/sw-minify-true/__expected/sw.js @@ -1,3 +1,3 @@ var __wpo = {"assets":{"main":["./external.js"],"additional":[],"optional":[]},"externals":["./external.js"],"hashesMap":{},"strategy":"changed","responseStrategy":"cache-first","version":"da39a3ee5e6b4b0d3255bfef95601890afd80709","name":"webpack-offline","relativePaths":true}; -!function(n){function e(r){if(t[r])return t[r].exports;var i=t[r]={exports:{},id:r,loaded:!1};return n[r].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var t={};return e.m=n,e.c=t,e.p="",e(0)}([function(n,e,t){"use strict";function r(n,e){function t(){if(!P.additional.length)return Promise.resolve();var n=void 0;return n="changed"===b?c("additional"):r("additional"),n.catch(function(n){})}function r(e){var t=P[e];return caches.open(W).then(function(e){return x(e,t,{bust:n.version,request:n.prefetchRequest})}).then(function(){f("Cached assets: "+e,t)}).catch(function(n){throw n})}function c(e){return l().then(function(t){if(!t)return r(e);var i=t[0],o=t[1],a=t[2],c=a.hashmap,u=a.version;if(!a.hashmap||u===n.version)return r(e);var s=Object.keys(c).map(function(n){return c[n]}),h=o.map(function(n){var e=new URL(n.url);return e.search="",e.hash="",e.toString()}),l=P[e],d=[],v=l.filter(function(n){return h.indexOf(n)===-1||s.indexOf(n)===-1});Object.keys(U).forEach(function(n){var e=U[n];if(l.indexOf(e)!==-1&&v.indexOf(e)===-1&&d.indexOf(e)===-1){var t=c[n];t&&h.indexOf(t)!==-1?d.push([t,e]):v.push(e)}}),f("Changed assets: "+e,v),f("Moved assets: "+e,d);var p=Promise.all(d.map(function(n){return i.match(n[0]).then(function(e){return[n[1],e]})}));return caches.open(W).then(function(e){var t=p.then(function(n){return Promise.all(n.map(function(n){return e.put(n[0],n[1])}))});return Promise.all([t,x(e,v,{bust:n.version,request:n.prefetchRequest})])})})}function h(){return caches.keys().then(function(n){var e=n.map(function(n){if(0===n.indexOf(L)&&0!==n.indexOf(W))return caches.delete(n)});return Promise.all(e)})}function l(){return caches.keys().then(function(n){for(var e=n.length,t=void 0;e--&&(t=n[e],0!==t.indexOf(L)););if(t){var r=void 0;return caches.open(t).then(function(n){return r=n,n.match(new URL(j,location).toString())}).then(function(n){if(n)return Promise.all([r,r.keys(),n.json()])})}})}function d(){return caches.open(W).then(function(e){var t=new Response(JSON.stringify({version:n.version,hashmap:U}));return e.put(new URL(j,location).toString(),t)})}function v(n,e,t){return i(t,W).then(function(r){if(r)return r;var i=fetch(n.request).then(function(r){return r.ok?(t===e&&!function(){var t=r.clone(),i=caches.open(W).then(function(n){return n.put(e,t)}).then(function(){});n.waitUntil(i)}(),r):r});return i})}function p(n,e,t){return fetch(n.request).then(function(n){if(n.ok)return n;throw new Error("Response is not ok")}).catch(function(){return i(t,W)})}function m(n){return n.catch(function(){}).then(function(n){var e=n&&n.ok,t=n&&"opaqueredirect"===n.type;return e||t&&!M?n:i(F,W)})}function g(){Object.keys(P).forEach(function(n){P[n]=P[n].map(function(n){var e=new URL(n,location);return e.hash="",E.indexOf(n)===-1&&(e.search=""),e.toString()})}),Object.keys(R).forEach(function(n){R[n]=R[n].map(function(n){var e=new URL(n,location);return e.hash="",E.indexOf(n)===-1&&(e.search=""),e.toString()})}),U=Object.keys(U).reduce(function(n,e){var t=new URL(U[e],location);return t.search="",t.hash="",n[e]=t.toString(),n},{}),E=E.map(function(n){var e=new URL(n,location);return e.hash="",e.toString()})}function x(n,e,t){var r=t.allowLoaders!==!1,i=t&&t.bust,a=t.request||{credentials:"omit",mode:"cors"};return Promise.all(e.map(function(n){return i&&(n=o(n,i)),fetch(n,a).then(u)})).then(function(i){if(i.some(function(n){return!n.ok}))return Promise.reject(new Error("Wrong response status"));var o=[],a=i.map(function(t,i){return r&&o.push(w(e[i],t)),n.put(e[i],t)});return o.length?!function(){var r=s(t);r.allowLoaders=!1;var i=a;a=Promise.all(o).then(function(t){var o=[].concat.apply([],t);return e.length&&(i=i.concat(x(n,o,r))),Promise.all(i)})}():a=Promise.all(a),a})}function w(n,e){var t=Object.keys(R).map(function(t){var r=R[t];if(r.indexOf(n)!==-1&&O[t])return O[t](e.clone())}).filter(function(n){return!!n});return Promise.all(t).then(function(n){return[].concat.apply([],n)})}function y(n){var e=n.url,t=new URL(e),r=void 0;r="navigate"===n.mode?"navigate":t.origin===location.origin?"same-origin":"cross-origin";for(var i=0;i Date: Tue, 5 Mar 2019 18:53:02 +0300 Subject: [PATCH 4/6] fix tests, remove unused loaders, remove babel from deps --- lib/service-worker.js | 2 - package.json | 1 - .../__expected/webpack4/sw.js | 10 +- .../appshell-basic/__expected/webpack4/sw.js | 10 +- .../basic-wIth-sw-out/__expected/sw.js | 564 --------------- .../__expected/webpack4/sw.js | 10 +- .../__expected/webpack4/sw.js | 10 +- .../cachemaps-basic/__expected/webpack4/sw.js | 10 +- .../loaders-externals/__expected/sw.js | 675 ------------------ .../sw-minify-auto/__expected/webpack4/sw.js | 2 +- .../fixtures/sw-minify-false/__expected/sw.js | 564 --------------- .../sw-minify-false/__expected/webpack4/sw.js | 10 +- .../__expected/webpack4/sw.js | 2 +- .../sw-minify-true/__expected/webpack4/sw.js | 2 +- 14 files changed, 57 insertions(+), 1815 deletions(-) delete mode 100644 tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js delete mode 100644 tests/legacy/fixtures/loaders-externals/__expected/sw.js delete mode 100644 tests/legacy/fixtures/sw-minify-false/__expected/sw.js diff --git a/lib/service-worker.js b/lib/service-worker.js index c8e840f8..a42cf897 100644 --- a/lib/service-worker.js +++ b/lib/service-worker.js @@ -224,8 +224,6 @@ var ServiceWorker = (function () { pluginVersion = plugin.pluginVersion; } - var loaders = Object.keys(plugin.loaders).length ? plugin.loaders : void 0; - var shouldServeFromNetworkPlaceholder = this.shouldServeFromNetwork ? '__func_should_serve_from_network__' : undefined; var functionResult = this.shouldServeFromNetwork && (minify ? this.shouldServeFromNetwork.toString().replace(REGEX_MINIFY_FUNC, '') : this.shouldServeFromNetwork.toString()); var result = ('\n var ' + this.SW_DATA_VAR + ' = ' + JSON.stringify({ diff --git a/package.json b/package.json index fdcdee48..41b51913 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "author": "Arthur Stolyar ", "license": "MIT", "dependencies": { - "babel": "^5.8.38", "deep-extend": "^0.5.1", "ejs": "^2.3.4", "loader-utils": "0.2.x", diff --git a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js index 64ac5c5a..60ba7e72 100644 --- a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js @@ -534,9 +534,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -881,6 +888,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js b/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js index 797a8035..932bba53 100644 --- a/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js @@ -534,9 +534,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -881,6 +888,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js deleted file mode 100644 index c6d4302d..00000000 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/sw.js +++ /dev/null @@ -1,564 +0,0 @@ - - function cacheChanged(section) { - return getLastCache().then(function (args) { - if (!args) { - return cacheAssets(section); - } - - var lastCache = args[0]; - var lastKeys = args[1]; - var lastData = args[2]; - - var lastMap = lastData.hashmap; - var lastVersion = lastData.version; - - if (!lastData.hashmap || lastVersion === params.version) { - return cacheAssets(section); - } - - var lastHashedAssets = Object.keys(lastMap).map(function (hash) { - return lastMap[hash]; - }); - - var lastUrls = lastKeys.map(function (req) { - var url = new URL(req.url); - url.search = ''; - url.hash = ''; - - return url.toString(); - }); - - var sectionAssets = assets[section]; - var moved = []; - var changed = sectionAssets.filter(function (url) { - if (lastUrls.indexOf(url) === -1 || lastHashedAssets.indexOf(url) === -1) { - return true; - } - - return false; - }); - - Object.keys(hashesMap).forEach(function (hash) { - var asset = hashesMap[hash]; - - // Return if not in sectionAssets or in changed or moved array - if (sectionAssets.indexOf(asset) === -1 || changed.indexOf(asset) !== -1 || moved.indexOf(asset) !== -1) return; - - var lastAsset = lastMap[hash]; - - if (lastAsset && lastUrls.indexOf(lastAsset) !== -1) { - moved.push([lastAsset, asset]); - } else { - changed.push(asset); - } - }); - - logGroup('Changed assets: ' + section, changed); - logGroup('Moved assets: ' + section, moved); - - var movedResponses = Promise.all(moved.map(function (pair) { - return lastCache.match(pair[0]).then(function (response) { - return [pair[1], response]; - }); - })); - - return caches.open(CACHE_NAME).then(function (cache) { - var move = movedResponses.then(function (responses) { - return Promise.all(responses.map(function (pair) { - return cache.put(pair[0], pair[1]); - })); - }); - - return Promise.all([move, addAllNormalized(cache, changed, { - bust: params.version, - request: params.prefetchRequest - })]); - }); - }); - } - - function deleteObsolete() { - return caches.keys().then(function (keys) { - var all = keys.map(function (key) { - if (key.indexOf(CACHE_PREFIX) !== 0 || key.indexOf(CACHE_NAME) === 0) return; - - console.log('[SW]:', 'Delete cache:', key); - return caches['delete'](key); - }); - - return Promise.all(all); - }); - } - - function getLastCache() { - return caches.keys().then(function (keys) { - var index = keys.length; - var key = undefined; - - while (index--) { - key = keys[index]; - - if (key.indexOf(CACHE_PREFIX) === 0) { - break; - } - } - - if (!key) return; - - var cache = undefined; - - return caches.open(key).then(function (_cache) { - cache = _cache; - return _cache.match(new URL(STORED_DATA_KEY, location).toString()); - }).then(function (response) { - if (!response) return; - - return Promise.all([cache, cache.keys(), response.json()]); - }); - }); - } - - function storeCacheData() { - return caches.open(CACHE_NAME).then(function (cache) { - var data = new Response(JSON.stringify({ - version: params.version, - hashmap: hashesMap - })); - - return cache.put(new URL(STORED_DATA_KEY, location).toString(), data); - }); - } - - self.addEventListener('fetch', function (event) { - var url = new URL(event.request.url); - url.hash = ''; - - var urlString = url.toString(); - - // Not external, so search part of the URL should be stripped, - // if it's external URL, the search part should be kept - if (externals.indexOf(urlString) === -1) { - url.search = ''; - urlString = url.toString(); - } - - // Handle only GET requests - var isGET = event.request.method === 'GET'; - var assetMatches = allAssets.indexOf(urlString) !== -1; - var cacheUrl = urlString; - - if (!assetMatches) { - var cacheRewrite = matchCacheMap(event.request); - - if (cacheRewrite) { - cacheUrl = cacheRewrite; - assetMatches = true; - } - } - - if (!assetMatches && isGET) { - // If isn't a cached asset and is a navigation request, - // fallback to navigateFallbackURL if available - if (navigateFallbackURL && isNavigateRequest(event.request)) { - event.respondWith(handleNavigateFallback(fetch(event.request))); - - return; - } - } - - if (!assetMatches || !isGET) { - // Fix for https://twitter.com/wanderview/status/696819243262873600 - if (url.origin !== location.origin && navigator.userAgent.indexOf('Firefox/44.') !== -1) { - event.respondWith(fetch(event.request)); - } - - return; - } - - // Logic of caching / fetching is here - // * urlString -- url to match from the CACHE_NAME - // * event.request -- original Request to perform fetch() if necessary - var resource = undefined; - - if (responseStrategy === 'network-first') { - resource = networkFirstResponse(event, urlString, cacheUrl); - } - // 'cache-first' - // (responseStrategy has been validated before) - else { - resource = cacheFirstResponse(event, urlString, cacheUrl); - } - - if (navigateFallbackURL && isNavigateRequest(event.request)) { - resource = handleNavigateFallback(resource); - } - - event.respondWith(resource); - }); - - self.addEventListener('message', function (e) { - var data = e.data; - if (!data) return; - - switch (data.action) { - case 'skipWaiting': - { - if (self.skipWaiting) self.skipWaiting(); - }break; - } - }); - - function cacheFirstResponse(event, urlString, cacheUrl) { - return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { - if (response) { - if (false) { - console.log('[SW]:', 'URL [' + cacheUrl + '](' + urlString + ') from cache'); - } - - return response; - } - - // Load and cache known assets - var fetching = fetch(event.request).then(function (response) { - if (!response.ok) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] wrong response: [' + response.status + '] ' + response.type); - } - - return response; - } - - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - if (cacheUrl === urlString) { - (function () { - var responseClone = response.clone(); - var storing = caches.open(CACHE_NAME).then(function (cache) { - return cache.put(urlString, responseClone); - }).then(function () { - console.log('[SW]:', 'Cache asset: ' + urlString); - }); - - event.waitUntil(storing); - })(); - } - - return response; - }); - - return fetching; - }); - } - - function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); - } - return response.ok; - } - - function networkFirstResponse(event, urlString, cacheUrl) { - return fetch(event.request).then(function (response) { - if (shouldServeFromNetwork(response, urlString, cacheUrl)) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - return response; - } - - // Throw to reach the code in the catch below - throw new Error('Response is not ok'); - }) - // This needs to be in a catch() and not just in the then() above - // cause if your network is down, the fetch() will throw - ['catch'](function () { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from cache if possible'); - } - - return cachesMatch(cacheUrl, CACHE_NAME); - }); - } - - function handleNavigateFallback(fetching) { - return fetching['catch'](function () {}).then(function (response) { - var isOk = response && response.ok; - var isRedirect = response && response.type === 'opaqueredirect'; - - if (isOk || isRedirect && !navigateFallbackForRedirects) { - return response; - } - - if (false) { - console.log('[SW]:', 'Loading navigation fallback [' + navigateFallbackURL + '] from cache'); - } - - return cachesMatch(navigateFallbackURL, CACHE_NAME); - }); - } - - function mapAssets() { - Object.keys(assets).forEach(function (key) { - assets[key] = assets[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - Object.keys(loadersMap).forEach(function (key) { - loadersMap[key] = loadersMap[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - hashesMap = Object.keys(hashesMap).reduce(function (result, hash) { - var url = new URL(hashesMap[hash], location); - url.search = ''; - url.hash = ''; - - result[hash] = url.toString(); - return result; - }, {}); - - externals = externals.map(function (path) { - var url = new URL(path, location); - url.hash = ''; - - return url.toString(); - }); - } - - function addAllNormalized(cache, requests, options) { - var allowLoaders = options.allowLoaders !== false; - var bustValue = options && options.bust; - var requestInit = options.request || { - credentials: 'omit', - mode: 'cors' - }; - - return Promise.all(requests.map(function (request) { - if (bustValue) { - request = applyCacheBust(request, bustValue); - } - - return fetch(request, requestInit).then(fixRedirectedResponse); - })).then(function (responses) { - if (responses.some(function (response) { - return !response.ok; - })) { - return Promise.reject(new Error('Wrong response status')); - } - - var extracted = []; - var addAll = responses.map(function (response, i) { - if (allowLoaders) { - extracted.push(extractAssetsWithLoaders(requests[i], response)); - } - - return cache.put(requests[i], response); - }); - - if (extracted.length) { - (function () { - var newOptions = copyObject(options); - newOptions.allowLoaders = false; - - var waitAll = addAll; - - addAll = Promise.all(extracted).then(function (all) { - var extractedRequests = [].concat.apply([], all); - - if (requests.length) { - waitAll = waitAll.concat(addAllNormalized(cache, extractedRequests, newOptions)); - } - - return Promise.all(waitAll); - }); - })(); - } else { - addAll = Promise.all(addAll); - } - - return addAll; - }); - } - - function extractAssetsWithLoaders(request, response) { - var all = Object.keys(loadersMap).map(function (key) { - var loader = loadersMap[key]; - - if (loader.indexOf(request) !== -1 && loaders[key]) { - return loaders[key](response.clone()); - } - }).filter(function (a) { - return !!a; - }); - - return Promise.all(all).then(function (all) { - return [].concat.apply([], all); - }); - } - - function matchCacheMap(request) { - var urlString = request.url; - var url = new URL(urlString); - - var requestType = undefined; - - if (request.mode === 'navigate') { - requestType = 'navigate'; - } else if (url.origin === location.origin) { - requestType = 'same-origin'; - } else { - requestType = 'cross-origin'; - } - - for (var i = 0; i < cacheMaps.length; i++) { - var map = cacheMaps[i]; - - if (!map) continue; - if (map.requestTypes && map.requestTypes.indexOf(requestType) === -1) { - continue; - } - - var newString = undefined; - - if (typeof map.match === 'function') { - newString = map.match(url, request); - } else { - newString = urlString.replace(map.match, map.to); - } - - if (newString && newString !== urlString) { - return newString; - } - } - } - } - - function cachesMatch(request, cacheName) { - return caches.match(request, { - cacheName: cacheName - }).then(function (response) { - if (isNotRedirectedResponse()) { - return response; - } - - // Fix already cached redirected responses - return fixRedirectedResponse(response).then(function (fixedResponse) { - return caches.open(cacheName).then(function (cache) { - return cache.put(request, fixedResponse); - }).then(function () { - return fixedResponse; - }); - }); - }) - // Return void if error happened (cache not found) - ['catch'](function () {}); - } - - function applyCacheBust(asset, key) { - var hasQuery = asset.indexOf('?') !== -1; - return asset + (hasQuery ? '&' : '?') + '__uncache=' + encodeURIComponent(key); - } - - function getClientsURLs() { - if (!self.clients) { - return Promise.resolve([]); - } - - return self.clients.matchAll({ - includeUncontrolled: true - }).then(function (clients) { - if (!clients.length) return []; - - var result = []; - - clients.forEach(function (client) { - var url = new URL(client.url); - url.search = ''; - url.hash = ''; - var urlString = url.toString(); - - if (!result.length || result.indexOf(urlString) === -1) { - result.push(urlString); - } - }); - - return result; - }); - } - - function isNavigateRequest(request) { - return request.mode === 'navigate' || request.headers.get('Upgrade-Insecure-Requests') || (request.headers.get('Accept') || '').indexOf('text/html') !== -1; - } - - function isNotRedirectedResponse(response) { - return !response || !response.redirected || !response.ok || response.type === 'opaqueredirect'; - } - - // Based on https://github.com/GoogleChrome/sw-precache/pull/241/files#diff-3ee9060dc7a312c6a822cac63a8c630bR85 - function fixRedirectedResponse(response) { - if (isNotRedirectedResponse(response)) { - return Promise.resolve(response); - } - - var body = 'body' in response ? Promise.resolve(response.body) : response.blob(); - - return body.then(function (data) { - return new Response(data, { - headers: response.headers, - status: response.status - }); - }); - } - - function copyObject(original) { - return Object.keys(original).reduce(function (result, key) { - result[key] = original[key]; - return result; - }, {}); - } - - function logGroup(title, assets) { - console.groupCollapsed('[SW]:', title); - - assets.forEach(function (asset) { - console.log('Asset:', asset); - }); - - console.groupEnd(); - } - WebpackServiceWorker(__wpo, { - loaders: {}, - cacheMaps: [], - }); - module.exports = __webpack_require__(1) - - -/***/ }, -/* 1 */ -/***/ function(module, exports) { - - - -/***/ } -/******/ ]); diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js index 42393adb..c266f5d6 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js @@ -534,9 +534,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -881,6 +888,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [], diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js index 685f26c6..f771fa0d 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js @@ -534,9 +534,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -881,6 +888,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [], diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js index d26b799d..25a553ce 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js @@ -530,9 +530,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -877,6 +884,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/loaders-externals/__expected/sw.js b/tests/legacy/fixtures/loaders-externals/__expected/sw.js deleted file mode 100644 index dd6d15f0..00000000 --- a/tests/legacy/fixtures/loaders-externals/__expected/sw.js +++ /dev/null @@ -1,675 +0,0 @@ -var __wpo = { - "assets": { - "main": [ - "./external.js", - "https://fonts.googleapis.com/css?family=Montserrat:400,700" - ], - "additional": [], - "optional": [] - }, - "externals": [ - "./external.js", - "https://fonts.googleapis.com/css?family=Montserrat:400,700" - ], - "hashesMap": {}, - "strategy": "changed", - "responseStrategy": "cache-first", - "version": "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "name": "webpack-offline", - "relativePaths": true, - "loaders": { - "fonts-css": [ - "https://fonts.googleapis.com/css?family=Montserrat:400,700" - ] - } -}; - -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - "use strict"; - - (function () { - var waitUntil = ExtendableEvent.prototype.waitUntil; - var respondWith = FetchEvent.prototype.respondWith; - var promisesMap = new WeakMap(); - - ExtendableEvent.prototype.waitUntil = function (promise) { - var extendableEvent = this; - var promises = promisesMap.get(extendableEvent); - - if (promises) { - promises.push(Promise.resolve(promise)); - return; - } - - promises = [Promise.resolve(promise)]; - promisesMap.set(extendableEvent, promises); - - // call original method - return waitUntil.call(extendableEvent, Promise.resolve().then(function processPromises() { - var len = promises.length; - - // wait for all to settle - return Promise.all(promises.map(function (p) { - return p["catch"](function () {}); - })).then(function () { - // have new items been added? If so, wait again - if (promises.length != len) return processPromises(); - // we're done! - promisesMap["delete"](extendableEvent); - // reject if one of the promises rejected - return Promise.all(promises); - }); - })); - }; - - FetchEvent.prototype.respondWith = function (promise) { - this.waitUntil(promise); - return respondWith.call(this, promise); - }; - })();; - 'use strict'; - - if (false) { - var DEBUG = false; - } - - function WebpackServiceWorker(params, helpers) { - var loaders = helpers.loaders; - var cacheMaps = helpers.cacheMaps; - - var strategy = params.strategy; - var responseStrategy = params.responseStrategy; - - var assets = params.assets; - var loadersMap = params.loaders || {}; - - var hashesMap = params.hashesMap; - var externals = params.externals; - - // Not used yet - // const alwaysRevalidate = params.alwaysRevalidate; - // const ignoreSearch = params.ignoreSearch; - // const preferOnline = params.preferOnline; - - var CACHE_PREFIX = params.name; - var CACHE_TAG = params.version; - var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG; - - var STORED_DATA_KEY = '__offline_webpack__data'; - - mapAssets(); - - var allAssets = [].concat(assets.main, assets.additional, assets.optional); - var navigateFallbackURL = params.navigateFallbackURL; - var navigateFallbackForRedirects = params.navigateFallbackForRedirects; - - self.addEventListener('install', function (event) { - console.log('[SW]:', 'Install event'); - - var installing = undefined; - - if (strategy === 'changed') { - installing = cacheChanged('main'); - } else { - installing = cacheAssets('main'); - } - - event.waitUntil(installing); - }); - - self.addEventListener('activate', function (event) { - console.log('[SW]:', 'Activate event'); - - var activation = cacheAdditional(); - - // Delete all assets which name starts with CACHE_PREFIX and - // is not current cache (CACHE_NAME) - activation = activation.then(storeCacheData); - activation = activation.then(deleteObsolete); - activation = activation.then(function () { - if (self.clients && self.clients.claim) { - return self.clients.claim(); - } - }); - - event.waitUntil(activation); - }); - - function cacheAdditional() { - if (!assets.additional.length) { - return Promise.resolve(); - } - - if (false) { - console.log('[SW]:', 'Caching additional'); - } - - var operation = undefined; - - if (strategy === 'changed') { - operation = cacheChanged('additional'); - } else { - operation = cacheAssets('additional'); - } - - // Ignore fail of `additional` cache section - return operation['catch'](function (e) { - console.error('[SW]:', 'Cache section `additional` failed to load'); - }); - } - - function cacheAssets(section) { - var batch = assets[section]; - - return caches.open(CACHE_NAME).then(function (cache) { - return addAllNormalized(cache, batch, { - bust: params.version, - request: params.prefetchRequest - }); - }).then(function () { - logGroup('Cached assets: ' + section, batch); - })['catch'](function (e) { - console.error(e); - throw e; - }); - } - - function cacheChanged(section) { - return getLastCache().then(function (args) { - if (!args) { - return cacheAssets(section); - } - - var lastCache = args[0]; - var lastKeys = args[1]; - var lastData = args[2]; - - var lastMap = lastData.hashmap; - var lastVersion = lastData.version; - - if (!lastData.hashmap || lastVersion === params.version) { - return cacheAssets(section); - } - - var lastHashedAssets = Object.keys(lastMap).map(function (hash) { - return lastMap[hash]; - }); - - var lastUrls = lastKeys.map(function (req) { - var url = new URL(req.url); - url.search = ''; - url.hash = ''; - - return url.toString(); - }); - - var sectionAssets = assets[section]; - var moved = []; - var changed = sectionAssets.filter(function (url) { - if (lastUrls.indexOf(url) === -1 || lastHashedAssets.indexOf(url) === -1) { - return true; - } - - return false; - }); - - Object.keys(hashesMap).forEach(function (hash) { - var asset = hashesMap[hash]; - - // Return if not in sectionAssets or in changed or moved array - if (sectionAssets.indexOf(asset) === -1 || changed.indexOf(asset) !== -1 || moved.indexOf(asset) !== -1) return; - - var lastAsset = lastMap[hash]; - - if (lastAsset && lastUrls.indexOf(lastAsset) !== -1) { - moved.push([lastAsset, asset]); - } else { - changed.push(asset); - } - }); - - logGroup('Changed assets: ' + section, changed); - logGroup('Moved assets: ' + section, moved); - - var movedResponses = Promise.all(moved.map(function (pair) { - return lastCache.match(pair[0]).then(function (response) { - return [pair[1], response]; - }); - })); - - return caches.open(CACHE_NAME).then(function (cache) { - var move = movedResponses.then(function (responses) { - return Promise.all(responses.map(function (pair) { - return cache.put(pair[0], pair[1]); - })); - }); - - return Promise.all([move, addAllNormalized(cache, changed, { - bust: params.version, - request: params.prefetchRequest - })]); - }); - }); - } - - function deleteObsolete() { - return caches.keys().then(function (keys) { - var all = keys.map(function (key) { - if (key.indexOf(CACHE_PREFIX) !== 0 || key.indexOf(CACHE_NAME) === 0) return; - - console.log('[SW]:', 'Delete cache:', key); - return caches['delete'](key); - }); - - return Promise.all(all); - }); - } - - function getLastCache() { - return caches.keys().then(function (keys) { - var index = keys.length; - var key = undefined; - - while (index--) { - key = keys[index]; - - if (key.indexOf(CACHE_PREFIX) === 0) { - break; - } - } - - if (!key) return; - - var cache = undefined; - - return caches.open(key).then(function (_cache) { - cache = _cache; - return _cache.match(new URL(STORED_DATA_KEY, location).toString()); - }).then(function (response) { - if (!response) return; - - return Promise.all([cache, cache.keys(), response.json()]); - }); - }); - } - - function storeCacheData() { - return caches.open(CACHE_NAME).then(function (cache) { - var data = new Response(JSON.stringify({ - version: params.version, - hashmap: hashesMap - })); - - return cache.put(new URL(STORED_DATA_KEY, location).toString(), data); - }); - } - - self.addEventListener('fetch', function (event) { - var url = new URL(event.request.url); - url.hash = ''; - - var urlString = url.toString(); - - // Not external, so search part of the URL should be stripped, - // if it's external URL, the search part should be kept - if (externals.indexOf(urlString) === -1) { - url.search = ''; - urlString = url.toString(); - } - - // Handle only GET requests - var isGET = event.request.method === 'GET'; - var assetMatches = allAssets.indexOf(urlString) !== -1; - var cacheUrl = urlString; - - if (!assetMatches) { - var cacheRewrite = matchCacheMap(event.request); - - if (cacheRewrite) { - cacheUrl = cacheRewrite; - assetMatches = true; - } - } - - if (!assetMatches && isGET) { - // If isn't a cached asset and is a navigation request, - // fallback to navigateFallbackURL if available - if (navigateFallbackURL && isNavigateRequest(event.request)) { - event.respondWith(handleNavigateFallback(fetch(event.request))); - - return; - } - } - - if (!assetMatches || !isGET) { - // Fix for https://twitter.com/wanderview/status/696819243262873600 - if (url.origin !== location.origin && navigator.userAgent.indexOf('Firefox/44.') !== -1) { - event.respondWith(fetch(event.request)); - } - - return; - } - - // Logic of caching / fetching is here - // * urlString -- url to match from the CACHE_NAME - // * event.request -- original Request to perform fetch() if necessary - var resource = undefined; - - if (responseStrategy === 'network-first') { - resource = networkFirstResponse(event, urlString, cacheUrl); - } - // 'cache-first' - // (responseStrategy has been validated before) - else { - resource = cacheFirstResponse(event, urlString, cacheUrl); - } - - if (navigateFallbackURL && isNavigateRequest(event.request)) { - resource = handleNavigateFallback(resource); - } - - event.respondWith(resource); - }); - - self.addEventListener('message', function (e) { - var data = e.data; - if (!data) return; - - switch (data.action) { - case 'skipWaiting': - { - if (self.skipWaiting) self.skipWaiting(); - }break; - } - }); - - function cacheFirstResponse(event, urlString, cacheUrl) { - return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { - if (response) { - if (false) { - console.log('[SW]:', 'URL [' + cacheUrl + '](' + urlString + ') from cache'); - } - - return response; - } - - // Load and cache known assets - var fetching = fetch(event.request).then(function (response) { - if (!response.ok) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] wrong response: [' + response.status + '] ' + response.type); - } - - return response; - } - - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - if (cacheUrl === urlString) { - (function () { - var responseClone = response.clone(); - var storing = caches.open(CACHE_NAME).then(function (cache) { - return cache.put(urlString, responseClone); - }).then(function () { - console.log('[SW]:', 'Cache asset: ' + urlString); - }); - - event.waitUntil(storing); - })(); - } - - return response; - }); - - return fetching; - }); - } - - function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); - } - return response.ok; - } - - function networkFirstResponse(event, urlString, cacheUrl) { - return fetch(event.request).then(function (response) { - if (shouldServeFromNetwork(response, urlString, cacheUrl)) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - return response; - } - - // Throw to reach the code in the catch below - throw new Error('Response is not ok'); - }) - // This needs to be in a catch() and not just in the then() above - // cause if your network is down, the fetch() will throw - ['catch'](function () { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from cache if possible'); - } - - return cachesMatch(cacheUrl, CACHE_NAME); - }); - } - - function handleNavigateFallback(fetching) { - return fetching['catch'](function () {}).then(function (response) { - var isOk = response && response.ok; - var isRedirect = response && response.type === 'opaqueredirect'; - - if (isOk || isRedirect && !navigateFallbackForRedirects) { - return response; - } - - if (false) { - console.log('[SW]:', 'Loading navigation fallback [' + navigateFallbackURL + '] from cache'); - } - - return cachesMatch(navigateFallbackURL, CACHE_NAME); - }); - } - - function mapAssets() { - Object.keys(assets).forEach(function (key) { - assets[key] = assets[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - Object.keys(loadersMap).forEach(function (key) { - loadersMap[key] = loadersMap[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - hashesMap = Object.keys(hashesMap).reduce(function (result, hash) { - var url = new URL(hashesMap[hash], location); - url.search = ''; - url.hash = ''; - - result[hash] = url.toString(); - return result; - }, {}); - - externals = externals.map(function (path) { - var url = new URL(path, location); - url.hash = ''; - - return url.toString(); - }); - } - - function addAllNormalized(cache, requests, options) { - var allowLoaders = options.allowLoaders !== false; - var bustValue = options && options.bust; - var requestInit = options.request || { - credentials: 'omit', - mode: 'cors' - }; - - return Promise.all(requests.map(function (request) { - if (bustValue) { - request = applyCacheBust(request, bustValue); - } - - return fetch(request, requestInit).then(fixRedirectedResponse); - })).then(function (responses) { - if (responses.some(function (response) { - return !response.ok; - })) { - return Promise.reject(new Error('Wrong response status')); - } - - var extracted = []; - var addAll = responses.map(function (response, i) { - if (allowLoaders) { - extracted.push(extractAssetsWithLoaders(requests[i], response)); - } - - return cache.put(requests[i], response); - }); - - if (extracted.length) { - (function () { - var newOptions = copyObject(options); - newOptions.allowLoaders = false; - - var waitAll = addAll; - - addAll = Promise.all(extracted).then(function (all) { - var extractedRequests = [].concat.apply([], all); - - if (requests.length) { - waitAll = waitAll.concat(addAllNormalized(cache, extractedRequests, newOptions)); - } - - return Promise.all(waitAll); - }); - })(); - } else { - addAll = Promise.all(addAll); - } - - return addAll; - }); - } - - function extractAssetsWithLoaders(request, response) { - var all = Object.keys(loadersMap).map(function (key) { - var loader = loadersMap[key]; - - if (loader.indexOf(request) !== -1 && loaders[key]) { - return loaders[key](response.clone()); - } - }).filter(function (a) { - return !!a; - }); - - return Promise.all(all).then(function (all) { - return [].concat.apply([], all); - }); - } - - function matchCacheMap(request) { - var urlString = request.url; - var url = new URL(urlString); - - var requestType = undefined; - - if (request.mode === 'navigate') { - requestType = 'navigate'; - } else if (url.origin === location.origin) { - requestType = 'same-origin'; - } else { - requestType = 'cross-origin'; - } - - for (var i = 0; i < cacheMaps.length; i++) { - var map = cacheMaps[i]; - - if (!map) continue; - if (map.requestTypes && map.requestTypes.indexOf(requestType) === -1) { - continue; - } - - var newString = undefined; - - if (typeof map.match === 'function') { - newString = map.match(url, request); - } else { - newString = urlString.replace(map.match, map.to); - } - - if (newString && newString !== urlString) { - return newString; - } - } - } - } diff --git a/tests/legacy/fixtures/sw-minify-auto/__expected/webpack4/sw.js b/tests/legacy/fixtures/sw-minify-auto/__expected/webpack4/sw.js index 6462eb11..727863bf 100644 --- a/tests/legacy/fixtures/sw-minify-auto/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/sw-minify-auto/__expected/webpack4/sw.js @@ -1,3 +1,3 @@ var __wpo = {"assets":{"main":["./external.js"],"additional":[],"optional":[]},"externals":["./external.js"],"hashesMap":{},"strategy":"changed","responseStrategy":"cache-first","version":"da39a3ee5e6b4b0d3255bfef95601890afd80709","name":"webpack-offline","relativePaths":true}; -!function(e){var n={};function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var i in e)t.d(r,i,function(n){return e[n]}.bind(null,i));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){"use strict";var r,i,o;if(r=ExtendableEvent.prototype.waitUntil,i=FetchEvent.prototype.respondWith,o=new WeakMap,ExtendableEvent.prototype.waitUntil=function(e){var n=this,t=o.get(n);if(!t)return t=[Promise.resolve(e)],o.set(n,t),r.call(n,Promise.resolve().then(function e(){var r=t.length;return Promise.all(t.map(function(e){return e.catch(function(){})})).then(function(){return t.length!=r?e():(o.delete(n),Promise.all(t))})}));t.push(Promise.resolve(e))},FetchEvent.prototype.respondWith=function(e){return this.waitUntil(e),i.call(this,e)},void 0===a)var a=!1;function u(e,n){return caches.match(e,{cacheName:n}).then(function(t){return c(t)?t:s(t).then(function(t){return caches.open(n).then(function(n){return n.put(e,t)}).then(function(){return t})})}).catch(function(){})}function c(e){return!e||!e.redirected||!e.ok||"opaqueredirect"===e.type}function s(e){return c(e)?Promise.resolve(e):("body"in e?Promise.resolve(e.body):e.blob()).then(function(n){return new Response(n,{headers:e.headers,status:e.status})})}function f(e,n){n.forEach(function(e){})}!function(e,n){var t=n.cacheMaps,r=n.navigationPreload,i=e.strategy,o=e.responseStrategy,a=e.assets,c=e.hashesMap,l=e.externals,h=e.prefetchRequest||{credentials:"same-origin",mode:"cors"},d=e.name,p=e.version,v=d+":"+p,m=d+"$preload",g="__offline_webpack__data";Object.keys(a).forEach(function(e){a[e]=a[e].map(function(e){var n=new URL(e,location);return n.hash="",-1===l.indexOf(e)&&(n.search=""),n.toString()})}),c=Object.keys(c).reduce(function(e,n){var t=new URL(c[n],location);return t.search="",t.hash="",e[n]=t.toString(),e},{}),l=l.map(function(e){var n=new URL(e,location);return n.hash="",n.toString()});var y=[].concat(a.main,a.additional,a.optional);function w(n){var t=a[n];return caches.open(v).then(function(r){return q(r,t,{bust:e.version,request:h,failAll:"main"===n})}).then(function(){f(0,t)}).catch(function(e){throw e})}function P(n){return caches.keys().then(function(e){for(var n=e.length,t=void 0;n--&&0!==(t=e[n]).indexOf(d););if(t){var r=void 0;return caches.open(t).then(function(e){return r=e,e.match(new URL(g,location).toString())}).then(function(e){if(e)return Promise.all([r,r.keys(),e.json()])})}}).then(function(t){if(!t)return w(n);var r=t[0],i=t[1],o=t[2],u=o.hashmap,s=o.version;if(!o.hashmap||s===e.version)return w(n);var l=Object.keys(u).map(function(e){return u[e]}),d=i.map(function(e){var n=new URL(e.url);return n.search="",n.hash="",n.toString()}),p=a[n],m=[],g=p.filter(function(e){return-1===d.indexOf(e)||-1===l.indexOf(e)});Object.keys(c).forEach(function(e){var n=c[e];if(-1!==p.indexOf(n)&&-1===g.indexOf(n)&&-1===m.indexOf(n)){var t=u[e];t&&-1!==d.indexOf(t)?m.push([t,n]):g.push(n)}}),f(0,g),f(0,m);var y=Promise.all(m.map(function(e){return r.match(e[0]).then(function(n){return[e[1],n]})}));return caches.open(v).then(function(t){var r=y.then(function(e){return Promise.all(e.map(function(e){return t.put(e[0],e[1])}))});return Promise.all([r,q(t,g,{bust:e.version,request:h,failAll:"main"===n,deleteFirst:"main"!==n})])})})}function b(){return caches.keys().then(function(e){var n=e.map(function(e){if(0===e.indexOf(d)&&0!==e.indexOf(v))return caches.delete(e)});return Promise.all(n)})}function O(){return caches.open(v).then(function(n){var t=new Response(JSON.stringify({version:e.version,hashmap:c}));return n.put(new URL(g,location).toString(),t)})}self.addEventListener("install",function(e){var n=void 0;n="changed"===i?P("main"):w("main"),e.waitUntil(n)}),self.addEventListener("activate",function(e){var n=function(){if(!a.additional.length)return Promise.resolve();return("changed"===i?P("additional"):w("additional")).catch(function(e){})}();n=(n=(n=n.then(O)).then(b)).then(function(){if(self.clients&&self.clients.claim)return self.clients.claim()}),r&&self.registration.navigationPreload&&(n=Promise.all([n,self.registration.navigationPreload.enable()])),e.waitUntil(n)}),self.addEventListener("fetch",function(e){if("GET"===e.request.method&&("only-if-cached"!==e.request.cache||"same-origin"===e.request.mode)){var n=new URL(e.request.url);n.hash="";var i=n.toString();-1===l.indexOf(i)&&(n.search="",i=n.toString());var a=-1!==y.indexOf(i),c=i;if(!a){var s=function(e){var n=e.url,r=new URL(n),i=void 0;i=function(e){return"navigate"===e.mode||e.headers.get("Upgrade-Insecure-Requests")||-1!==(e.headers.get("Accept")||"").indexOf("text/html")}(e)?"navigate":r.origin===location.origin?"same-origin":"cross-origin";for(var o=0;o Date: Thu, 7 Mar 2019 13:29:30 +0300 Subject: [PATCH 5/6] fix tests for webpack version 2 & 3 --- .../appshell-absolute-path/__expected/webpack2/sw.js | 10 +++++++++- .../appshell-absolute-path/__expected/webpack3/sw.js | 10 +++++++++- .../fixtures/appshell-basic/__expected/webpack2/sw.js | 10 +++++++++- .../fixtures/appshell-basic/__expected/webpack3/sw.js | 10 +++++++++- .../basic-wIth-sw-out/__expected/webpack2/sw.js | 10 +++++++++- .../basic-wIth-sw-out/__expected/webpack3/sw.js | 10 +++++++++- .../__expected/webpack2/sw.js | 10 +++++++++- .../__expected/webpack3/sw.js | 10 +++++++++- .../fixtures/cachemaps-basic/__expected/webpack2/sw.js | 10 +++++++++- .../fixtures/cachemaps-basic/__expected/webpack3/sw.js | 10 +++++++++- .../fixtures/sw-minify-auto/__expected/webpack2/sw.js | 2 +- .../fixtures/sw-minify-auto/__expected/webpack3/sw.js | 2 +- .../fixtures/sw-minify-false/__expected/webpack2/sw.js | 10 +++++++++- .../fixtures/sw-minify-false/__expected/webpack3/sw.js | 10 +++++++++- .../fixtures/sw-minify-true/__expected/webpack2/sw.js | 2 +- .../fixtures/sw-minify-true/__expected/webpack3/sw.js | 2 +- 16 files changed, 112 insertions(+), 16 deletions(-) diff --git a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js index 01a7e8c7..d3fa9175 100644 --- a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js @@ -522,9 +522,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -869,6 +876,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js index a823b2fc..7bf1068b 100644 --- a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js @@ -513,9 +513,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -860,6 +867,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js b/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js index 09a08ea9..6f4d5e5c 100644 --- a/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js @@ -522,9 +522,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -869,6 +876,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js b/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js index 4a4e8950..b8980bf4 100644 --- a/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js @@ -513,9 +513,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -860,6 +867,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js index b55d2808..44e53e3a 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js @@ -522,9 +522,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -869,6 +876,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [], diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js index 0141d2c4..4ae2536b 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js @@ -513,9 +513,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -860,6 +867,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [], diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js index 54141e82..d0a465f9 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js @@ -522,9 +522,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -869,6 +876,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [], diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js index 594e780c..f6e8c864 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js @@ -513,9 +513,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -860,6 +867,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [], diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js index 5cd4b883..360f2551 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js @@ -518,9 +518,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -865,6 +872,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js index 45ed9392..25a9e7f6 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js @@ -509,9 +509,16 @@ function WebpackServiceWorker(params, helpers) { }); } + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (params.shouldServeFromNetwork) { + return params.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + function networkFirstResponse(event, urlString, cacheUrl) { return fetchWithPreload(event).then(function (response) { - if (response.ok) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { if (DEBUG) { console.log('[SW]:', 'URL [' + urlString + '] from network'); } @@ -856,6 +863,7 @@ function logGroup(title, assets) { console.groupEnd(); } + WebpackServiceWorker(__wpo, { loaders: {}, cacheMaps: [ diff --git a/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js b/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js index 369c0e4d..e794483b 100644 --- a/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js @@ -1,3 +1,3 @@ var __wpo = {"assets":{"main":["./external.js"],"additional":[],"optional":[]},"externals":["./external.js"],"hashesMap":{},"strategy":"changed","responseStrategy":"cache-first","version":"da39a3ee5e6b4b0d3255bfef95601890afd80709","name":"webpack-offline","relativePaths":true}; -!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var t={};n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=1)}([function(e,n){},function(e,n,t){"use strict";function r(e,n){return caches.match(e,{cacheName:n}).then(function(t){return a(t)?t:c(t).then(function(t){return caches.open(n).then(function(n){return n.put(e,t)}).then(function(){return t})})}).catch(function(){})}function o(e,n){return e+(-1!==e.indexOf("?")?"&":"?")+"__uncache="+encodeURIComponent(n)}function i(e){return"navigate"===e.mode||e.headers.get("Upgrade-Insecure-Requests")||-1!==(e.headers.get("Accept")||"").indexOf("text/html")}function a(e){return!e||!e.redirected||!e.ok||"opaqueredirect"===e.type}function c(e){return a(e)?Promise.resolve(e):("body"in e?Promise.resolve(e.body):e.blob()).then(function(n){return new Response(n,{headers:e.headers,status:e.status})})}function s(e,n){console.groupCollapsed("[SW]:",e),n.forEach(function(e){console.log("Asset:",e)}),console.groupEnd()}if(function(){var e=ExtendableEvent.prototype.waitUntil,n=FetchEvent.prototype.respondWith,t=new WeakMap;ExtendableEvent.prototype.waitUntil=function(n){var r=this,o=t.get(r);return o?void o.push(Promise.resolve(n)):(o=[Promise.resolve(n)],t.set(r,o),e.call(r,Promise.resolve().then(function e(){var n=o.length;return Promise.all(o.map(function(e){return e.catch(function(){})})).then(function(){return o.length!=n?e():(t.delete(r),Promise.all(o))})})))},FetchEvent.prototype.respondWith=function(e){return this.waitUntil(e),n.call(this,e)}}(),void 0===u)var u=!1;!function(e,n){function t(){if(!W.additional.length)return Promise.resolve();u&&console.log("[SW]:","Caching additional");var e=void 0;return e="changed"===O?f("additional"):a("additional"),e.catch(function(e){console.error("[SW]:","Cache section `additional` failed to load")})}function a(n){var t=W[n];return caches.open(j).then(function(r){return y(r,t,{bust:e.version,request:k,failAll:"main"===n})}).then(function(){s("Cached assets: "+n,t)}).catch(function(e){throw console.error(e),e})}function f(n){return h().then(function(t){if(!t)return a(n);var r=t[0],o=t[1],i=t[2],c=i.hashmap,u=i.version;if(!i.hashmap||u===e.version)return a(n);var f=Object.keys(c).map(function(e){return c[e]}),l=o.map(function(e){var n=new URL(e.url);return n.search="",n.hash="",n.toString()}),h=W[n],d=[],p=h.filter(function(e){return-1===l.indexOf(e)||-1===f.indexOf(e)});Object.keys(b).forEach(function(e){var n=b[e];if(-1!==h.indexOf(n)&&-1===p.indexOf(n)&&-1===d.indexOf(n)){var t=c[e];t&&-1!==l.indexOf(t)?d.push([t,n]):p.push(n)}}),s("Changed assets: "+n,p),s("Moved assets: "+n,d);var v=Promise.all(d.map(function(e){return r.match(e[0]).then(function(n){return[e[1],n]})}));return caches.open(j).then(function(t){var r=v.then(function(e){return Promise.all(e.map(function(e){return t.put(e[0],e[1])}))});return Promise.all([r,y(t,p,{bust:e.version,request:k,failAll:"main"===n,deleteFirst:"main"!==n})])})})}function l(){return caches.keys().then(function(e){var n=e.map(function(e){if(0===e.indexOf(E)&&0!==e.indexOf(j))return console.log("[SW]:","Delete cache:",e),caches.delete(e)});return Promise.all(n)})}function h(){return caches.keys().then(function(e){for(var n=e.length,t=void 0;n--&&(t=e[n],0!==t.indexOf(E)););if(t){var r=void 0;return caches.open(t).then(function(e){return r=e,e.match(new URL(M,location).toString())}).then(function(e){if(e)return Promise.all([r,r.keys(),e.json()])})}})}function d(){return caches.open(j).then(function(n){var t=new Response(JSON.stringify({version:e.version,hashmap:b}));return n.put(new URL(M,location).toString(),t)})}function p(e,n,t){return m(e),r(t,j).then(function(r){return r?(u&&console.log("[SW]:","URL ["+t+"]("+n+") from cache"),r):fetch(e.request).then(function(r){return r.ok?(u&&console.log("[SW]:","URL ["+n+"] from network"),t===n&&function(){var t=r.clone(),o=caches.open(j).then(function(e){return e.put(n,t)}).then(function(){console.log("[SW]:","Cache asset: "+n)});e.waitUntil(o)}(),r):(u&&console.log("[SW]:","URL ["+n+"] wrong response: ["+r.status+"] "+r.type),r)})})}function v(e,n,t){return R(e).then(function(e){if(e.ok)return u&&console.log("[SW]:","URL ["+n+"] from network"),e;throw e}).catch(function(e){return u&&console.log("[SW]:","URL ["+n+"] from cache if possible"),r(t,j).then(function(n){if(n)return n;if(e instanceof Response)return e;throw e})})}function m(e){if(q&&"function"==typeof q.map&&e.preloadResponse&&"navigate"===e.request.mode){var n=q.map(new URL(e.request.url),e.request);n&&g(n,e)}}function g(e,n){var t=new URL(e,location),r=n.preloadResponse;F.set(r,{url:t,response:r});var o=function(){return F.has(r)},i=r.then(function(e){if(e&&o()){var n=e.clone();return caches.open(C).then(function(e){if(o())return e.put(t,n).then(function(){if(!o())return caches.open(C).then(function(e){return e.delete(t)})})})}});n.waitUntil(i)}function w(e){if(F){var n=void 0,t=void 0;return F.forEach(function(r,o){r.url.href===e.href&&(n=r.response,t=o)}),n?(F.delete(t),n):void 0}}function U(e){var n=new URL(e.request.url);if(self.registration.navigationPreload&&q&&q.test&&q.test(n,e.request)){var t=w(n),o=e.request;return t?(e.waitUntil(caches.open(C).then(function(e){return e.delete(o)})),t):r(o,C).then(function(n){return n&&e.waitUntil(caches.open(C).then(function(e){return e.delete(o)})),n||fetch(e.request)})}}function y(e,n,t){var r=t.bust,i=!1!==t.failAll,a=!0===t.deleteFirst,s=t.request||{credentials:"omit",mode:"cors"},u=Promise.resolve();return a&&(u=Promise.all(n.map(function(n){return e.delete(n).catch(function(){})}))),Promise.all(n.map(function(e){return r&&(e=o(e,r)),fetch(e,s).then(c).then(function(e){return e.ok?{response:e}:{error:!0}},function(){return{error:!0}})})).then(function(t){return i&&t.some(function(e){return e.error})?Promise.reject(new Error("Wrong response status")):(i||(t=t.filter(function(e){return!e.error})),u.then(function(){var r=t.map(function(t,r){var o=t.response;return e.put(n[r],o)});return Promise.all(r)}))})}function P(e){var n=e.url,t=new URL(n),r=void 0;r=i(e)?"navigate":t.origin===location.origin?"same-origin":"cross-origin";for(var o=0;o Date: Tue, 23 Apr 2019 15:30:09 +0200 Subject: [PATCH 6/6] Moved shouldServeFromNetwork to helpers instead to prevent minification issues, adjusted tests --- lib/misc/sw-loader.js | 2 +- lib/misc/sw-template.js | 6 +- lib/service-worker.js | 14 +- src/misc/sw-loader.js | 3 +- src/misc/sw-template.js | 6 +- src/service-worker.js | 15 +- .../__expected/webpack2/sw.js | 6 +- .../__expected/webpack3/sw.js | 6 +- .../__expected/webpack4/sw.js | 6 +- .../appshell-basic/__expected/webpack2/sw.js | 6 +- .../appshell-basic/__expected/webpack3/sw.js | 6 +- .../appshell-basic/__expected/webpack4/sw.js | 6 +- .../__expected/webpack2/sw.js | 6 +- .../__expected/webpack3/sw.js | 6 +- .../__expected/webpack4/sw.js | 6 +- .../__expected/sw.js | 1582 ++++++++-------- .../__expected/webpack2/sw.js | 6 +- .../__expected/webpack3/sw.js | 6 +- .../__expected/webpack4/sw.js | 6 +- .../fixtures/cachemaps-basic/__expected/sw.js | 1638 +++++++++-------- .../cachemaps-basic/__expected/webpack2/sw.js | 6 +- .../cachemaps-basic/__expected/webpack3/sw.js | 6 +- .../cachemaps-basic/__expected/webpack4/sw.js | 6 +- .../sw-minify-auto/__expected/webpack2/sw.js | 2 +- .../sw-minify-auto/__expected/webpack3/sw.js | 2 +- .../sw-minify-auto/__expected/webpack4/sw.js | 2 +- .../sw-minify-false/__expected/webpack2/sw.js | 6 +- .../sw-minify-false/__expected/webpack3/sw.js | 6 +- .../sw-minify-false/__expected/webpack4/sw.js | 6 +- .../__expected/webpack4/sw.js | 2 +- .../fixtures/sw-minify-true/__expected/sw.js | 2 +- .../sw-minify-true/__expected/webpack2/sw.js | 2 +- .../sw-minify-true/__expected/webpack3/sw.js | 2 +- .../sw-minify-true/__expected/webpack4/sw.js | 2 +- 34 files changed, 1819 insertions(+), 1571 deletions(-) diff --git a/lib/misc/sw-loader.js b/lib/misc/sw-loader.js index 9c3f8c67..e034fddb 100644 --- a/lib/misc/sw-loader.js +++ b/lib/misc/sw-loader.js @@ -51,7 +51,7 @@ module.exports.pitch = function pitch(remainingRequest, precedingRequest, data) var navigationPreloadCode = params.navigationPreload; - var helpersCode = [', {', 'loaders: ' + loadersCode + ',', 'cacheMaps: ' + cacheMapsCode + ',', 'navigationPreload: ' + navigationPreloadCode + ',', '}']; + var helpersCode = [', {', 'shouldServeFromNetwork: ' + params.shouldServeFromNetwork + ',', 'loaders: ' + loadersCode + ',', 'cacheMaps: ' + cacheMapsCode + ',', 'navigationPreload: ' + navigationPreloadCode + ',', '}']; Promise.all([].concat(_toConsumableArray(modules.map(function (mod) { return readFile(path.join(__dirname, mod)); diff --git a/lib/misc/sw-template.js b/lib/misc/sw-template.js index 62d9e2f4..59a801e3 100644 --- a/lib/misc/sw-template.js +++ b/lib/misc/sw-template.js @@ -383,8 +383,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -735,4 +735,4 @@ function logGroup(title, assets) { }); console.groupEnd(); -} +} \ No newline at end of file diff --git a/lib/service-worker.js b/lib/service-worker.js index a42cf897..8beb094c 100644 --- a/lib/service-worker.js +++ b/lib/service-worker.js @@ -78,6 +78,7 @@ var ServiceWorker = (function () { var data = JSON.stringify({ data_var_name: this.SW_DATA_VAR, cacheMaps: plugin.cacheMaps, + shouldServeFromNetwork: (0, _miscUtils.functionToString)(this.shouldServeFromNetwork), navigationPreload: this.stringifyNavigationPreload(this.navigationPreload, plugin) }); @@ -224,8 +225,8 @@ var ServiceWorker = (function () { pluginVersion = plugin.pluginVersion; } - var shouldServeFromNetworkPlaceholder = this.shouldServeFromNetwork ? '__func_should_serve_from_network__' : undefined; - var functionResult = this.shouldServeFromNetwork && (minify ? this.shouldServeFromNetwork.toString().replace(REGEX_MINIFY_FUNC, '') : this.shouldServeFromNetwork.toString()); + var loaders = Object.keys(plugin.loaders || {}).length ? plugin.loaders : void 0; + var result = ('\n var ' + this.SW_DATA_VAR + ' = ' + JSON.stringify({ assets: { main: cache('main'), @@ -234,7 +235,6 @@ var ServiceWorker = (function () { }, externals: externals, - shouldServeFromNetwork: shouldServeFromNetworkPlaceholder, hashesMap: hashesMap, strategy: plugin.strategy, @@ -245,17 +245,13 @@ var ServiceWorker = (function () { relativePaths: plugin.relativePaths, prefetchRequest: this.prefetchRequest, - + loaders: loaders, // These aren't added alwaysRevalidate: plugin.alwaysRevalidate, preferOnline: plugin.preferOnline, ignoreSearch: plugin.ignoreSearch }, null, minify ? void 0 : ' ') + ';\n ').trim(); - if (functionResult) { - return result.replace('"' + shouldServeFromNetworkPlaceholder + '"', functionResult.trim()); - } - return result; } }, { @@ -314,4 +310,4 @@ var ServiceWorker = (function () { })(); exports['default'] = ServiceWorker; -module.exports = exports['default']; +module.exports = exports['default']; \ No newline at end of file diff --git a/src/misc/sw-loader.js b/src/misc/sw-loader.js index 9e24cd6c..3a9a66f7 100644 --- a/src/misc/sw-loader.js +++ b/src/misc/sw-loader.js @@ -57,6 +57,7 @@ module.exports.pitch = function pitch(remainingRequest, precedingRequest, data) const helpersCode = [ ', {', + `shouldServeFromNetwork: ${params.shouldServeFromNetwork},`, `loaders: ${loadersCode},`, `cacheMaps: ${cacheMapsCode},`, `navigationPreload: ${navigationPreloadCode},`, @@ -90,4 +91,4 @@ function readFile(path) { resolve(file); }); }); -} \ No newline at end of file +} diff --git a/src/misc/sw-template.js b/src/misc/sw-template.js index e676c360..1ebc886d 100644 --- a/src/misc/sw-template.js +++ b/src/misc/sw-template.js @@ -398,8 +398,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -755,4 +755,4 @@ function logGroup(title, assets) { }); console.groupEnd(); -} \ No newline at end of file +} diff --git a/src/service-worker.js b/src/service-worker.js index ba09c0bb..6d248635 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -58,6 +58,7 @@ export default class ServiceWorker { const data = JSON.stringify({ data_var_name: this.SW_DATA_VAR, cacheMaps: plugin.cacheMaps, + shouldServeFromNetwork: functionToString(this.shouldServeFromNetwork), navigationPreload: this.stringifyNavigationPreload(this.navigationPreload, plugin) }); @@ -215,14 +216,9 @@ export default class ServiceWorker { pluginVersion = plugin.pluginVersion; } - const loaders = Object.keys(plugin.loaders).length ? + const loaders = Object.keys(plugin.loaders || {}).length ? plugin.loaders : void 0; - const shouldServeFromNetworkPlaceholder = - this.shouldServeFromNetwork ? '__func_should_serve_from_network__' : undefined; - const functionResult = this.shouldServeFromNetwork && - (minify ? this.shouldServeFromNetwork.toString().replace(REGEX_MINIFY_FUNC, '') : - this.shouldServeFromNetwork.toString()); const result = ` var ${ this.SW_DATA_VAR } = ${ JSON.stringify({ assets: { @@ -232,7 +228,6 @@ export default class ServiceWorker { }, externals: externals, - shouldServeFromNetwork: shouldServeFromNetworkPlaceholder, hashesMap: hashesMap, strategy: plugin.strategy, @@ -243,7 +238,7 @@ export default class ServiceWorker { relativePaths: plugin.relativePaths, prefetchRequest: this.prefetchRequest, - + loaders: loaders, // These aren't added alwaysRevalidate: plugin.alwaysRevalidate, preferOnline: plugin.preferOnline, @@ -251,10 +246,6 @@ export default class ServiceWorker { }, null, minify ? void 0 : ' ') }; `.trim(); - if (functionResult) { - return result.replace( `"${shouldServeFromNetworkPlaceholder}"`, functionResult.trim()); - } - return result; } diff --git a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js index d3fa9175..b5ad7806 100644 --- a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack2/sw.js @@ -523,8 +523,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -876,8 +876,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js index 7bf1068b..25210a6c 100644 --- a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack3/sw.js @@ -514,8 +514,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -867,8 +867,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js index 60ba7e72..4971e05d 100644 --- a/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/appshell-absolute-path/__expected/webpack4/sw.js @@ -535,8 +535,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -888,8 +888,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js b/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js index 6f4d5e5c..a688ee6d 100644 --- a/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/appshell-basic/__expected/webpack2/sw.js @@ -523,8 +523,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -876,8 +876,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js b/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js index b8980bf4..60d4dc3a 100644 --- a/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/appshell-basic/__expected/webpack3/sw.js @@ -514,8 +514,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -867,8 +867,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js b/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js index 932bba53..eda8fb58 100644 --- a/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/appshell-basic/__expected/webpack4/sw.js @@ -535,8 +535,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -888,8 +888,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js index 44e53e3a..34fd3ee5 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack2/sw.js @@ -523,8 +523,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -876,8 +876,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [], navigationPreload: false, diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js index 4ae2536b..a711b29f 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack3/sw.js @@ -514,8 +514,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -867,8 +867,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [], navigationPreload: false, diff --git a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js index c266f5d6..1c11a8bc 100644 --- a/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/basic-wIth-sw-out/__expected/webpack4/sw.js @@ -535,8 +535,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -888,8 +888,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [], navigationPreload: false, diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js index daea0266..ad57d16c 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/sw.js @@ -20,758 +20,888 @@ var __wpo = { /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; - +/******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { - +/******/ /******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) +/******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; - +/******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} /******/ }; - +/******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - +/******/ /******/ // Flag the module as loaded -/******/ module.loaded = true; - +/******/ module.l = true; +/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } - - +/******/ +/******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; - +/******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; - +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; - +/******/ +/******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(0); +/******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ -/***/ function(module, exports, __webpack_require__) { +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +(function () { + var waitUntil = ExtendableEvent.prototype.waitUntil; + var respondWith = FetchEvent.prototype.respondWith; + var promisesMap = new WeakMap(); + + ExtendableEvent.prototype.waitUntil = function (promise) { + var extendableEvent = this; + var promises = promisesMap.get(extendableEvent); + + if (promises) { + promises.push(Promise.resolve(promise)); + return; + } - "use strict"; - - (function () { - var waitUntil = ExtendableEvent.prototype.waitUntil; - var respondWith = FetchEvent.prototype.respondWith; - var promisesMap = new WeakMap(); - - ExtendableEvent.prototype.waitUntil = function (promise) { - var extendableEvent = this; - var promises = promisesMap.get(extendableEvent); - - if (promises) { - promises.push(Promise.resolve(promise)); - return; - } - - promises = [Promise.resolve(promise)]; - promisesMap.set(extendableEvent, promises); - - // call original method - return waitUntil.call(extendableEvent, Promise.resolve().then(function processPromises() { - var len = promises.length; - - // wait for all to settle - return Promise.all(promises.map(function (p) { - return p["catch"](function () {}); - })).then(function () { - // have new items been added? If so, wait again - if (promises.length != len) return processPromises(); - // we're done! - promisesMap["delete"](extendableEvent); - // reject if one of the promises rejected - return Promise.all(promises); - }); - })); - }; - - FetchEvent.prototype.respondWith = function (promise) { - this.waitUntil(promise); - return respondWith.call(this, promise); - }; - })();; - 'use strict'; - - if (false) { - var DEBUG = false; - } - - function WebpackServiceWorker(params, helpers) { - var loaders = helpers.loaders; - var cacheMaps = helpers.cacheMaps; - - var strategy = params.strategy; - var responseStrategy = params.responseStrategy; - - var assets = params.assets; - var loadersMap = params.loaders || {}; - - var hashesMap = params.hashesMap; - var externals = params.externals; - - // Not used yet - // const alwaysRevalidate = params.alwaysRevalidate; - // const ignoreSearch = params.ignoreSearch; - // const preferOnline = params.preferOnline; - - var CACHE_PREFIX = params.name; - var CACHE_TAG = params.version; - var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG; - - var STORED_DATA_KEY = '__offline_webpack__data'; - - mapAssets(); - - var allAssets = [].concat(assets.main, assets.additional, assets.optional); - var navigateFallbackURL = params.navigateFallbackURL; - var navigateFallbackForRedirects = params.navigateFallbackForRedirects; - - self.addEventListener('install', function (event) { - console.log('[SW]:', 'Install event'); - - var installing = undefined; - - if (strategy === 'changed') { - installing = cacheChanged('main'); - } else { - installing = cacheAssets('main'); - } - - event.waitUntil(installing); - }); - - self.addEventListener('activate', function (event) { - console.log('[SW]:', 'Activate event'); - - var activation = cacheAdditional(); - - // Delete all assets which name starts with CACHE_PREFIX and - // is not current cache (CACHE_NAME) - activation = activation.then(storeCacheData); - activation = activation.then(deleteObsolete); - activation = activation.then(function () { - if (self.clients && self.clients.claim) { - return self.clients.claim(); - } - }); - - event.waitUntil(activation); - }); - - function cacheAdditional() { - if (!assets.additional.length) { - return Promise.resolve(); - } - - if (false) { - console.log('[SW]:', 'Caching additional'); - } - - var operation = undefined; - - if (strategy === 'changed') { - operation = cacheChanged('additional'); - } else { - operation = cacheAssets('additional'); - } - - // Ignore fail of `additional` cache section - return operation['catch'](function (e) { - console.error('[SW]:', 'Cache section `additional` failed to load'); - }); - } - - function cacheAssets(section) { - var batch = assets[section]; - - return caches.open(CACHE_NAME).then(function (cache) { - return addAllNormalized(cache, batch, { - bust: params.version, - request: params.prefetchRequest - }); - }).then(function () { - logGroup('Cached assets: ' + section, batch); - })['catch'](function (e) { - console.error(e); - throw e; - }); - } - - function cacheChanged(section) { - return getLastCache().then(function (args) { - if (!args) { - return cacheAssets(section); - } - - var lastCache = args[0]; - var lastKeys = args[1]; - var lastData = args[2]; - - var lastMap = lastData.hashmap; - var lastVersion = lastData.version; - - if (!lastData.hashmap || lastVersion === params.version) { - return cacheAssets(section); - } - - var lastHashedAssets = Object.keys(lastMap).map(function (hash) { - return lastMap[hash]; - }); - - var lastUrls = lastKeys.map(function (req) { - var url = new URL(req.url); - url.search = ''; - url.hash = ''; - - return url.toString(); - }); - - var sectionAssets = assets[section]; - var moved = []; - var changed = sectionAssets.filter(function (url) { - if (lastUrls.indexOf(url) === -1 || lastHashedAssets.indexOf(url) === -1) { - return true; - } - - return false; - }); - - Object.keys(hashesMap).forEach(function (hash) { - var asset = hashesMap[hash]; - - // Return if not in sectionAssets or in changed or moved array - if (sectionAssets.indexOf(asset) === -1 || changed.indexOf(asset) !== -1 || moved.indexOf(asset) !== -1) return; - - var lastAsset = lastMap[hash]; - - if (lastAsset && lastUrls.indexOf(lastAsset) !== -1) { - moved.push([lastAsset, asset]); - } else { - changed.push(asset); - } - }); - - logGroup('Changed assets: ' + section, changed); - logGroup('Moved assets: ' + section, moved); - - var movedResponses = Promise.all(moved.map(function (pair) { - return lastCache.match(pair[0]).then(function (response) { - return [pair[1], response]; - }); - })); - - return caches.open(CACHE_NAME).then(function (cache) { - var move = movedResponses.then(function (responses) { - return Promise.all(responses.map(function (pair) { - return cache.put(pair[0], pair[1]); - })); - }); - - return Promise.all([move, addAllNormalized(cache, changed, { - bust: params.version, - request: params.prefetchRequest - })]); - }); - }); - } - - function deleteObsolete() { - return caches.keys().then(function (keys) { - var all = keys.map(function (key) { - if (key.indexOf(CACHE_PREFIX) !== 0 || key.indexOf(CACHE_NAME) === 0) return; - - console.log('[SW]:', 'Delete cache:', key); - return caches['delete'](key); - }); - - return Promise.all(all); - }); - } - - function getLastCache() { - return caches.keys().then(function (keys) { - var index = keys.length; - var key = undefined; - - while (index--) { - key = keys[index]; - - if (key.indexOf(CACHE_PREFIX) === 0) { - break; - } - } - - if (!key) return; - - var cache = undefined; - - return caches.open(key).then(function (_cache) { - cache = _cache; - return _cache.match(new URL(STORED_DATA_KEY, location).toString()); - }).then(function (response) { - if (!response) return; - - return Promise.all([cache, cache.keys(), response.json()]); - }); - }); - } - - function storeCacheData() { - return caches.open(CACHE_NAME).then(function (cache) { - var data = new Response(JSON.stringify({ - version: params.version, - hashmap: hashesMap - })); - - return cache.put(new URL(STORED_DATA_KEY, location).toString(), data); - }); - } - - self.addEventListener('fetch', function (event) { - var url = new URL(event.request.url); - url.hash = ''; - - var urlString = url.toString(); - - // Not external, so search part of the URL should be stripped, - // if it's external URL, the search part should be kept - if (externals.indexOf(urlString) === -1) { - url.search = ''; - urlString = url.toString(); - } - - // Handle only GET requests - var isGET = event.request.method === 'GET'; - var assetMatches = allAssets.indexOf(urlString) !== -1; - var cacheUrl = urlString; - - if (!assetMatches) { - var cacheRewrite = matchCacheMap(event.request); - - if (cacheRewrite) { - cacheUrl = cacheRewrite; - assetMatches = true; - } - } - - if (!assetMatches && isGET) { - // If isn't a cached asset and is a navigation request, - // fallback to navigateFallbackURL if available - if (navigateFallbackURL && isNavigateRequest(event.request)) { - event.respondWith(handleNavigateFallback(fetch(event.request))); - - return; - } - } - - if (!assetMatches || !isGET) { - // Fix for https://twitter.com/wanderview/status/696819243262873600 - if (url.origin !== location.origin && navigator.userAgent.indexOf('Firefox/44.') !== -1) { - event.respondWith(fetch(event.request)); - } - - return; - } - - // Logic of caching / fetching is here - // * urlString -- url to match from the CACHE_NAME - // * event.request -- original Request to perform fetch() if necessary - var resource = undefined; - - if (responseStrategy === 'network-first') { - resource = networkFirstResponse(event, urlString, cacheUrl); - } - // 'cache-first' - // (responseStrategy has been validated before) - else { - resource = cacheFirstResponse(event, urlString, cacheUrl); - } - - if (navigateFallbackURL && isNavigateRequest(event.request)) { - resource = handleNavigateFallback(resource); - } - - event.respondWith(resource); - }); - - self.addEventListener('message', function (e) { - var data = e.data; - if (!data) return; - - switch (data.action) { - case 'skipWaiting': - { - if (self.skipWaiting) self.skipWaiting(); - }break; - } - }); - - function cacheFirstResponse(event, urlString, cacheUrl) { - return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { - if (response) { - if (false) { - console.log('[SW]:', 'URL [' + cacheUrl + '](' + urlString + ') from cache'); - } - - return response; - } - - // Load and cache known assets - var fetching = fetch(event.request).then(function (response) { - if (!response.ok) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] wrong response: [' + response.status + '] ' + response.type); - } - - return response; - } - - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - if (cacheUrl === urlString) { - (function () { - var responseClone = response.clone(); - var storing = caches.open(CACHE_NAME).then(function (cache) { - return cache.put(urlString, responseClone); - }).then(function () { - console.log('[SW]:', 'Cache asset: ' + urlString); - }); - - event.waitUntil(storing); - })(); - } - - return response; - }); - - return fetching; - }); - } - - function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); - } - return response.ok; - } - - function networkFirstResponse(event, urlString, cacheUrl) { - return fetch(event.request).then(function (response) { - if (shouldServeFromNetwork(response, urlString, cacheUrl)) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - return response; - } - - // Throw to reach the code in the catch below - throw new Error('Response is not ok'); - }) - // This needs to be in a catch() and not just in the then() above - // cause if your network is down, the fetch() will throw - ['catch'](function () { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from cache if possible'); - } - - return cachesMatch(cacheUrl, CACHE_NAME); - }); - } - - function handleNavigateFallback(fetching) { - return fetching['catch'](function () {}).then(function (response) { - var isOk = response && response.ok; - var isRedirect = response && response.type === 'opaqueredirect'; - - if (isOk || isRedirect && !navigateFallbackForRedirects) { - return response; - } - - if (false) { - console.log('[SW]:', 'Loading navigation fallback [' + navigateFallbackURL + '] from cache'); - } - - return cachesMatch(navigateFallbackURL, CACHE_NAME); - }); - } - - function mapAssets() { - Object.keys(assets).forEach(function (key) { - assets[key] = assets[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - Object.keys(loadersMap).forEach(function (key) { - loadersMap[key] = loadersMap[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - hashesMap = Object.keys(hashesMap).reduce(function (result, hash) { - var url = new URL(hashesMap[hash], location); - url.search = ''; - url.hash = ''; - - result[hash] = url.toString(); - return result; - }, {}); - - externals = externals.map(function (path) { - var url = new URL(path, location); - url.hash = ''; - - return url.toString(); - }); - } - - function addAllNormalized(cache, requests, options) { - var allowLoaders = options.allowLoaders !== false; - var bustValue = options && options.bust; - var requestInit = options.request || { - credentials: 'omit', - mode: 'cors' - }; - - return Promise.all(requests.map(function (request) { - if (bustValue) { - request = applyCacheBust(request, bustValue); - } - - return fetch(request, requestInit).then(fixRedirectedResponse); - })).then(function (responses) { - if (responses.some(function (response) { - return !response.ok; - })) { - return Promise.reject(new Error('Wrong response status')); - } - - var extracted = []; - var addAll = responses.map(function (response, i) { - if (allowLoaders) { - extracted.push(extractAssetsWithLoaders(requests[i], response)); - } - - return cache.put(requests[i], response); - }); - - if (extracted.length) { - (function () { - var newOptions = copyObject(options); - newOptions.allowLoaders = false; - - var waitAll = addAll; - - addAll = Promise.all(extracted).then(function (all) { - var extractedRequests = [].concat.apply([], all); - - if (requests.length) { - waitAll = waitAll.concat(addAllNormalized(cache, extractedRequests, newOptions)); - } - - return Promise.all(waitAll); - }); - })(); - } else { - addAll = Promise.all(addAll); - } - - return addAll; - }); - } - - function extractAssetsWithLoaders(request, response) { - var all = Object.keys(loadersMap).map(function (key) { - var loader = loadersMap[key]; - - if (loader.indexOf(request) !== -1 && loaders[key]) { - return loaders[key](response.clone()); - } - }).filter(function (a) { - return !!a; - }); - - return Promise.all(all).then(function (all) { - return [].concat.apply([], all); - }); - } - - function matchCacheMap(request) { - var urlString = request.url; - var url = new URL(urlString); - - var requestType = undefined; - - if (request.mode === 'navigate') { - requestType = 'navigate'; - } else if (url.origin === location.origin) { - requestType = 'same-origin'; - } else { - requestType = 'cross-origin'; - } - - for (var i = 0; i < cacheMaps.length; i++) { - var map = cacheMaps[i]; - - if (!map) continue; - if (map.requestTypes && map.requestTypes.indexOf(requestType) === -1) { - continue; - } - - var newString = undefined; - - if (typeof map.match === 'function') { - newString = map.match(url, request); - } else { - newString = urlString.replace(map.match, map.to); - } - - if (newString && newString !== urlString) { - return newString; - } - } - } - } - - function cachesMatch(request, cacheName) { - return caches.match(request, { - cacheName: cacheName - }).then(function (response) { - if (isNotRedirectedResponse()) { - return response; - } - - // Fix already cached redirected responses - return fixRedirectedResponse(response).then(function (fixedResponse) { - return caches.open(cacheName).then(function (cache) { - return cache.put(request, fixedResponse); - }).then(function () { - return fixedResponse; - }); - }); - }) - // Return void if error happened (cache not found) - ['catch'](function () {}); - } - - function applyCacheBust(asset, key) { - var hasQuery = asset.indexOf('?') !== -1; - return asset + (hasQuery ? '&' : '?') + '__uncache=' + encodeURIComponent(key); - } - - function getClientsURLs() { - if (!self.clients) { - return Promise.resolve([]); - } - - return self.clients.matchAll({ - includeUncontrolled: true - }).then(function (clients) { - if (!clients.length) return []; - - var result = []; - - clients.forEach(function (client) { - var url = new URL(client.url); - url.search = ''; - url.hash = ''; - var urlString = url.toString(); - - if (!result.length || result.indexOf(urlString) === -1) { - result.push(urlString); - } - }); - - return result; - }); - } - - function isNavigateRequest(request) { - return request.mode === 'navigate' || request.headers.get('Upgrade-Insecure-Requests') || (request.headers.get('Accept') || '').indexOf('text/html') !== -1; - } - - function isNotRedirectedResponse(response) { - return !response || !response.redirected || !response.ok || response.type === 'opaqueredirect'; - } - - // Based on https://github.com/GoogleChrome/sw-precache/pull/241/files#diff-3ee9060dc7a312c6a822cac63a8c630bR85 - function fixRedirectedResponse(response) { - if (isNotRedirectedResponse(response)) { - return Promise.resolve(response); - } - - var body = 'body' in response ? Promise.resolve(response.body) : response.blob(); - - return body.then(function (data) { - return new Response(data, { - headers: response.headers, - status: response.status - }); - }); - } - - function copyObject(original) { - return Object.keys(original).reduce(function (result, key) { - result[key] = original[key]; - return result; - }, {}); - } - - function logGroup(title, assets) { - console.groupCollapsed('[SW]:', title); - - assets.forEach(function (asset) { - console.log('Asset:', asset); - }); - - console.groupEnd(); - } - WebpackServiceWorker(__wpo, { - loaders: {}, - cacheMaps: [], - }); - module.exports = __webpack_require__(1) - - -/***/ }, + promises = [Promise.resolve(promise)]; + promisesMap.set(extendableEvent, promises); + + // call original method + return waitUntil.call(extendableEvent, Promise.resolve().then(function processPromises() { + var len = promises.length; + + // wait for all to settle + return Promise.all(promises.map(function (p) { + return p["catch"](function () {}); + })).then(function () { + // have new items been added? If so, wait again + if (promises.length != len) return processPromises(); + // we're done! + promisesMap["delete"](extendableEvent); + // reject if one of the promises rejected + return Promise.all(promises); + }); + })); + }; + + FetchEvent.prototype.respondWith = function (promise) { + this.waitUntil(promise); + return respondWith.call(this, promise); + }; +})();; + 'use strict'; + +if (typeof DEBUG === 'undefined') { + var DEBUG = false; +} + +function WebpackServiceWorker(params, helpers) { + var cacheMaps = helpers.cacheMaps; + // navigationPreload: true, { map: (URL) => URL, test: (URL) => boolean } + var navigationPreload = helpers.navigationPreload; + + // (update)strategy: changed, all + var strategy = params.strategy; + // responseStrategy: cache-first, network-first + var responseStrategy = params.responseStrategy; + + var assets = params.assets; + + var hashesMap = params.hashesMap; + var externals = params.externals; + + var prefetchRequest = params.prefetchRequest || { + credentials: 'same-origin', + mode: 'cors' + }; + + var CACHE_PREFIX = params.name; + var CACHE_TAG = params.version; + var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG; + + var PRELOAD_CACHE_NAME = CACHE_PREFIX + '$preload'; + var STORED_DATA_KEY = '__offline_webpack__data'; + + mapAssets(); + + var allAssets = [].concat(assets.main, assets.additional, assets.optional); + + self.addEventListener('install', function (event) { + console.log('[SW]:', 'Install event'); + + var installing = undefined; + + if (strategy === 'changed') { + installing = cacheChanged('main'); + } else { + installing = cacheAssets('main'); + } + + event.waitUntil(installing); + }); + + self.addEventListener('activate', function (event) { + console.log('[SW]:', 'Activate event'); + + var activation = cacheAdditional(); + + // Delete all assets which name starts with CACHE_PREFIX and + // is not current cache (CACHE_NAME) + activation = activation.then(storeCacheData); + activation = activation.then(deleteObsolete); + activation = activation.then(function () { + if (self.clients && self.clients.claim) { + return self.clients.claim(); + } + }); + + if (navigationPreload && self.registration.navigationPreload) { + activation = Promise.all([activation, self.registration.navigationPreload.enable()]); + } + + event.waitUntil(activation); + }); + + function cacheAdditional() { + if (!assets.additional.length) { + return Promise.resolve(); + } + + if (DEBUG) { + console.log('[SW]:', 'Caching additional'); + } + + var operation = undefined; + + if (strategy === 'changed') { + operation = cacheChanged('additional'); + } else { + operation = cacheAssets('additional'); + } + + // Ignore fail of `additional` cache section + return operation['catch'](function (e) { + console.error('[SW]:', 'Cache section `additional` failed to load'); + }); + } + + function cacheAssets(section) { + var batch = assets[section]; + + return caches.open(CACHE_NAME).then(function (cache) { + return addAllNormalized(cache, batch, { + bust: params.version, + request: prefetchRequest, + failAll: section === 'main' + }); + }).then(function () { + logGroup('Cached assets: ' + section, batch); + })['catch'](function (e) { + console.error(e); + throw e; + }); + } + + function cacheChanged(section) { + return getLastCache().then(function (args) { + if (!args) { + return cacheAssets(section); + } + + var lastCache = args[0]; + var lastKeys = args[1]; + var lastData = args[2]; + + var lastMap = lastData.hashmap; + var lastVersion = lastData.version; + + if (!lastData.hashmap || lastVersion === params.version) { + return cacheAssets(section); + } + + var lastHashedAssets = Object.keys(lastMap).map(function (hash) { + return lastMap[hash]; + }); + + var lastUrls = lastKeys.map(function (req) { + var url = new URL(req.url); + url.search = ''; + url.hash = ''; + + return url.toString(); + }); + + var sectionAssets = assets[section]; + var moved = []; + var changed = sectionAssets.filter(function (url) { + if (lastUrls.indexOf(url) === -1 || lastHashedAssets.indexOf(url) === -1) { + return true; + } + + return false; + }); + + Object.keys(hashesMap).forEach(function (hash) { + var asset = hashesMap[hash]; + + // Return if not in sectionAssets or in changed or moved array + if (sectionAssets.indexOf(asset) === -1 || changed.indexOf(asset) !== -1 || moved.indexOf(asset) !== -1) return; + + var lastAsset = lastMap[hash]; + + if (lastAsset && lastUrls.indexOf(lastAsset) !== -1) { + moved.push([lastAsset, asset]); + } else { + changed.push(asset); + } + }); + + logGroup('Changed assets: ' + section, changed); + logGroup('Moved assets: ' + section, moved); + + var movedResponses = Promise.all(moved.map(function (pair) { + return lastCache.match(pair[0]).then(function (response) { + return [pair[1], response]; + }); + })); + + return caches.open(CACHE_NAME).then(function (cache) { + var move = movedResponses.then(function (responses) { + return Promise.all(responses.map(function (pair) { + return cache.put(pair[0], pair[1]); + })); + }); + + return Promise.all([move, addAllNormalized(cache, changed, { + bust: params.version, + request: prefetchRequest, + failAll: section === 'main', + deleteFirst: section !== 'main' + })]); + }); + }); + } + + function deleteObsolete() { + return caches.keys().then(function (keys) { + var all = keys.map(function (key) { + if (key.indexOf(CACHE_PREFIX) !== 0 || key.indexOf(CACHE_NAME) === 0) return; + + console.log('[SW]:', 'Delete cache:', key); + return caches['delete'](key); + }); + + return Promise.all(all); + }); + } + + function getLastCache() { + return caches.keys().then(function (keys) { + var index = keys.length; + var key = undefined; + + while (index--) { + key = keys[index]; + + if (key.indexOf(CACHE_PREFIX) === 0) { + break; + } + } + + if (!key) return; + + var cache = undefined; + + return caches.open(key).then(function (_cache) { + cache = _cache; + return _cache.match(new URL(STORED_DATA_KEY, location).toString()); + }).then(function (response) { + if (!response) return; + + return Promise.all([cache, cache.keys(), response.json()]); + }); + }); + } + + function storeCacheData() { + return caches.open(CACHE_NAME).then(function (cache) { + var data = new Response(JSON.stringify({ + version: params.version, + hashmap: hashesMap + })); + + return cache.put(new URL(STORED_DATA_KEY, location).toString(), data); + }); + } + + self.addEventListener('fetch', function (event) { + // Handle only GET requests + if (event.request.method !== 'GET') { + return; + } + + // This prevents some weird issue with Chrome DevTools and 'only-if-cached' + // Fixes issue #385, also ref to: + // - https://github.com/paulirish/caltrainschedule.io/issues/49 + // - https://bugs.chromium.org/p/chromium/issues/detail?id=823392 + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + return; + } + + var url = new URL(event.request.url); + url.hash = ''; + + var urlString = url.toString(); + + // Not external, so search part of the URL should be stripped, + // if it's external URL, the search part should be kept + if (externals.indexOf(urlString) === -1) { + url.search = ''; + urlString = url.toString(); + } + + var assetMatches = allAssets.indexOf(urlString) !== -1; + var cacheUrl = urlString; + + if (!assetMatches) { + var cacheRewrite = matchCacheMap(event.request); + + if (cacheRewrite) { + cacheUrl = cacheRewrite; + assetMatches = true; + } + } + + if (!assetMatches) { + // Use request.mode === 'navigate' instead of isNavigateRequest + // because everything what supports navigationPreload supports + // 'navigate' request.mode + if (event.request.mode === 'navigate') { + // Requesting with fetchWithPreload(). + // Preload is used only if navigationPreload is enabled and + // navigationPreload mapping is not used. + if (navigationPreload === true) { + event.respondWith(fetchWithPreload(event)); + return; + } + } + + // Something else, positive, but not `true` + if (navigationPreload) { + var preloadedResponse = retrivePreloadedResponse(event); + + if (preloadedResponse) { + event.respondWith(preloadedResponse); + return; + } + } + + // Logic exists here if no cache match + return; + } + + // Cache handling/storing/fetching starts here + var resource = undefined; + + if (responseStrategy === 'network-first') { + resource = networkFirstResponse(event, urlString, cacheUrl); + } + // 'cache-first' otherwise + // (responseStrategy has been validated before) + else { + resource = cacheFirstResponse(event, urlString, cacheUrl); + } + + event.respondWith(resource); + }); + + self.addEventListener('message', function (e) { + var data = e.data; + if (!data) return; + + switch (data.action) { + case 'skipWaiting': + { + if (self.skipWaiting) self.skipWaiting(); + }break; + } + }); + + function cacheFirstResponse(event, urlString, cacheUrl) { + handleNavigationPreload(event); + + return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { + if (response) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + cacheUrl + '](' + urlString + ') from cache'); + } + + return response; + } + + // Load and cache known assets + var fetching = fetch(event.request).then(function (response) { + if (!response.ok) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] wrong response: [' + response.status + '] ' + response.type); + } + + return response; + } + + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] from network'); + } + + if (cacheUrl === urlString) { + (function () { + var responseClone = response.clone(); + var storing = caches.open(CACHE_NAME).then(function (cache) { + return cache.put(urlString, responseClone); + }).then(function () { + console.log('[SW]:', 'Cache asset: ' + urlString); + }); + + event.waitUntil(storing); + })(); + } + + return response; + }); + + return fetching; + }); + } + + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + + function networkFirstResponse(event, urlString, cacheUrl) { + return fetchWithPreload(event).then(function (response) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] from network'); + } + + return response; + } + + // Throw to reach the code in the catch below + throw response; + }) + // This needs to be in a catch() and not just in the then() above + // cause if your network is down, the fetch() will throw + ['catch'](function (erroredResponse) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] from cache if possible'); + } + + return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { + if (response) { + return response; + } + + if (erroredResponse instanceof Response) { + return erroredResponse; + } + + // Not a response at this point, some other error + throw erroredResponse; + // return Response.error(); + }); + }); + } + + function handleNavigationPreload(event) { + if (navigationPreload && typeof navigationPreload.map === 'function' && + // Use request.mode === 'navigate' instead of isNavigateRequest + // because everything what supports navigationPreload supports + // 'navigate' request.mode + event.preloadResponse && event.request.mode === 'navigate') { + var mapped = navigationPreload.map(new URL(event.request.url), event.request); + + if (mapped) { + storePreloadedResponse(mapped, event); + } + } + } + + // Temporary in-memory store for faster access + var navigationPreloadStore = new Map(); + + function storePreloadedResponse(_url, event) { + var url = new URL(_url, location); + var preloadResponsePromise = event.preloadResponse; + + navigationPreloadStore.set(preloadResponsePromise, { + url: url, + response: preloadResponsePromise + }); + + var isSamePreload = function isSamePreload() { + return navigationPreloadStore.has(preloadResponsePromise); + }; + + var storing = preloadResponsePromise.then(function (res) { + // Return if preload isn't enabled or hasn't happened + if (!res) return; + + // If navigationPreloadStore already consumed + // or navigationPreloadStore already contains another preload, + // then do not store anything and return + if (!isSamePreload()) { + return; + } + + var clone = res.clone(); + + // Storing the preload response for later consume (hasn't yet been consumed) + return caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + if (!isSamePreload()) return; + + return cache.put(url, clone).then(function () { + if (!isSamePreload()) { + return caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + return cache['delete'](url); + }); + } + }); + }); + }); + + event.waitUntil(storing); + } + + function retriveInMemoryPreloadedResponse(url) { + if (!navigationPreloadStore) { + return; + } + + var foundResponse = undefined; + var foundKey = undefined; + + navigationPreloadStore.forEach(function (store, key) { + if (store.url.href === url.href) { + foundResponse = store.response; + foundKey = key; + } + }); + + if (foundResponse) { + navigationPreloadStore['delete'](foundKey); + return foundResponse; + } + } + + function retrivePreloadedResponse(event) { + var url = new URL(event.request.url); + + if (self.registration.navigationPreload && navigationPreload && navigationPreload.test && navigationPreload.test(url, event.request)) {} else { + return; + } + + var fromMemory = retriveInMemoryPreloadedResponse(url); + var request = event.request; + + if (fromMemory) { + event.waitUntil(caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + return cache['delete'](request); + })); + + return fromMemory; + } + + return cachesMatch(request, PRELOAD_CACHE_NAME).then(function (response) { + if (response) { + event.waitUntil(caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + return cache['delete'](request); + })); + } + + return response || fetch(event.request); + }); + } + + function mapAssets() { + Object.keys(assets).forEach(function (key) { + assets[key] = assets[key].map(function (path) { + var url = new URL(path, location); + + url.hash = ''; + + if (externals.indexOf(path) === -1) { + url.search = ''; + } + + return url.toString(); + }); + }); + + hashesMap = Object.keys(hashesMap).reduce(function (result, hash) { + var url = new URL(hashesMap[hash], location); + url.search = ''; + url.hash = ''; + + result[hash] = url.toString(); + return result; + }, {}); + + externals = externals.map(function (path) { + var url = new URL(path, location); + url.hash = ''; + + return url.toString(); + }); + } + + function addAllNormalized(cache, requests, options) { + var bustValue = options.bust; + var failAll = options.failAll !== false; + var deleteFirst = options.deleteFirst === true; + var requestInit = options.request || { + credentials: 'omit', + mode: 'cors' + }; + + var deleting = Promise.resolve(); + + if (deleteFirst) { + deleting = Promise.all(requests.map(function (request) { + return cache['delete'](request)['catch'](function () {}); + })); + } + + return Promise.all(requests.map(function (request) { + if (bustValue) { + request = applyCacheBust(request, bustValue); + } + + return fetch(request, requestInit).then(fixRedirectedResponse).then(function (response) { + if (!response.ok) { + return { error: true }; + } + + return { response: response }; + }, function () { + return { error: true }; + }); + })).then(function (responses) { + if (failAll && responses.some(function (data) { + return data.error; + })) { + return Promise.reject(new Error('Wrong response status')); + } + + if (!failAll) { + responses = responses.filter(function (data) { + return !data.error; + }); + } + + return deleting.then(function () { + var addAll = responses.map(function (_ref, i) { + var response = _ref.response; + + return cache.put(requests[i], response); + }); + + return Promise.all(addAll); + }); + }); + } + + function matchCacheMap(request) { + var urlString = request.url; + var url = new URL(urlString); + + var requestType = undefined; + + if (isNavigateRequest(request)) { + requestType = 'navigate'; + } else if (url.origin === location.origin) { + requestType = 'same-origin'; + } else { + requestType = 'cross-origin'; + } + + for (var i = 0; i < cacheMaps.length; i++) { + var map = cacheMaps[i]; + + if (!map) continue; + if (map.requestTypes && map.requestTypes.indexOf(requestType) === -1) { + continue; + } + + var newString = undefined; + + if (typeof map.match === 'function') { + newString = map.match(url, request); + } else { + newString = urlString.replace(map.match, map.to); + } + + if (newString && newString !== urlString) { + return newString; + } + } + } + + function fetchWithPreload(event) { + if (!event.preloadResponse || navigationPreload !== true) { + return fetch(event.request); + } + + return event.preloadResponse.then(function (response) { + return response || fetch(event.request); + }); + } +} + +function cachesMatch(request, cacheName) { + return caches.match(request, { + cacheName: cacheName + }).then(function (response) { + if (isNotRedirectedResponse(response)) { + return response; + } + + // Fix already cached redirected responses + return fixRedirectedResponse(response).then(function (fixedResponse) { + return caches.open(cacheName).then(function (cache) { + return cache.put(request, fixedResponse); + }).then(function () { + return fixedResponse; + }); + }); + }) + // Return void if error happened (cache not found) + ['catch'](function () {}); +} + +function applyCacheBust(asset, key) { + var hasQuery = asset.indexOf('?') !== -1; + return asset + (hasQuery ? '&' : '?') + '__uncache=' + encodeURIComponent(key); +} + +function isNavigateRequest(request) { + return request.mode === 'navigate' || request.headers.get('Upgrade-Insecure-Requests') || (request.headers.get('Accept') || '').indexOf('text/html') !== -1; +} + +function isNotRedirectedResponse(response) { + return !response || !response.redirected || !response.ok || response.type === 'opaqueredirect'; +} + +// Based on https://github.com/GoogleChrome/sw-precache/pull/241/files#diff-3ee9060dc7a312c6a822cac63a8c630bR85 +function fixRedirectedResponse(response) { + if (isNotRedirectedResponse(response)) { + return Promise.resolve(response); + } + + var body = 'body' in response ? Promise.resolve(response.body) : response.blob(); + + return body.then(function (data) { + return new Response(data, { + headers: response.headers, + status: response.status + }); + }); +} + +function copyObject(original) { + return Object.keys(original).reduce(function (result, key) { + result[key] = original[key]; + return result; + }, {}); +} + +function logGroup(title, assets) { + console.groupCollapsed('[SW]:', title); + + assets.forEach(function (asset) { + console.log('Asset:', asset); + }); + + console.groupEnd(); +} + WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), +loaders: {}, +cacheMaps: [], +navigationPreload: false, +}); + module.exports = __webpack_require__(1) + + +/***/ }), /* 1 */ -/***/ function(module, exports) { +/***/ (function(module, exports) { - // custom sw entry +// custom sw entry -/***/ } +/***/ }) /******/ ]); \ No newline at end of file diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js index d0a465f9..f7b9ccaa 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack2/sw.js @@ -523,8 +523,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -876,8 +876,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [], navigationPreload: false, diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js index f6e8c864..3ce80423 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack3/sw.js @@ -514,8 +514,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -867,8 +867,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [], navigationPreload: false, diff --git a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js index f771fa0d..ad57d16c 100644 --- a/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/basic-with-sw-custom-entry/__expected/webpack4/sw.js @@ -535,8 +535,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -888,8 +888,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [], navigationPreload: false, diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js index bf4588bf..0ebdcca1 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/sw.js @@ -16,786 +16,916 @@ var __wpo = { /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; - +/******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { - +/******/ /******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) +/******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; - +/******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} /******/ }; - +/******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - +/******/ /******/ // Flag the module as loaded -/******/ module.loaded = true; - +/******/ module.l = true; +/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } - - +/******/ +/******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; - +/******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; - +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; - +/******/ +/******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(0); +/******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ -/***/ function(module, exports, __webpack_require__) { +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; - "use strict"; - - (function () { - var waitUntil = ExtendableEvent.prototype.waitUntil; - var respondWith = FetchEvent.prototype.respondWith; - var promisesMap = new WeakMap(); - - ExtendableEvent.prototype.waitUntil = function (promise) { - var extendableEvent = this; - var promises = promisesMap.get(extendableEvent); - - if (promises) { - promises.push(Promise.resolve(promise)); - return; - } - - promises = [Promise.resolve(promise)]; - promisesMap.set(extendableEvent, promises); - - // call original method - return waitUntil.call(extendableEvent, Promise.resolve().then(function processPromises() { - var len = promises.length; - - // wait for all to settle - return Promise.all(promises.map(function (p) { - return p["catch"](function () {}); - })).then(function () { - // have new items been added? If so, wait again - if (promises.length != len) return processPromises(); - // we're done! - promisesMap["delete"](extendableEvent); - // reject if one of the promises rejected - return Promise.all(promises); - }); - })); - }; - - FetchEvent.prototype.respondWith = function (promise) { - this.waitUntil(promise); - return respondWith.call(this, promise); - }; - })();; - 'use strict'; - - if (false) { - var DEBUG = false; - } - - function WebpackServiceWorker(params, helpers) { - var loaders = helpers.loaders; - var cacheMaps = helpers.cacheMaps; - - var strategy = params.strategy; - var responseStrategy = params.responseStrategy; - - var assets = params.assets; - var loadersMap = params.loaders || {}; - - var hashesMap = params.hashesMap; - var externals = params.externals; - - // Not used yet - // const alwaysRevalidate = params.alwaysRevalidate; - // const ignoreSearch = params.ignoreSearch; - // const preferOnline = params.preferOnline; - - var CACHE_PREFIX = params.name; - var CACHE_TAG = params.version; - var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG; - - var STORED_DATA_KEY = '__offline_webpack__data'; - - mapAssets(); - - var allAssets = [].concat(assets.main, assets.additional, assets.optional); - var navigateFallbackURL = params.navigateFallbackURL; - var navigateFallbackForRedirects = params.navigateFallbackForRedirects; - - self.addEventListener('install', function (event) { - console.log('[SW]:', 'Install event'); - - var installing = undefined; - - if (strategy === 'changed') { - installing = cacheChanged('main'); - } else { - installing = cacheAssets('main'); - } - - event.waitUntil(installing); - }); - - self.addEventListener('activate', function (event) { - console.log('[SW]:', 'Activate event'); - - var activation = cacheAdditional(); - - // Delete all assets which name starts with CACHE_PREFIX and - // is not current cache (CACHE_NAME) - activation = activation.then(storeCacheData); - activation = activation.then(deleteObsolete); - activation = activation.then(function () { - if (self.clients && self.clients.claim) { - return self.clients.claim(); - } - }); - - event.waitUntil(activation); - }); - - function cacheAdditional() { - if (!assets.additional.length) { - return Promise.resolve(); - } - - if (false) { - console.log('[SW]:', 'Caching additional'); - } - - var operation = undefined; - - if (strategy === 'changed') { - operation = cacheChanged('additional'); - } else { - operation = cacheAssets('additional'); - } - - // Ignore fail of `additional` cache section - return operation['catch'](function (e) { - console.error('[SW]:', 'Cache section `additional` failed to load'); - }); - } - - function cacheAssets(section) { - var batch = assets[section]; - - return caches.open(CACHE_NAME).then(function (cache) { - return addAllNormalized(cache, batch, { - bust: params.version, - request: params.prefetchRequest - }); - }).then(function () { - logGroup('Cached assets: ' + section, batch); - })['catch'](function (e) { - console.error(e); - throw e; - }); - } - - function cacheChanged(section) { - return getLastCache().then(function (args) { - if (!args) { - return cacheAssets(section); - } - - var lastCache = args[0]; - var lastKeys = args[1]; - var lastData = args[2]; - - var lastMap = lastData.hashmap; - var lastVersion = lastData.version; - - if (!lastData.hashmap || lastVersion === params.version) { - return cacheAssets(section); - } - - var lastHashedAssets = Object.keys(lastMap).map(function (hash) { - return lastMap[hash]; - }); - - var lastUrls = lastKeys.map(function (req) { - var url = new URL(req.url); - url.search = ''; - url.hash = ''; - - return url.toString(); - }); - - var sectionAssets = assets[section]; - var moved = []; - var changed = sectionAssets.filter(function (url) { - if (lastUrls.indexOf(url) === -1 || lastHashedAssets.indexOf(url) === -1) { - return true; - } - - return false; - }); - - Object.keys(hashesMap).forEach(function (hash) { - var asset = hashesMap[hash]; - - // Return if not in sectionAssets or in changed or moved array - if (sectionAssets.indexOf(asset) === -1 || changed.indexOf(asset) !== -1 || moved.indexOf(asset) !== -1) return; - - var lastAsset = lastMap[hash]; - - if (lastAsset && lastUrls.indexOf(lastAsset) !== -1) { - moved.push([lastAsset, asset]); - } else { - changed.push(asset); - } - }); - - logGroup('Changed assets: ' + section, changed); - logGroup('Moved assets: ' + section, moved); - - var movedResponses = Promise.all(moved.map(function (pair) { - return lastCache.match(pair[0]).then(function (response) { - return [pair[1], response]; - }); - })); - - return caches.open(CACHE_NAME).then(function (cache) { - var move = movedResponses.then(function (responses) { - return Promise.all(responses.map(function (pair) { - return cache.put(pair[0], pair[1]); - })); - }); - - return Promise.all([move, addAllNormalized(cache, changed, { - bust: params.version, - request: params.prefetchRequest - })]); - }); - }); - } - - function deleteObsolete() { - return caches.keys().then(function (keys) { - var all = keys.map(function (key) { - if (key.indexOf(CACHE_PREFIX) !== 0 || key.indexOf(CACHE_NAME) === 0) return; - - console.log('[SW]:', 'Delete cache:', key); - return caches['delete'](key); - }); - - return Promise.all(all); - }); - } - - function getLastCache() { - return caches.keys().then(function (keys) { - var index = keys.length; - var key = undefined; - - while (index--) { - key = keys[index]; - - if (key.indexOf(CACHE_PREFIX) === 0) { - break; - } - } - - if (!key) return; - - var cache = undefined; - - return caches.open(key).then(function (_cache) { - cache = _cache; - return _cache.match(new URL(STORED_DATA_KEY, location).toString()); - }).then(function (response) { - if (!response) return; - - return Promise.all([cache, cache.keys(), response.json()]); - }); - }); - } - - function storeCacheData() { - return caches.open(CACHE_NAME).then(function (cache) { - var data = new Response(JSON.stringify({ - version: params.version, - hashmap: hashesMap - })); - - return cache.put(new URL(STORED_DATA_KEY, location).toString(), data); - }); - } - - self.addEventListener('fetch', function (event) { - var url = new URL(event.request.url); - url.hash = ''; - - var urlString = url.toString(); - - // Not external, so search part of the URL should be stripped, - // if it's external URL, the search part should be kept - if (externals.indexOf(urlString) === -1) { - url.search = ''; - urlString = url.toString(); - } - - // Handle only GET requests - var isGET = event.request.method === 'GET'; - var assetMatches = allAssets.indexOf(urlString) !== -1; - var cacheUrl = urlString; - - if (!assetMatches) { - var cacheRewrite = matchCacheMap(event.request); - - if (cacheRewrite) { - cacheUrl = cacheRewrite; - assetMatches = true; - } - } - - if (!assetMatches && isGET) { - // If isn't a cached asset and is a navigation request, - // fallback to navigateFallbackURL if available - if (navigateFallbackURL && isNavigateRequest(event.request)) { - event.respondWith(handleNavigateFallback(fetch(event.request))); - - return; - } - } - - if (!assetMatches || !isGET) { - // Fix for https://twitter.com/wanderview/status/696819243262873600 - if (url.origin !== location.origin && navigator.userAgent.indexOf('Firefox/44.') !== -1) { - event.respondWith(fetch(event.request)); - } - - return; - } - - // Logic of caching / fetching is here - // * urlString -- url to match from the CACHE_NAME - // * event.request -- original Request to perform fetch() if necessary - var resource = undefined; - - if (responseStrategy === 'network-first') { - resource = networkFirstResponse(event, urlString, cacheUrl); - } - // 'cache-first' - // (responseStrategy has been validated before) - else { - resource = cacheFirstResponse(event, urlString, cacheUrl); - } - - if (navigateFallbackURL && isNavigateRequest(event.request)) { - resource = handleNavigateFallback(resource); - } - - event.respondWith(resource); - }); - - self.addEventListener('message', function (e) { - var data = e.data; - if (!data) return; - - switch (data.action) { - case 'skipWaiting': - { - if (self.skipWaiting) self.skipWaiting(); - }break; - } - }); - - function cacheFirstResponse(event, urlString, cacheUrl) { - return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { - if (response) { - if (false) { - console.log('[SW]:', 'URL [' + cacheUrl + '](' + urlString + ') from cache'); - } - - return response; - } - - // Load and cache known assets - var fetching = fetch(event.request).then(function (response) { - if (!response.ok) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] wrong response: [' + response.status + '] ' + response.type); - } - - return response; - } - - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - if (cacheUrl === urlString) { - (function () { - var responseClone = response.clone(); - var storing = caches.open(CACHE_NAME).then(function (cache) { - return cache.put(urlString, responseClone); - }).then(function () { - console.log('[SW]:', 'Cache asset: ' + urlString); - }); - - event.waitUntil(storing); - })(); - } - - return response; - }); - - return fetching; - }); - } - - function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); - } - return response.ok; - } - - function networkFirstResponse(event, urlString, cacheUrl) { - return fetch(event.request).then(function (response) { - if (shouldServeFromNetwork(response, urlString, cacheUrl)) { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from network'); - } - - return response; - } - - // Throw to reach the code in the catch below - throw new Error('Response is not ok'); - }) - // This needs to be in a catch() and not just in the then() above - // cause if your network is down, the fetch() will throw - ['catch'](function () { - if (false) { - console.log('[SW]:', 'URL [' + urlString + '] from cache if possible'); - } - - return cachesMatch(cacheUrl, CACHE_NAME); - }); - } - - function handleNavigateFallback(fetching) { - return fetching['catch'](function () {}).then(function (response) { - var isOk = response && response.ok; - var isRedirect = response && response.type === 'opaqueredirect'; - - if (isOk || isRedirect && !navigateFallbackForRedirects) { - return response; - } - - if (false) { - console.log('[SW]:', 'Loading navigation fallback [' + navigateFallbackURL + '] from cache'); - } - - return cachesMatch(navigateFallbackURL, CACHE_NAME); - }); - } - - function mapAssets() { - Object.keys(assets).forEach(function (key) { - assets[key] = assets[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - Object.keys(loadersMap).forEach(function (key) { - loadersMap[key] = loadersMap[key].map(function (path) { - var url = new URL(path, location); - - url.hash = ''; - - if (externals.indexOf(path) === -1) { - url.search = ''; - } - - return url.toString(); - }); - }); - - hashesMap = Object.keys(hashesMap).reduce(function (result, hash) { - var url = new URL(hashesMap[hash], location); - url.search = ''; - url.hash = ''; - - result[hash] = url.toString(); - return result; - }, {}); - - externals = externals.map(function (path) { - var url = new URL(path, location); - url.hash = ''; - - return url.toString(); - }); - } - - function addAllNormalized(cache, requests, options) { - var allowLoaders = options.allowLoaders !== false; - var bustValue = options && options.bust; - var requestInit = options.request || { - credentials: 'omit', - mode: 'cors' - }; - - return Promise.all(requests.map(function (request) { - if (bustValue) { - request = applyCacheBust(request, bustValue); - } - - return fetch(request, requestInit).then(fixRedirectedResponse); - })).then(function (responses) { - if (responses.some(function (response) { - return !response.ok; - })) { - return Promise.reject(new Error('Wrong response status')); - } - - var extracted = []; - var addAll = responses.map(function (response, i) { - if (allowLoaders) { - extracted.push(extractAssetsWithLoaders(requests[i], response)); - } - - return cache.put(requests[i], response); - }); - - if (extracted.length) { - (function () { - var newOptions = copyObject(options); - newOptions.allowLoaders = false; - - var waitAll = addAll; - - addAll = Promise.all(extracted).then(function (all) { - var extractedRequests = [].concat.apply([], all); - - if (requests.length) { - waitAll = waitAll.concat(addAllNormalized(cache, extractedRequests, newOptions)); - } - - return Promise.all(waitAll); - }); - })(); - } else { - addAll = Promise.all(addAll); - } - - return addAll; - }); - } - - function extractAssetsWithLoaders(request, response) { - var all = Object.keys(loadersMap).map(function (key) { - var loader = loadersMap[key]; - - if (loader.indexOf(request) !== -1 && loaders[key]) { - return loaders[key](response.clone()); - } - }).filter(function (a) { - return !!a; - }); - - return Promise.all(all).then(function (all) { - return [].concat.apply([], all); - }); - } - - function matchCacheMap(request) { - var urlString = request.url; - var url = new URL(urlString); - - var requestType = undefined; - - if (request.mode === 'navigate') { - requestType = 'navigate'; - } else if (url.origin === location.origin) { - requestType = 'same-origin'; - } else { - requestType = 'cross-origin'; - } - - for (var i = 0; i < cacheMaps.length; i++) { - var map = cacheMaps[i]; - - if (!map) continue; - if (map.requestTypes && map.requestTypes.indexOf(requestType) === -1) { - continue; - } - - var newString = undefined; - - if (typeof map.match === 'function') { - newString = map.match(url, request); - } else { - newString = urlString.replace(map.match, map.to); - } - - if (newString && newString !== urlString) { - return newString; - } - } - } - } - - function cachesMatch(request, cacheName) { - return caches.match(request, { - cacheName: cacheName - }).then(function (response) { - if (isNotRedirectedResponse()) { - return response; - } - - // Fix already cached redirected responses - return fixRedirectedResponse(response).then(function (fixedResponse) { - return caches.open(cacheName).then(function (cache) { - return cache.put(request, fixedResponse); - }).then(function () { - return fixedResponse; - }); - }); - }) - // Return void if error happened (cache not found) - ['catch'](function () {}); - } - - function applyCacheBust(asset, key) { - var hasQuery = asset.indexOf('?') !== -1; - return asset + (hasQuery ? '&' : '?') + '__uncache=' + encodeURIComponent(key); - } - - function getClientsURLs() { - if (!self.clients) { - return Promise.resolve([]); - } - - return self.clients.matchAll({ - includeUncontrolled: true - }).then(function (clients) { - if (!clients.length) return []; - - var result = []; - - clients.forEach(function (client) { - var url = new URL(client.url); - url.search = ''; - url.hash = ''; - var urlString = url.toString(); - - if (!result.length || result.indexOf(urlString) === -1) { - result.push(urlString); - } - }); - - return result; - }); - } - - function isNavigateRequest(request) { - return request.mode === 'navigate' || request.headers.get('Upgrade-Insecure-Requests') || (request.headers.get('Accept') || '').indexOf('text/html') !== -1; - } - - function isNotRedirectedResponse(response) { - return !response || !response.redirected || !response.ok || response.type === 'opaqueredirect'; - } - - // Based on https://github.com/GoogleChrome/sw-precache/pull/241/files#diff-3ee9060dc7a312c6a822cac63a8c630bR85 - function fixRedirectedResponse(response) { - if (isNotRedirectedResponse(response)) { - return Promise.resolve(response); - } - - var body = 'body' in response ? Promise.resolve(response.body) : response.blob(); - - return body.then(function (data) { - return new Response(data, { - headers: response.headers, - status: response.status - }); - }); - } - - function copyObject(original) { - return Object.keys(original).reduce(function (result, key) { - result[key] = original[key]; - return result; - }, {}); - } - - function logGroup(title, assets) { - console.groupCollapsed('[SW]:', title); - - assets.forEach(function (asset) { - console.log('Asset:', asset); - }); - - console.groupEnd(); - } - WebpackServiceWorker(__wpo, { - loaders: {}, - cacheMaps: [ - { - match: /^https:\/\/google\.com\/([\s\S]+)$/, - to: "https://facebook.com/$1", - requestTypes: null, - }, - { - match: function (url) { - if (url.href.indexOf('https://google.com') === 0) { - return url.href.replace('https://google.com', 'https://facebook.com'); - } - }, - to: null, - requestTypes: null, - }, - { - match: function (url) { - if (url.origin !== location.origin) return; - - if (url.pathname.indexOf('/api/') === 0) { - return; - } - - return new URL('/', location); - }, - to: null, - requestTypes: null, - } - ], - }); - module.exports = __webpack_require__(1) - - -/***/ }, + +(function () { + var waitUntil = ExtendableEvent.prototype.waitUntil; + var respondWith = FetchEvent.prototype.respondWith; + var promisesMap = new WeakMap(); + + ExtendableEvent.prototype.waitUntil = function (promise) { + var extendableEvent = this; + var promises = promisesMap.get(extendableEvent); + + if (promises) { + promises.push(Promise.resolve(promise)); + return; + } + + promises = [Promise.resolve(promise)]; + promisesMap.set(extendableEvent, promises); + + // call original method + return waitUntil.call(extendableEvent, Promise.resolve().then(function processPromises() { + var len = promises.length; + + // wait for all to settle + return Promise.all(promises.map(function (p) { + return p["catch"](function () {}); + })).then(function () { + // have new items been added? If so, wait again + if (promises.length != len) return processPromises(); + // we're done! + promisesMap["delete"](extendableEvent); + // reject if one of the promises rejected + return Promise.all(promises); + }); + })); + }; + + FetchEvent.prototype.respondWith = function (promise) { + this.waitUntil(promise); + return respondWith.call(this, promise); + }; +})();; + 'use strict'; + +if (typeof DEBUG === 'undefined') { + var DEBUG = false; +} + +function WebpackServiceWorker(params, helpers) { + var cacheMaps = helpers.cacheMaps; + // navigationPreload: true, { map: (URL) => URL, test: (URL) => boolean } + var navigationPreload = helpers.navigationPreload; + + // (update)strategy: changed, all + var strategy = params.strategy; + // responseStrategy: cache-first, network-first + var responseStrategy = params.responseStrategy; + + var assets = params.assets; + + var hashesMap = params.hashesMap; + var externals = params.externals; + + var prefetchRequest = params.prefetchRequest || { + credentials: 'same-origin', + mode: 'cors' + }; + + var CACHE_PREFIX = params.name; + var CACHE_TAG = params.version; + var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG; + + var PRELOAD_CACHE_NAME = CACHE_PREFIX + '$preload'; + var STORED_DATA_KEY = '__offline_webpack__data'; + + mapAssets(); + + var allAssets = [].concat(assets.main, assets.additional, assets.optional); + + self.addEventListener('install', function (event) { + console.log('[SW]:', 'Install event'); + + var installing = undefined; + + if (strategy === 'changed') { + installing = cacheChanged('main'); + } else { + installing = cacheAssets('main'); + } + + event.waitUntil(installing); + }); + + self.addEventListener('activate', function (event) { + console.log('[SW]:', 'Activate event'); + + var activation = cacheAdditional(); + + // Delete all assets which name starts with CACHE_PREFIX and + // is not current cache (CACHE_NAME) + activation = activation.then(storeCacheData); + activation = activation.then(deleteObsolete); + activation = activation.then(function () { + if (self.clients && self.clients.claim) { + return self.clients.claim(); + } + }); + + if (navigationPreload && self.registration.navigationPreload) { + activation = Promise.all([activation, self.registration.navigationPreload.enable()]); + } + + event.waitUntil(activation); + }); + + function cacheAdditional() { + if (!assets.additional.length) { + return Promise.resolve(); + } + + if (DEBUG) { + console.log('[SW]:', 'Caching additional'); + } + + var operation = undefined; + + if (strategy === 'changed') { + operation = cacheChanged('additional'); + } else { + operation = cacheAssets('additional'); + } + + // Ignore fail of `additional` cache section + return operation['catch'](function (e) { + console.error('[SW]:', 'Cache section `additional` failed to load'); + }); + } + + function cacheAssets(section) { + var batch = assets[section]; + + return caches.open(CACHE_NAME).then(function (cache) { + return addAllNormalized(cache, batch, { + bust: params.version, + request: prefetchRequest, + failAll: section === 'main' + }); + }).then(function () { + logGroup('Cached assets: ' + section, batch); + })['catch'](function (e) { + console.error(e); + throw e; + }); + } + + function cacheChanged(section) { + return getLastCache().then(function (args) { + if (!args) { + return cacheAssets(section); + } + + var lastCache = args[0]; + var lastKeys = args[1]; + var lastData = args[2]; + + var lastMap = lastData.hashmap; + var lastVersion = lastData.version; + + if (!lastData.hashmap || lastVersion === params.version) { + return cacheAssets(section); + } + + var lastHashedAssets = Object.keys(lastMap).map(function (hash) { + return lastMap[hash]; + }); + + var lastUrls = lastKeys.map(function (req) { + var url = new URL(req.url); + url.search = ''; + url.hash = ''; + + return url.toString(); + }); + + var sectionAssets = assets[section]; + var moved = []; + var changed = sectionAssets.filter(function (url) { + if (lastUrls.indexOf(url) === -1 || lastHashedAssets.indexOf(url) === -1) { + return true; + } + + return false; + }); + + Object.keys(hashesMap).forEach(function (hash) { + var asset = hashesMap[hash]; + + // Return if not in sectionAssets or in changed or moved array + if (sectionAssets.indexOf(asset) === -1 || changed.indexOf(asset) !== -1 || moved.indexOf(asset) !== -1) return; + + var lastAsset = lastMap[hash]; + + if (lastAsset && lastUrls.indexOf(lastAsset) !== -1) { + moved.push([lastAsset, asset]); + } else { + changed.push(asset); + } + }); + + logGroup('Changed assets: ' + section, changed); + logGroup('Moved assets: ' + section, moved); + + var movedResponses = Promise.all(moved.map(function (pair) { + return lastCache.match(pair[0]).then(function (response) { + return [pair[1], response]; + }); + })); + + return caches.open(CACHE_NAME).then(function (cache) { + var move = movedResponses.then(function (responses) { + return Promise.all(responses.map(function (pair) { + return cache.put(pair[0], pair[1]); + })); + }); + + return Promise.all([move, addAllNormalized(cache, changed, { + bust: params.version, + request: prefetchRequest, + failAll: section === 'main', + deleteFirst: section !== 'main' + })]); + }); + }); + } + + function deleteObsolete() { + return caches.keys().then(function (keys) { + var all = keys.map(function (key) { + if (key.indexOf(CACHE_PREFIX) !== 0 || key.indexOf(CACHE_NAME) === 0) return; + + console.log('[SW]:', 'Delete cache:', key); + return caches['delete'](key); + }); + + return Promise.all(all); + }); + } + + function getLastCache() { + return caches.keys().then(function (keys) { + var index = keys.length; + var key = undefined; + + while (index--) { + key = keys[index]; + + if (key.indexOf(CACHE_PREFIX) === 0) { + break; + } + } + + if (!key) return; + + var cache = undefined; + + return caches.open(key).then(function (_cache) { + cache = _cache; + return _cache.match(new URL(STORED_DATA_KEY, location).toString()); + }).then(function (response) { + if (!response) return; + + return Promise.all([cache, cache.keys(), response.json()]); + }); + }); + } + + function storeCacheData() { + return caches.open(CACHE_NAME).then(function (cache) { + var data = new Response(JSON.stringify({ + version: params.version, + hashmap: hashesMap + })); + + return cache.put(new URL(STORED_DATA_KEY, location).toString(), data); + }); + } + + self.addEventListener('fetch', function (event) { + // Handle only GET requests + if (event.request.method !== 'GET') { + return; + } + + // This prevents some weird issue with Chrome DevTools and 'only-if-cached' + // Fixes issue #385, also ref to: + // - https://github.com/paulirish/caltrainschedule.io/issues/49 + // - https://bugs.chromium.org/p/chromium/issues/detail?id=823392 + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + return; + } + + var url = new URL(event.request.url); + url.hash = ''; + + var urlString = url.toString(); + + // Not external, so search part of the URL should be stripped, + // if it's external URL, the search part should be kept + if (externals.indexOf(urlString) === -1) { + url.search = ''; + urlString = url.toString(); + } + + var assetMatches = allAssets.indexOf(urlString) !== -1; + var cacheUrl = urlString; + + if (!assetMatches) { + var cacheRewrite = matchCacheMap(event.request); + + if (cacheRewrite) { + cacheUrl = cacheRewrite; + assetMatches = true; + } + } + + if (!assetMatches) { + // Use request.mode === 'navigate' instead of isNavigateRequest + // because everything what supports navigationPreload supports + // 'navigate' request.mode + if (event.request.mode === 'navigate') { + // Requesting with fetchWithPreload(). + // Preload is used only if navigationPreload is enabled and + // navigationPreload mapping is not used. + if (navigationPreload === true) { + event.respondWith(fetchWithPreload(event)); + return; + } + } + + // Something else, positive, but not `true` + if (navigationPreload) { + var preloadedResponse = retrivePreloadedResponse(event); + + if (preloadedResponse) { + event.respondWith(preloadedResponse); + return; + } + } + + // Logic exists here if no cache match + return; + } + + // Cache handling/storing/fetching starts here + var resource = undefined; + + if (responseStrategy === 'network-first') { + resource = networkFirstResponse(event, urlString, cacheUrl); + } + // 'cache-first' otherwise + // (responseStrategy has been validated before) + else { + resource = cacheFirstResponse(event, urlString, cacheUrl); + } + + event.respondWith(resource); + }); + + self.addEventListener('message', function (e) { + var data = e.data; + if (!data) return; + + switch (data.action) { + case 'skipWaiting': + { + if (self.skipWaiting) self.skipWaiting(); + }break; + } + }); + + function cacheFirstResponse(event, urlString, cacheUrl) { + handleNavigationPreload(event); + + return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { + if (response) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + cacheUrl + '](' + urlString + ') from cache'); + } + + return response; + } + + // Load and cache known assets + var fetching = fetch(event.request).then(function (response) { + if (!response.ok) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] wrong response: [' + response.status + '] ' + response.type); + } + + return response; + } + + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] from network'); + } + + if (cacheUrl === urlString) { + (function () { + var responseClone = response.clone(); + var storing = caches.open(CACHE_NAME).then(function (cache) { + return cache.put(urlString, responseClone); + }).then(function () { + console.log('[SW]:', 'Cache asset: ' + urlString); + }); + + event.waitUntil(storing); + })(); + } + + return response; + }); + + return fetching; + }); + } + + function shouldServeFromNetwork(response, urlString, cacheUrl) { + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); + } + return response.ok; + } + + function networkFirstResponse(event, urlString, cacheUrl) { + return fetchWithPreload(event).then(function (response) { + if (shouldServeFromNetwork(response, urlString, cacheUrl)) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] from network'); + } + + return response; + } + + // Throw to reach the code in the catch below + throw response; + }) + // This needs to be in a catch() and not just in the then() above + // cause if your network is down, the fetch() will throw + ['catch'](function (erroredResponse) { + if (DEBUG) { + console.log('[SW]:', 'URL [' + urlString + '] from cache if possible'); + } + + return cachesMatch(cacheUrl, CACHE_NAME).then(function (response) { + if (response) { + return response; + } + + if (erroredResponse instanceof Response) { + return erroredResponse; + } + + // Not a response at this point, some other error + throw erroredResponse; + // return Response.error(); + }); + }); + } + + function handleNavigationPreload(event) { + if (navigationPreload && typeof navigationPreload.map === 'function' && + // Use request.mode === 'navigate' instead of isNavigateRequest + // because everything what supports navigationPreload supports + // 'navigate' request.mode + event.preloadResponse && event.request.mode === 'navigate') { + var mapped = navigationPreload.map(new URL(event.request.url), event.request); + + if (mapped) { + storePreloadedResponse(mapped, event); + } + } + } + + // Temporary in-memory store for faster access + var navigationPreloadStore = new Map(); + + function storePreloadedResponse(_url, event) { + var url = new URL(_url, location); + var preloadResponsePromise = event.preloadResponse; + + navigationPreloadStore.set(preloadResponsePromise, { + url: url, + response: preloadResponsePromise + }); + + var isSamePreload = function isSamePreload() { + return navigationPreloadStore.has(preloadResponsePromise); + }; + + var storing = preloadResponsePromise.then(function (res) { + // Return if preload isn't enabled or hasn't happened + if (!res) return; + + // If navigationPreloadStore already consumed + // or navigationPreloadStore already contains another preload, + // then do not store anything and return + if (!isSamePreload()) { + return; + } + + var clone = res.clone(); + + // Storing the preload response for later consume (hasn't yet been consumed) + return caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + if (!isSamePreload()) return; + + return cache.put(url, clone).then(function () { + if (!isSamePreload()) { + return caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + return cache['delete'](url); + }); + } + }); + }); + }); + + event.waitUntil(storing); + } + + function retriveInMemoryPreloadedResponse(url) { + if (!navigationPreloadStore) { + return; + } + + var foundResponse = undefined; + var foundKey = undefined; + + navigationPreloadStore.forEach(function (store, key) { + if (store.url.href === url.href) { + foundResponse = store.response; + foundKey = key; + } + }); + + if (foundResponse) { + navigationPreloadStore['delete'](foundKey); + return foundResponse; + } + } + + function retrivePreloadedResponse(event) { + var url = new URL(event.request.url); + + if (self.registration.navigationPreload && navigationPreload && navigationPreload.test && navigationPreload.test(url, event.request)) {} else { + return; + } + + var fromMemory = retriveInMemoryPreloadedResponse(url); + var request = event.request; + + if (fromMemory) { + event.waitUntil(caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + return cache['delete'](request); + })); + + return fromMemory; + } + + return cachesMatch(request, PRELOAD_CACHE_NAME).then(function (response) { + if (response) { + event.waitUntil(caches.open(PRELOAD_CACHE_NAME).then(function (cache) { + return cache['delete'](request); + })); + } + + return response || fetch(event.request); + }); + } + + function mapAssets() { + Object.keys(assets).forEach(function (key) { + assets[key] = assets[key].map(function (path) { + var url = new URL(path, location); + + url.hash = ''; + + if (externals.indexOf(path) === -1) { + url.search = ''; + } + + return url.toString(); + }); + }); + + hashesMap = Object.keys(hashesMap).reduce(function (result, hash) { + var url = new URL(hashesMap[hash], location); + url.search = ''; + url.hash = ''; + + result[hash] = url.toString(); + return result; + }, {}); + + externals = externals.map(function (path) { + var url = new URL(path, location); + url.hash = ''; + + return url.toString(); + }); + } + + function addAllNormalized(cache, requests, options) { + var bustValue = options.bust; + var failAll = options.failAll !== false; + var deleteFirst = options.deleteFirst === true; + var requestInit = options.request || { + credentials: 'omit', + mode: 'cors' + }; + + var deleting = Promise.resolve(); + + if (deleteFirst) { + deleting = Promise.all(requests.map(function (request) { + return cache['delete'](request)['catch'](function () {}); + })); + } + + return Promise.all(requests.map(function (request) { + if (bustValue) { + request = applyCacheBust(request, bustValue); + } + + return fetch(request, requestInit).then(fixRedirectedResponse).then(function (response) { + if (!response.ok) { + return { error: true }; + } + + return { response: response }; + }, function () { + return { error: true }; + }); + })).then(function (responses) { + if (failAll && responses.some(function (data) { + return data.error; + })) { + return Promise.reject(new Error('Wrong response status')); + } + + if (!failAll) { + responses = responses.filter(function (data) { + return !data.error; + }); + } + + return deleting.then(function () { + var addAll = responses.map(function (_ref, i) { + var response = _ref.response; + + return cache.put(requests[i], response); + }); + + return Promise.all(addAll); + }); + }); + } + + function matchCacheMap(request) { + var urlString = request.url; + var url = new URL(urlString); + + var requestType = undefined; + + if (isNavigateRequest(request)) { + requestType = 'navigate'; + } else if (url.origin === location.origin) { + requestType = 'same-origin'; + } else { + requestType = 'cross-origin'; + } + + for (var i = 0; i < cacheMaps.length; i++) { + var map = cacheMaps[i]; + + if (!map) continue; + if (map.requestTypes && map.requestTypes.indexOf(requestType) === -1) { + continue; + } + + var newString = undefined; + + if (typeof map.match === 'function') { + newString = map.match(url, request); + } else { + newString = urlString.replace(map.match, map.to); + } + + if (newString && newString !== urlString) { + return newString; + } + } + } + + function fetchWithPreload(event) { + if (!event.preloadResponse || navigationPreload !== true) { + return fetch(event.request); + } + + return event.preloadResponse.then(function (response) { + return response || fetch(event.request); + }); + } +} + +function cachesMatch(request, cacheName) { + return caches.match(request, { + cacheName: cacheName + }).then(function (response) { + if (isNotRedirectedResponse(response)) { + return response; + } + + // Fix already cached redirected responses + return fixRedirectedResponse(response).then(function (fixedResponse) { + return caches.open(cacheName).then(function (cache) { + return cache.put(request, fixedResponse); + }).then(function () { + return fixedResponse; + }); + }); + }) + // Return void if error happened (cache not found) + ['catch'](function () {}); +} + +function applyCacheBust(asset, key) { + var hasQuery = asset.indexOf('?') !== -1; + return asset + (hasQuery ? '&' : '?') + '__uncache=' + encodeURIComponent(key); +} + +function isNavigateRequest(request) { + return request.mode === 'navigate' || request.headers.get('Upgrade-Insecure-Requests') || (request.headers.get('Accept') || '').indexOf('text/html') !== -1; +} + +function isNotRedirectedResponse(response) { + return !response || !response.redirected || !response.ok || response.type === 'opaqueredirect'; +} + +// Based on https://github.com/GoogleChrome/sw-precache/pull/241/files#diff-3ee9060dc7a312c6a822cac63a8c630bR85 +function fixRedirectedResponse(response) { + if (isNotRedirectedResponse(response)) { + return Promise.resolve(response); + } + + var body = 'body' in response ? Promise.resolve(response.body) : response.blob(); + + return body.then(function (data) { + return new Response(data, { + headers: response.headers, + status: response.status + }); + }); +} + +function copyObject(original) { + return Object.keys(original).reduce(function (result, key) { + result[key] = original[key]; + return result; + }, {}); +} + +function logGroup(title, assets) { + console.groupCollapsed('[SW]:', title); + + assets.forEach(function (asset) { + console.log('Asset:', asset); + }); + + console.groupEnd(); +} + WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), +loaders: {}, +cacheMaps: [ + { + match: /^https:\/\/google\.com\/([\s\S]+)$/, + to: "https://facebook.com/$1", + requestTypes: null, + }, +{ + match: function (url) { + if (url.href.indexOf('https://google.com') === 0) { + return url.href.replace('https://google.com', 'https://facebook.com'); + } + }, + to: null, + requestTypes: null, + }, +{ + match: function (url) { + if (url.origin !== location.origin) return; + + if (url.pathname.indexOf('/api/') === 0) { + return; + } + + return new URL('/', location); + }, + to: null, + requestTypes: null, + } + ], +navigationPreload: false, +}); + module.exports = __webpack_require__(1) + + +/***/ }), /* 1 */ -/***/ function(module, exports) { +/***/ (function(module, exports) { + - -/***/ } +/***/ }) /******/ ]); \ No newline at end of file diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js index 360f2551..30fd9525 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack2/sw.js @@ -519,8 +519,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -872,8 +872,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js index 25a9e7f6..ddc1f7cd 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack3/sw.js @@ -510,8 +510,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -863,8 +863,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js index 25a553ce..0ebdcca1 100644 --- a/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js +++ b/tests/legacy/fixtures/cachemaps-basic/__expected/webpack4/sw.js @@ -531,8 +531,8 @@ function WebpackServiceWorker(params, helpers) { } function shouldServeFromNetwork(response, urlString, cacheUrl) { - if (params.shouldServeFromNetwork) { - return params.shouldServeFromNetwork(response, urlString, cacheUrl); + if (helpers.shouldServeFromNetwork) { + return helpers.shouldServeFromNetwork(response, urlString, cacheUrl); } return response.ok; } @@ -884,8 +884,8 @@ function logGroup(title, assets) { console.groupEnd(); } - WebpackServiceWorker(__wpo, { +shouldServeFromNetwork: (void 0), loaders: {}, cacheMaps: [ { diff --git a/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js b/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js index e794483b..747579b0 100644 --- a/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js +++ b/tests/legacy/fixtures/sw-minify-auto/__expected/webpack2/sw.js @@ -1,3 +1,3 @@ var __wpo = {"assets":{"main":["./external.js"],"additional":[],"optional":[]},"externals":["./external.js"],"hashesMap":{},"strategy":"changed","responseStrategy":"cache-first","version":"da39a3ee5e6b4b0d3255bfef95601890afd80709","name":"webpack-offline","relativePaths":true}; -!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var t={};n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=1)}([function(e,n){},function(e,n,t){"use strict";function r(e,n){return caches.match(e,{cacheName:n}).then(function(t){return a(t)?t:c(t).then(function(t){return caches.open(n).then(function(n){return n.put(e,t)}).then(function(){return t})})}).catch(function(){})}function o(e,n){return e+(-1!==e.indexOf("?")?"&":"?")+"__uncache="+encodeURIComponent(n)}function i(e){return"navigate"===e.mode||e.headers.get("Upgrade-Insecure-Requests")||-1!==(e.headers.get("Accept")||"").indexOf("text/html")}function a(e){return!e||!e.redirected||!e.ok||"opaqueredirect"===e.type}function c(e){return a(e)?Promise.resolve(e):("body"in e?Promise.resolve(e.body):e.blob()).then(function(n){return new Response(n,{headers:e.headers,status:e.status})})}function s(e,n){console.groupCollapsed("[SW]:",e),n.forEach(function(e){console.log("Asset:",e)}),console.groupEnd()}if(function(){var e=ExtendableEvent.prototype.waitUntil,n=FetchEvent.prototype.respondWith,t=new WeakMap;ExtendableEvent.prototype.waitUntil=function(n){var r=this,o=t.get(r);return o?void o.push(Promise.resolve(n)):(o=[Promise.resolve(n)],t.set(r,o),e.call(r,Promise.resolve().then(function e(){var n=o.length;return Promise.all(o.map(function(e){return e.catch(function(){})})).then(function(){return o.length!=n?e():(t.delete(r),Promise.all(o))})})))},FetchEvent.prototype.respondWith=function(e){return this.waitUntil(e),n.call(this,e)}}(),void 0===u)var u=!1;!function(e,n){function t(){if(!k.additional.length)return Promise.resolve();u&&console.log("[SW]:","Caching additional");var e=void 0;return e="changed"===O?f("additional"):a("additional"),e.catch(function(e){console.error("[SW]:","Cache section `additional` failed to load")})}function a(n){var t=k[n];return caches.open(C).then(function(r){return P(r,t,{bust:e.version,request:E,failAll:"main"===n})}).then(function(){s("Cached assets: "+n,t)}).catch(function(e){throw console.error(e),e})}function f(n){return h().then(function(t){if(!t)return a(n);var r=t[0],o=t[1],i=t[2],c=i.hashmap,u=i.version;if(!i.hashmap||u===e.version)return a(n);var f=Object.keys(c).map(function(e){return c[e]}),l=o.map(function(e){var n=new URL(e.url);return n.search="",n.hash="",n.toString()}),h=k[n],d=[],p=h.filter(function(e){return-1===l.indexOf(e)||-1===f.indexOf(e)});Object.keys(b).forEach(function(e){var n=b[e];if(-1!==h.indexOf(n)&&-1===p.indexOf(n)&&-1===d.indexOf(n)){var t=c[e];t&&-1!==l.indexOf(t)?d.push([t,n]):p.push(n)}}),s("Changed assets: "+n,p),s("Moved assets: "+n,d);var v=Promise.all(d.map(function(e){return r.match(e[0]).then(function(n){return[e[1],n]})}));return caches.open(C).then(function(t){var r=v.then(function(e){return Promise.all(e.map(function(e){return t.put(e[0],e[1])}))});return Promise.all([r,P(t,p,{bust:e.version,request:E,failAll:"main"===n,deleteFirst:"main"!==n})])})})}function l(){return caches.keys().then(function(e){var n=e.map(function(e){if(0===e.indexOf(_)&&0!==e.indexOf(C))return console.log("[SW]:","Delete cache:",e),caches.delete(e)});return Promise.all(n)})}function h(){return caches.keys().then(function(e){for(var n=e.length,t=void 0;n--&&(t=e[n],0!==t.indexOf(_)););if(t){var r=void 0;return caches.open(t).then(function(e){return r=e,e.match(new URL(A,location).toString())}).then(function(e){if(e)return Promise.all([r,r.keys(),e.json()])})}})}function d(){return caches.open(C).then(function(n){var t=new Response(JSON.stringify({version:e.version,hashmap:b}));return n.put(new URL(A,location).toString(),t)})}function p(e,n,t){return g(e),r(t,C).then(function(r){return r?(u&&console.log("[SW]:","URL ["+t+"]("+n+") from cache"),r):fetch(e.request).then(function(r){return r.ok?(u&&console.log("[SW]:","URL ["+n+"] from network"),t===n&&function(){var t=r.clone(),o=caches.open(C).then(function(e){return e.put(n,t)}).then(function(){console.log("[SW]:","Cache asset: "+n)});e.waitUntil(o)}(),r):(u&&console.log("[SW]:","URL ["+n+"] wrong response: ["+r.status+"] "+r.type),r)})})}function v(n,t,r){return e.shouldServeFromNetwork?e.shouldServeFromNetwork(n,t,r):n.ok}function m(e,n,t){return x(e).then(function(e){if(v(e,n,t))return u&&console.log("[SW]:","URL ["+n+"] from network"),e;throw e}).catch(function(e){return u&&console.log("[SW]:","URL ["+n+"] from cache if possible"),r(t,C).then(function(n){if(n)return n;if(e instanceof Response)return e;throw e})})}function g(e){if(S&&"function"==typeof S.map&&e.preloadResponse&&"navigate"===e.request.mode){var n=S.map(new URL(e.request.url),e.request);n&&w(n,e)}}function w(e,n){var t=new URL(e,location),r=n.preloadResponse;N.set(r,{url:t,response:r});var o=function(){return N.has(r)},i=r.then(function(e){if(e&&o()){var n=e.clone();return caches.open(M).then(function(e){if(o())return e.put(t,n).then(function(){if(!o())return caches.open(M).then(function(e){return e.delete(t)})})})}});n.waitUntil(i)}function U(e){if(N){var n=void 0,t=void 0;return N.forEach(function(r,o){r.url.href===e.href&&(n=r.response,t=o)}),n?(N.delete(t),n):void 0}}function y(e){var n=new URL(e.request.url);if(self.registration.navigationPreload&&S&&S.test&&S.test(n,e.request)){var t=U(n),o=e.request;return t?(e.waitUntil(caches.open(M).then(function(e){return e.delete(o)})),t):r(o,M).then(function(n){return n&&e.waitUntil(caches.open(M).then(function(e){return e.delete(o)})),n||fetch(e.request)})}}function P(e,n,t){var r=t.bust,i=!1!==t.failAll,a=!0===t.deleteFirst,s=t.request||{credentials:"omit",mode:"cors"},u=Promise.resolve();return a&&(u=Promise.all(n.map(function(n){return e.delete(n).catch(function(){})}))),Promise.all(n.map(function(e){return r&&(e=o(e,r)),fetch(e,s).then(c).then(function(e){return e.ok?{response:e}:{error:!0}},function(){return{error:!0}})})).then(function(t){return i&&t.some(function(e){return e.error})?Promise.reject(new Error("Wrong response status")):(i||(t=t.filter(function(e){return!e.error})),u.then(function(){var r=t.map(function(t,r){var o=t.response;return e.put(n[r],o)});return Promise.all(r)}))})}function R(e){var n=e.url,t=new URL(n),r=void 0;r=i(e)?"navigate":t.origin===location.origin?"same-origin":"cross-origin";for(var o=0;o