Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

_default.mjs 7.3 KiB

vor 3 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. Copyright 2017 Google Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. import {NavigationRoute} from './NavigationRoute.mjs';
  14. import {RegExpRoute} from './RegExpRoute.mjs';
  15. import {Router} from './Router.mjs';
  16. import {Route} from './Route.mjs';
  17. import {WorkboxError} from 'workbox-core/_private/WorkboxError.mjs';
  18. import {assert} from 'workbox-core/_private/assert.mjs';
  19. import {cacheNames} from 'workbox-core/_private/cacheNames.mjs';
  20. import {logger} from 'workbox-core/_private/logger.mjs';
  21. import './_version.mjs';
  22. if (process.env.NODE_ENV !== 'production') {
  23. assert.isSwEnv('workbox-routing');
  24. }
  25. /**
  26. * @private
  27. */
  28. class DefaultRouter extends Router {
  29. /**
  30. * Easily register a RegExp, string, or function with a caching
  31. * strategy to the Router.
  32. *
  33. * This method will generate a Route for you if needed and
  34. * call [Router.registerRoute()]{@link
  35. * workbox.routing.Router#registerRoute}.
  36. *
  37. * @param {
  38. * RegExp|
  39. * string|
  40. * workbox.routing.Route~matchCallback|
  41. * workbox.routing.Route
  42. * } capture
  43. * If the capture param is a `Route`, all other arguments will be ignored.
  44. * @param {workbox.routing.Route~handlerCallback} handler A callback
  45. * function that returns a Promise resulting in a Response.
  46. * @param {string} [method='GET'] The HTTP method to match the Route
  47. * against.
  48. * @return {workbox.routing.Route} The generated `Route`(Useful for
  49. * unregistering).
  50. *
  51. * @alias workbox.routing.registerRoute
  52. */
  53. registerRoute(capture, handler, method = 'GET') {
  54. let route;
  55. if (typeof capture === 'string') {
  56. const captureUrl = new URL(capture, location);
  57. if (process.env.NODE_ENV !== 'production') {
  58. if (!(capture.startsWith('/') || capture.startsWith('http'))) {
  59. throw new WorkboxError('invalid-string', {
  60. moduleName: 'workbox-routing',
  61. className: 'DefaultRouter',
  62. funcName: 'registerRoute',
  63. paramName: 'capture',
  64. });
  65. }
  66. // We want to check if Express-style wildcards are in the pathname only.
  67. // TODO: Remove this log message in v4.
  68. const valueToCheck = capture.startsWith('http') ?
  69. captureUrl.pathname :
  70. capture;
  71. // See https://github.com/pillarjs/path-to-regexp#parameters
  72. const wildcards = '[*:?+]';
  73. if (valueToCheck.match(new RegExp(`${wildcards}`))) {
  74. logger.debug(
  75. `The '$capture' parameter contains an Express-style wildcard ` +
  76. `character (${wildcards}). Strings are now always interpreted as ` +
  77. `exact matches; use a RegExp for partial or wildcard matches.`
  78. );
  79. }
  80. }
  81. const matchCallback = ({url}) => {
  82. if (process.env.NODE_ENV !== 'production') {
  83. if ((url.pathname === captureUrl.pathname) &&
  84. (url.origin !== captureUrl.origin)) {
  85. logger.debug(
  86. `${capture} only partially matches the cross-origin URL ` +
  87. `${url}. This route will only handle cross-origin requests ` +
  88. `if they match the entire URL.`
  89. );
  90. }
  91. }
  92. return url.href === captureUrl.href;
  93. };
  94. route = new Route(matchCallback, handler, method);
  95. } else if (capture instanceof RegExp) {
  96. route = new RegExpRoute(capture, handler, method);
  97. } else if (typeof capture === 'function') {
  98. route = new Route(capture, handler, method);
  99. } else if (capture instanceof Route) {
  100. route = capture;
  101. } else {
  102. throw new WorkboxError('unsupported-route-type', {
  103. moduleName: 'workbox-routing',
  104. className: 'DefaultRouter',
  105. funcName: 'registerRoute',
  106. paramName: 'capture',
  107. });
  108. }
  109. super.registerRoute(route);
  110. return route;
  111. }
  112. /**
  113. * Register a route that will return a precached file for a navigation
  114. * request. This is useful for the
  115. * [application shell pattern]{@link https://developers.google.com/web/fundamentals/architecture/app-shell}.
  116. *
  117. * This method will generate a
  118. * [NavigationRoute]{@link workbox.routing.NavigationRoute}
  119. * and call
  120. * [Router.registerRoute()]{@link workbox.routing.Router#registerRoute}
  121. * .
  122. *
  123. * @param {string} cachedAssetUrl
  124. * @param {Object} [options]
  125. * @param {string} [options.cacheName] Cache name to store and retrieve
  126. * requests. Defaults to precache cache name provided by
  127. * [workbox-core.cacheNames]{@link workbox.core.cacheNames}.
  128. * @param {Array<RegExp>} [options.blacklist=[]] If any of these patterns
  129. * match, the route will not handle the request (even if a whitelist entry
  130. * matches).
  131. * @param {Array<RegExp>} [options.whitelist=[/./]] If any of these patterns
  132. * match the URL's pathname and search parameter, the route will handle the
  133. * request (assuming the blacklist doesn't match).
  134. * @return {workbox.routing.NavigationRoute} Returns the generated
  135. * Route.
  136. *
  137. * @alias workbox.routing.registerNavigationRoute
  138. */
  139. registerNavigationRoute(cachedAssetUrl, options = {}) {
  140. if (process.env.NODE_ENV !== 'production') {
  141. assert.isType(cachedAssetUrl, 'string', {
  142. moduleName: 'workbox-routing',
  143. className: '[default export]',
  144. funcName: 'registerNavigationRoute',
  145. paramName: 'cachedAssetUrl',
  146. });
  147. }
  148. const cacheName = cacheNames.getPrecacheName(options.cacheName);
  149. const handler = () => caches.match(cachedAssetUrl, {cacheName})
  150. .then((response) => {
  151. if (response) {
  152. return response;
  153. }
  154. // This shouldn't normally happen, but there are edge cases:
  155. // https://github.com/GoogleChrome/workbox/issues/1441
  156. throw new Error(`The cache ${cacheName} did not have an entry for ` +
  157. `${cachedAssetUrl}.`);
  158. }).catch((error) => {
  159. // If there's either a cache miss, or the caches.match() call threw
  160. // an exception, then attempt to fulfill the navigation request with
  161. // a response from the network rather than leaving the user with a
  162. // failed navigation.
  163. if (process.env.NODE_ENV !== 'production') {
  164. logger.debug(`Unable to respond to navigation request with cached ` +
  165. `response: ${error.message}. Falling back to network.`);
  166. }
  167. // This might still fail if the browser is offline...
  168. return fetch(cachedAssetUrl);
  169. });
  170. const route = new NavigationRoute(handler, {
  171. whitelist: options.whitelist,
  172. blacklist: options.blacklist,
  173. });
  174. super.registerRoute(route);
  175. return route;
  176. }
  177. }
  178. const router = new DefaultRouter();
  179. // By default, register a fetch event listener that will respond to a request
  180. // only if there's a matching route.
  181. self.addEventListener('fetch', (event) => {
  182. const responsePromise = router.handleRequest(event);
  183. if (responsePromise) {
  184. event.respondWith(responsePromise);
  185. }
  186. });
  187. export default router;