workbox-window.dev.umd.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = global || self, factory(global.workbox = {}));
  5. }(this, function (exports) { 'use strict';
  6. try {
  7. self['workbox:window:4.3.1'] && _();
  8. } catch (e) {} // eslint-disable-line
  9. /*
  10. Copyright 2019 Google LLC
  11. Use of this source code is governed by an MIT-style
  12. license that can be found in the LICENSE file or at
  13. https://opensource.org/licenses/MIT.
  14. */
  15. /**
  16. * Sends a data object to a service worker via `postMessage` and resolves with
  17. * a response (if any).
  18. *
  19. * A response can be set in a message handler in the service worker by
  20. * calling `event.ports[0].postMessage(...)`, which will resolve the promise
  21. * returned by `messageSW()`. If no response is set, the promise will not
  22. * resolve.
  23. *
  24. * @param {ServiceWorker} sw The service worker to send the message to.
  25. * @param {Object} data An object to send to the service worker.
  26. * @return {Promise<Object|undefined>}
  27. *
  28. * @memberof module:workbox-window
  29. */
  30. var messageSW = function messageSW(sw, data) {
  31. return new Promise(function (resolve) {
  32. var messageChannel = new MessageChannel();
  33. messageChannel.port1.onmessage = function (evt) {
  34. return resolve(evt.data);
  35. };
  36. sw.postMessage(data, [messageChannel.port2]);
  37. });
  38. };
  39. function _defineProperties(target, props) {
  40. for (var i = 0; i < props.length; i++) {
  41. var descriptor = props[i];
  42. descriptor.enumerable = descriptor.enumerable || false;
  43. descriptor.configurable = true;
  44. if ("value" in descriptor) descriptor.writable = true;
  45. Object.defineProperty(target, descriptor.key, descriptor);
  46. }
  47. }
  48. function _createClass(Constructor, protoProps, staticProps) {
  49. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  50. if (staticProps) _defineProperties(Constructor, staticProps);
  51. return Constructor;
  52. }
  53. function _inheritsLoose(subClass, superClass) {
  54. subClass.prototype = Object.create(superClass.prototype);
  55. subClass.prototype.constructor = subClass;
  56. subClass.__proto__ = superClass;
  57. }
  58. function _assertThisInitialized(self) {
  59. if (self === void 0) {
  60. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  61. }
  62. return self;
  63. }
  64. try {
  65. self['workbox:core:4.3.1'] && _();
  66. } catch (e) {} // eslint-disable-line
  67. /*
  68. Copyright 2018 Google LLC
  69. Use of this source code is governed by an MIT-style
  70. license that can be found in the LICENSE file or at
  71. https://opensource.org/licenses/MIT.
  72. */
  73. /**
  74. * The Deferred class composes Promises in a way that allows for them to be
  75. * resolved or rejected from outside the constructor. In most cases promises
  76. * should be used directly, but Deferreds can be necessary when the logic to
  77. * resolve a promise must be separate.
  78. *
  79. * @private
  80. */
  81. var Deferred =
  82. /**
  83. * Creates a promise and exposes its resolve and reject functions as methods.
  84. */
  85. function Deferred() {
  86. var _this = this;
  87. this.promise = new Promise(function (resolve, reject) {
  88. _this.resolve = resolve;
  89. _this.reject = reject;
  90. });
  91. };
  92. /*
  93. Copyright 2019 Google LLC
  94. Use of this source code is governed by an MIT-style
  95. license that can be found in the LICENSE file or at
  96. https://opensource.org/licenses/MIT.
  97. */
  98. var logger = function () {
  99. var inGroup = false;
  100. var methodToColorMap = {
  101. debug: "#7f8c8d",
  102. // Gray
  103. log: "#2ecc71",
  104. // Green
  105. warn: "#f39c12",
  106. // Yellow
  107. error: "#c0392b",
  108. // Red
  109. groupCollapsed: "#3498db",
  110. // Blue
  111. groupEnd: null // No colored prefix on groupEnd
  112. };
  113. var print = function print(method, args) {
  114. var _console2;
  115. if (method === 'groupCollapsed') {
  116. // Safari doesn't print all console.groupCollapsed() arguments:
  117. // https://bugs.webkit.org/show_bug.cgi?id=182754
  118. if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
  119. var _console;
  120. (_console = console)[method].apply(_console, args);
  121. return;
  122. }
  123. }
  124. var styles = ["background: " + methodToColorMap[method], "border-radius: 0.5em", "color: white", "font-weight: bold", "padding: 2px 0.5em"]; // When in a group, the workbox prefix is not displayed.
  125. var logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];
  126. (_console2 = console)[method].apply(_console2, logPrefix.concat(args));
  127. if (method === 'groupCollapsed') {
  128. inGroup = true;
  129. }
  130. if (method === 'groupEnd') {
  131. inGroup = false;
  132. }
  133. };
  134. var api = {};
  135. var _arr = Object.keys(methodToColorMap);
  136. var _loop = function _loop() {
  137. var method = _arr[_i];
  138. api[method] = function () {
  139. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  140. args[_key] = arguments[_key];
  141. }
  142. print(method, args);
  143. };
  144. };
  145. for (var _i = 0; _i < _arr.length; _i++) {
  146. _loop();
  147. }
  148. return api;
  149. }();
  150. /*
  151. Copyright 2019 Google LLC
  152. Use of this source code is governed by an MIT-style
  153. license that can be found in the LICENSE file or at
  154. https://opensource.org/licenses/MIT.
  155. */
  156. /**
  157. * A minimal `EventTarget` shim.
  158. * This is necessary because not all browsers support constructable
  159. * `EventTarget`, so using a real `EventTarget` will error.
  160. * @private
  161. */
  162. var EventTargetShim =
  163. /*#__PURE__*/
  164. function () {
  165. /**
  166. * Creates an event listener registry
  167. *
  168. * @private
  169. */
  170. function EventTargetShim() {
  171. // A registry of event types to listeners.
  172. this._eventListenerRegistry = {};
  173. }
  174. /**
  175. * @param {string} type
  176. * @param {Function} listener
  177. * @private
  178. */
  179. var _proto = EventTargetShim.prototype;
  180. _proto.addEventListener = function addEventListener(type, listener) {
  181. this._getEventListenersByType(type).add(listener);
  182. };
  183. /**
  184. * @param {string} type
  185. * @param {Function} listener
  186. * @private
  187. */
  188. _proto.removeEventListener = function removeEventListener(type, listener) {
  189. this._getEventListenersByType(type).delete(listener);
  190. };
  191. /**
  192. * @param {Event} event
  193. * @private
  194. */
  195. _proto.dispatchEvent = function dispatchEvent(event) {
  196. event.target = this;
  197. this._getEventListenersByType(event.type).forEach(function (listener) {
  198. return listener(event);
  199. });
  200. };
  201. /**
  202. * Returns a Set of listeners associated with the passed event type.
  203. * If no handlers have been registered, an empty Set is returned.
  204. *
  205. * @param {string} type The event type.
  206. * @return {Set} An array of handler functions.
  207. * @private
  208. */
  209. _proto._getEventListenersByType = function _getEventListenersByType(type) {
  210. return this._eventListenerRegistry[type] = this._eventListenerRegistry[type] || new Set();
  211. };
  212. return EventTargetShim;
  213. }();
  214. /*
  215. Copyright 2019 Google LLC
  216. Use of this source code is governed by an MIT-style
  217. license that can be found in the LICENSE file or at
  218. https://opensource.org/licenses/MIT.
  219. */
  220. /**
  221. * Returns true if two URLs have the same `.href` property. The URLS can be
  222. * relative, and if they are the current location href is used to resolve URLs.
  223. *
  224. * @private
  225. * @param {string} url1
  226. * @param {string} url2
  227. * @return {boolean}
  228. */
  229. var urlsMatch = function urlsMatch(url1, url2) {
  230. return new URL(url1, location).href === new URL(url2, location).href;
  231. };
  232. /*
  233. Copyright 2019 Google LLC
  234. Use of this source code is governed by an MIT-style
  235. license that can be found in the LICENSE file or at
  236. https://opensource.org/licenses/MIT.
  237. */
  238. /**
  239. * A minimal `Event` subclass shim.
  240. * This doesn't *actually* subclass `Event` because not all browsers support
  241. * constructable `EventTarget`, and using a real `Event` will error.
  242. * @private
  243. */
  244. var WorkboxEvent =
  245. /**
  246. * @param {string} type
  247. * @param {Object} props
  248. */
  249. function WorkboxEvent(type, props) {
  250. Object.assign(this, props, {
  251. type: type
  252. });
  253. };
  254. function _catch(body, recover) {
  255. try {
  256. var result = body();
  257. } catch (e) {
  258. return recover(e);
  259. }
  260. if (result && result.then) {
  261. return result.then(void 0, recover);
  262. }
  263. return result;
  264. }
  265. function _async(f) {
  266. return function () {
  267. for (var args = [], i = 0; i < arguments.length; i++) {
  268. args[i] = arguments[i];
  269. }
  270. try {
  271. return Promise.resolve(f.apply(this, args));
  272. } catch (e) {
  273. return Promise.reject(e);
  274. }
  275. };
  276. }
  277. function _invoke(body, then) {
  278. var result = body();
  279. if (result && result.then) {
  280. return result.then(then);
  281. }
  282. return then(result);
  283. }
  284. function _await(value, then, direct) {
  285. if (direct) {
  286. return then ? then(value) : value;
  287. }
  288. if (!value || !value.then) {
  289. value = Promise.resolve(value);
  290. }
  291. return then ? value.then(then) : value;
  292. }
  293. function _awaitIgnored(value, direct) {
  294. if (!direct) {
  295. return value && value.then ? value.then(_empty) : Promise.resolve();
  296. }
  297. }
  298. function _empty() {}
  299. // `skipWaiting()` wasn't called. This 200 amount wasn't scientifically
  300. // chosen, but it seems to avoid false positives in my testing.
  301. var WAITING_TIMEOUT_DURATION = 200; // The amount of time after a registration that we can reasonably conclude
  302. // that the registration didn't trigger an update.
  303. var REGISTRATION_TIMEOUT_DURATION = 60000;
  304. /**
  305. * A class to aid in handling service worker registration, updates, and
  306. * reacting to service worker lifecycle events.
  307. *
  308. * @fires [message]{@link module:workbox-window.Workbox#message}
  309. * @fires [installed]{@link module:workbox-window.Workbox#installed}
  310. * @fires [waiting]{@link module:workbox-window.Workbox#waiting}
  311. * @fires [controlling]{@link module:workbox-window.Workbox#controlling}
  312. * @fires [activated]{@link module:workbox-window.Workbox#activated}
  313. * @fires [redundant]{@link module:workbox-window.Workbox#redundant}
  314. * @fires [externalinstalled]{@link module:workbox-window.Workbox#externalinstalled}
  315. * @fires [externalwaiting]{@link module:workbox-window.Workbox#externalwaiting}
  316. * @fires [externalactivated]{@link module:workbox-window.Workbox#externalactivated}
  317. *
  318. * @memberof module:workbox-window
  319. */
  320. var Workbox =
  321. /*#__PURE__*/
  322. function (_EventTargetShim) {
  323. _inheritsLoose(Workbox, _EventTargetShim);
  324. /**
  325. * Creates a new Workbox instance with a script URL and service worker
  326. * options. The script URL and options are the same as those used when
  327. * calling `navigator.serviceWorker.register(scriptURL, options)`. See:
  328. * https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register
  329. *
  330. * @param {string} scriptURL The service worker script associated with this
  331. * instance.
  332. * @param {Object} [registerOptions] The service worker options associated
  333. * with this instance.
  334. */
  335. function Workbox(scriptURL, registerOptions) {
  336. var _this;
  337. if (registerOptions === void 0) {
  338. registerOptions = {};
  339. }
  340. _this = _EventTargetShim.call(this) || this;
  341. _this._scriptURL = scriptURL;
  342. _this._registerOptions = registerOptions;
  343. _this._updateFoundCount = 0; // Deferreds we can resolve later.
  344. _this._swDeferred = new Deferred();
  345. _this._activeDeferred = new Deferred();
  346. _this._controllingDeferred = new Deferred(); // Bind event handler callbacks.
  347. _this._onMessage = _this._onMessage.bind(_assertThisInitialized(_assertThisInitialized(_this)));
  348. _this._onStateChange = _this._onStateChange.bind(_assertThisInitialized(_assertThisInitialized(_this)));
  349. _this._onUpdateFound = _this._onUpdateFound.bind(_assertThisInitialized(_assertThisInitialized(_this)));
  350. _this._onControllerChange = _this._onControllerChange.bind(_assertThisInitialized(_assertThisInitialized(_this)));
  351. return _this;
  352. }
  353. /**
  354. * Registers a service worker for this instances script URL and service
  355. * worker options. By default this method delays registration until after
  356. * the window has loaded.
  357. *
  358. * @param {Object} [options]
  359. * @param {Function} [options.immediate=false] Setting this to true will
  360. * register the service worker immediately, even if the window has
  361. * not loaded (not recommended).
  362. */
  363. var _proto = Workbox.prototype;
  364. _proto.register = _async(function (_temp) {
  365. var _this2 = this;
  366. var _ref = _temp === void 0 ? {} : _temp,
  367. _ref$immediate = _ref.immediate,
  368. immediate = _ref$immediate === void 0 ? false : _ref$immediate;
  369. {
  370. if (_this2._registrationTime) {
  371. logger.error('Cannot re-register a Workbox instance after it has ' + 'been registered. Create a new instance instead.');
  372. return;
  373. }
  374. }
  375. return _invoke(function () {
  376. if (!immediate && document.readyState !== 'complete') {
  377. return _awaitIgnored(new Promise(function (res) {
  378. return addEventListener('load', res);
  379. }));
  380. }
  381. }, function () {
  382. // Set this flag to true if any service worker was controlling the page
  383. // at registration time.
  384. _this2._isUpdate = Boolean(navigator.serviceWorker.controller); // Before registering, attempt to determine if a SW is already controlling
  385. // the page, and if that SW script (and version, if specified) matches this
  386. // instance's script.
  387. _this2._compatibleControllingSW = _this2._getControllingSWIfCompatible();
  388. return _await(_this2._registerScript(), function (_this2$_registerScrip) {
  389. _this2._registration = _this2$_registerScrip;
  390. // If we have a compatible controller, store the controller as the "own"
  391. // SW, resolve active/controlling deferreds and add necessary listeners.
  392. if (_this2._compatibleControllingSW) {
  393. _this2._sw = _this2._compatibleControllingSW;
  394. _this2._activeDeferred.resolve(_this2._compatibleControllingSW);
  395. _this2._controllingDeferred.resolve(_this2._compatibleControllingSW);
  396. _this2._reportWindowReady(_this2._compatibleControllingSW);
  397. _this2._compatibleControllingSW.addEventListener('statechange', _this2._onStateChange, {
  398. once: true
  399. });
  400. } // If there's a waiting service worker with a matching URL before the
  401. // `updatefound` event fires, it likely means that this site is open
  402. // in another tab, or the user refreshed the page (and thus the prevoius
  403. // page wasn't fully unloaded before this page started loading).
  404. // https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#waiting
  405. var waitingSW = _this2._registration.waiting;
  406. if (waitingSW && urlsMatch(waitingSW.scriptURL, _this2._scriptURL)) {
  407. // Store the waiting SW as the "own" Sw, even if it means overwriting
  408. // a compatible controller.
  409. _this2._sw = waitingSW; // Run this in the next microtask, so any code that adds an event
  410. // listener after awaiting `register()` will get this event.
  411. Promise.resolve().then(function () {
  412. _this2.dispatchEvent(new WorkboxEvent('waiting', {
  413. sw: waitingSW,
  414. wasWaitingBeforeRegister: true
  415. }));
  416. {
  417. logger.warn('A service worker was already waiting to activate ' + 'before this script was registered...');
  418. }
  419. });
  420. } // If an "own" SW is already set, resolve the deferred.
  421. if (_this2._sw) {
  422. _this2._swDeferred.resolve(_this2._sw);
  423. }
  424. {
  425. logger.log('Successfully registered service worker.', _this2._scriptURL);
  426. if (navigator.serviceWorker.controller) {
  427. if (_this2._compatibleControllingSW) {
  428. logger.debug('A service worker with the same script URL ' + 'is already controlling this page.');
  429. } else {
  430. logger.debug('A service worker with a different script URL is ' + 'currently controlling the page. The browser is now fetching ' + 'the new script now...');
  431. }
  432. }
  433. var currentPageIsOutOfScope = function currentPageIsOutOfScope() {
  434. var scopeURL = new URL(_this2._registerOptions.scope || _this2._scriptURL, document.baseURI);
  435. var scopeURLBasePath = new URL('./', scopeURL.href).pathname;
  436. return !location.pathname.startsWith(scopeURLBasePath);
  437. };
  438. if (currentPageIsOutOfScope()) {
  439. logger.warn('The current page is not in scope for the registered ' + 'service worker. Was this a mistake?');
  440. }
  441. }
  442. _this2._registration.addEventListener('updatefound', _this2._onUpdateFound);
  443. navigator.serviceWorker.addEventListener('controllerchange', _this2._onControllerChange, {
  444. once: true
  445. }); // Add message listeners.
  446. if ('BroadcastChannel' in self) {
  447. _this2._broadcastChannel = new BroadcastChannel('workbox');
  448. _this2._broadcastChannel.addEventListener('message', _this2._onMessage);
  449. }
  450. navigator.serviceWorker.addEventListener('message', _this2._onMessage);
  451. return _this2._registration;
  452. });
  453. });
  454. });
  455. /**
  456. * Resolves to the service worker registered by this instance as soon as it
  457. * is active. If a service worker was already controlling at registration
  458. * time then it will resolve to that if the script URLs (and optionally
  459. * script versions) match, otherwise it will wait until an update is found
  460. * and activates.
  461. *
  462. * @return {Promise<ServiceWorker>}
  463. */
  464. /**
  465. * Resolves with a reference to a service worker that matches the script URL
  466. * of this instance, as soon as it's available.
  467. *
  468. * If, at registration time, there's already an active or waiting service
  469. * worker with a matching script URL, it will be used (with the waiting
  470. * service worker taking precedence over the active service worker if both
  471. * match, since the waiting service worker would have been registered more
  472. * recently).
  473. * If there's no matching active or waiting service worker at registration
  474. * time then the promise will not resolve until an update is found and starts
  475. * installing, at which point the installing service worker is used.
  476. *
  477. * @return {Promise<ServiceWorker>}
  478. */
  479. _proto.getSW = _async(function () {
  480. var _this3 = this;
  481. // If `this._sw` is set, resolve with that as we want `getSW()` to
  482. // return the correct (new) service worker if an update is found.
  483. return _this3._sw || _this3._swDeferred.promise;
  484. });
  485. /**
  486. * Sends the passed data object to the service worker registered by this
  487. * instance (via [`getSW()`]{@link module:workbox-window.Workbox#getSW}) and resolves
  488. * with a response (if any).
  489. *
  490. * A response can be set in a message handler in the service worker by
  491. * calling `event.ports[0].postMessage(...)`, which will resolve the promise
  492. * returned by `messageSW()`. If no response is set, the promise will never
  493. * resolve.
  494. *
  495. * @param {Object} data An object to send to the service worker
  496. * @return {Promise<Object>}
  497. */
  498. _proto.messageSW = _async(function (data) {
  499. var _this4 = this;
  500. return _await(_this4.getSW(), function (sw) {
  501. return messageSW(sw, data);
  502. });
  503. });
  504. /**
  505. * Checks for a service worker already controlling the page and returns
  506. * it if its script URL matchs.
  507. *
  508. * @private
  509. * @return {ServiceWorker|undefined}
  510. */
  511. _proto._getControllingSWIfCompatible = function _getControllingSWIfCompatible() {
  512. var controller = navigator.serviceWorker.controller;
  513. if (controller && urlsMatch(controller.scriptURL, this._scriptURL)) {
  514. return controller;
  515. }
  516. };
  517. /**
  518. * Registers a service worker for this instances script URL and register
  519. * options and tracks the time registration was complete.
  520. *
  521. * @private
  522. */
  523. _proto._registerScript = _async(function () {
  524. var _this5 = this;
  525. return _catch(function () {
  526. return _await(navigator.serviceWorker.register(_this5._scriptURL, _this5._registerOptions), function (reg) {
  527. // Keep track of when registration happened, so it can be used in the
  528. // `this._onUpdateFound` heuristic. Also use the presence of this
  529. // property as a way to see if `.register()` has been called.
  530. _this5._registrationTime = performance.now();
  531. return reg;
  532. });
  533. }, function (error) {
  534. {
  535. logger.error(error);
  536. } // Re-throw the error.
  537. throw error;
  538. });
  539. });
  540. /**
  541. * Sends a message to the passed service worker that the window is ready.
  542. *
  543. * @param {ServiceWorker} sw
  544. * @private
  545. */
  546. _proto._reportWindowReady = function _reportWindowReady(sw) {
  547. messageSW(sw, {
  548. type: 'WINDOW_READY',
  549. meta: 'workbox-window'
  550. });
  551. };
  552. /**
  553. * @private
  554. */
  555. _proto._onUpdateFound = function _onUpdateFound() {
  556. var installingSW = this._registration.installing; // If the script URL passed to `navigator.serviceWorker.register()` is
  557. // different from the current controlling SW's script URL, we know any
  558. // successful registration calls will trigger an `updatefound` event.
  559. // But if the registered script URL is the same as the current controlling
  560. // SW's script URL, we'll only get an `updatefound` event if the file
  561. // changed since it was last registered. This can be a problem if the user
  562. // opens up the same page in a different tab, and that page registers
  563. // a SW that triggers an update. It's a problem because this page has no
  564. // good way of knowing whether the `updatefound` event came from the SW
  565. // script it registered or from a registration attempt made by a newer
  566. // version of the page running in another tab.
  567. // To minimize the possibility of a false positive, we use the logic here:
  568. var updateLikelyTriggeredExternally = // Since we enforce only calling `register()` once, and since we don't
  569. // add the `updatefound` event listener until the `register()` call, if
  570. // `_updateFoundCount` is > 0 then it means this method has already
  571. // been called, thus this SW must be external
  572. this._updateFoundCount > 0 || // If the script URL of the installing SW is different from this
  573. // instance's script URL, we know it's definitely not from our
  574. // registration.
  575. !urlsMatch(installingSW.scriptURL, this._scriptURL) || // If all of the above are false, then we use a time-based heuristic:
  576. // Any `updatefound` event that occurs long after our registration is
  577. // assumed to be external.
  578. performance.now() > this._registrationTime + REGISTRATION_TIMEOUT_DURATION ? // If any of the above are not true, we assume the update was
  579. // triggered by this instance.
  580. true : false;
  581. if (updateLikelyTriggeredExternally) {
  582. this._externalSW = installingSW;
  583. this._registration.removeEventListener('updatefound', this._onUpdateFound);
  584. } else {
  585. // If the update was not triggered externally we know the installing
  586. // SW is the one we registered, so we set it.
  587. this._sw = installingSW;
  588. this._swDeferred.resolve(installingSW); // The `installing` state isn't something we have a dedicated
  589. // callback for, but we do log messages for it in development.
  590. {
  591. if (navigator.serviceWorker.controller) {
  592. logger.log('Updated service worker found. Installing now...');
  593. } else {
  594. logger.log('Service worker is installing...');
  595. }
  596. }
  597. } // Increment the `updatefound` count, so future invocations of this
  598. // method can be sure they were triggered externally.
  599. ++this._updateFoundCount; // Add a `statechange` listener regardless of whether this update was
  600. // triggered externally, since we have callbacks for both.
  601. installingSW.addEventListener('statechange', this._onStateChange);
  602. };
  603. /**
  604. * @private
  605. * @param {Event} originalEvent
  606. */
  607. _proto._onStateChange = function _onStateChange(originalEvent) {
  608. var _this6 = this;
  609. var sw = originalEvent.target;
  610. var state = sw.state;
  611. var isExternal = sw === this._externalSW;
  612. var eventPrefix = isExternal ? 'external' : '';
  613. var eventProps = {
  614. sw: sw,
  615. originalEvent: originalEvent
  616. };
  617. if (!isExternal && this._isUpdate) {
  618. eventProps.isUpdate = true;
  619. }
  620. this.dispatchEvent(new WorkboxEvent(eventPrefix + state, eventProps));
  621. if (state === 'installed') {
  622. // This timeout is used to ignore cases where the service worker calls
  623. // `skipWaiting()` in the install event, thus moving it directly in the
  624. // activating state. (Since all service workers *must* go through the
  625. // waiting phase, the only way to detect `skipWaiting()` called in the
  626. // install event is to observe that the time spent in the waiting phase
  627. // is very short.)
  628. // NOTE: we don't need separate timeouts for the own and external SWs
  629. // since they can't go through these phases at the same time.
  630. this._waitingTimeout = setTimeout(function () {
  631. // Ensure the SW is still waiting (it may now be redundant).
  632. if (state === 'installed' && _this6._registration.waiting === sw) {
  633. _this6.dispatchEvent(new WorkboxEvent(eventPrefix + 'waiting', eventProps));
  634. {
  635. if (isExternal) {
  636. logger.warn('An external service worker has installed but is ' + 'waiting for this client to close before activating...');
  637. } else {
  638. logger.warn('The service worker has installed but is waiting ' + 'for existing clients to close before activating...');
  639. }
  640. }
  641. }
  642. }, WAITING_TIMEOUT_DURATION);
  643. } else if (state === 'activating') {
  644. clearTimeout(this._waitingTimeout);
  645. if (!isExternal) {
  646. this._activeDeferred.resolve(sw);
  647. }
  648. }
  649. {
  650. switch (state) {
  651. case 'installed':
  652. if (isExternal) {
  653. logger.warn('An external service worker has installed. ' + 'You may want to suggest users reload this page.');
  654. } else {
  655. logger.log('Registered service worker installed.');
  656. }
  657. break;
  658. case 'activated':
  659. if (isExternal) {
  660. logger.warn('An external service worker has activated.');
  661. } else {
  662. logger.log('Registered service worker activated.');
  663. if (sw !== navigator.serviceWorker.controller) {
  664. logger.warn('The registered service worker is active but ' + 'not yet controlling the page. Reload or run ' + '`clients.claim()` in the service worker.');
  665. }
  666. }
  667. break;
  668. case 'redundant':
  669. if (sw === this._compatibleControllingSW) {
  670. logger.log('Previously controlling service worker now redundant!');
  671. } else if (!isExternal) {
  672. logger.log('Registered service worker now redundant!');
  673. }
  674. break;
  675. }
  676. }
  677. };
  678. /**
  679. * @private
  680. * @param {Event} originalEvent
  681. */
  682. _proto._onControllerChange = function _onControllerChange(originalEvent) {
  683. var sw = this._sw;
  684. if (sw === navigator.serviceWorker.controller) {
  685. this.dispatchEvent(new WorkboxEvent('controlling', {
  686. sw: sw,
  687. originalEvent: originalEvent
  688. }));
  689. {
  690. logger.log('Registered service worker now controlling this page.');
  691. }
  692. this._controllingDeferred.resolve(sw);
  693. }
  694. };
  695. /**
  696. * @private
  697. * @param {Event} originalEvent
  698. */
  699. _proto._onMessage = function _onMessage(originalEvent) {
  700. var data = originalEvent.data;
  701. this.dispatchEvent(new WorkboxEvent('message', {
  702. data: data,
  703. originalEvent: originalEvent
  704. }));
  705. };
  706. _createClass(Workbox, [{
  707. key: "active",
  708. get: function get() {
  709. return this._activeDeferred.promise;
  710. }
  711. /**
  712. * Resolves to the service worker registered by this instance as soon as it
  713. * is controlling the page. If a service worker was already controlling at
  714. * registration time then it will resolve to that if the script URLs (and
  715. * optionally script versions) match, otherwise it will wait until an update
  716. * is found and starts controlling the page.
  717. * Note: the first time a service worker is installed it will active but
  718. * not start controlling the page unless `clients.claim()` is called in the
  719. * service worker.
  720. *
  721. * @return {Promise<ServiceWorker>}
  722. */
  723. }, {
  724. key: "controlling",
  725. get: function get() {
  726. return this._controllingDeferred.promise;
  727. }
  728. }]);
  729. return Workbox;
  730. }(EventTargetShim); // The jsdoc comments below outline the events this instance may dispatch:
  731. /*
  732. Copyright 2019 Google LLC
  733. Use of this source code is governed by an MIT-style
  734. license that can be found in the LICENSE file or at
  735. https://opensource.org/licenses/MIT.
  736. */
  737. exports.Workbox = Workbox;
  738. exports.messageSW = messageSW;
  739. Object.defineProperty(exports, '__esModule', { value: true });
  740. }));
  741. //# sourceMappingURL=workbox-window.dev.umd.js.map