• 离线模式
    • 创建 serviceWorker
    • 注册
    • 体验一下

    离线模式

    Progressive Web Apps(PWA) 是一项融合 Web 和 Native 应用各项优点的解决方案。我们可以利用其支持离线功能的特点,让我们的网站可以在信号差或者离线状态下正常运行。
    要使用它也非常容易。

    创建 serviceWorker

    这里已经整理好了一份代码,你只需要在网站根目录下创建一个 sw.js 文件,并粘贴下面的代码。

    sw.js

    1. /* ===========================================================
    2. * docsify sw.js
    3. * ===========================================================
    4. * Copyright 2016 @huxpro
    5. * Licensed under Apache 2.0
    6. * Register service worker.
    7. * ========================================================== */
    8. const RUNTIME = 'docsify'
    9. const HOSTNAME_WHITELIST = [
    10. self.location.hostname,
    11. 'fonts.gstatic.com',
    12. 'fonts.googleapis.com',
    13. 'unpkg.com'
    14. ]
    15. // The Util Function to hack URLs of intercepted requests
    16. const getFixedUrl = (req) => {
    17. var now = Date.now()
    18. var url = new URL(req.url)
    19. // 1. fixed http URL
    20. // Just keep syncing with location.protocol
    21. // fetch(httpURL) belongs to active mixed content.
    22. // And fetch(httpRequest) is not supported yet.
    23. url.protocol = self.location.protocol
    24. // 2. add query for caching-busting.
    25. // Github Pages served with Cache-Control: max-age=600
    26. // max-age on mutable content is error-prone, with SW life of bugs can even extend.
    27. // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
    28. // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
    29. if (url.hostname === self.location.hostname) {
    30. url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
    31. }
    32. return url.href
    33. }
    34. /**
    35. * @Lifecycle Activate
    36. * New one activated when old isnt being used.
    37. *
    38. * waitUntil(): activating ====> activated
    39. */
    40. self.addEventListener('activate', event => {
    41. event.waitUntil(self.clients.claim())
    42. })
    43. /**
    44. * @Functional Fetch
    45. * All network requests are being intercepted here.
    46. *
    47. * void respondWith(Promise<Response> r)
    48. */
    49. self.addEventListener('fetch', event => {
    50. // Skip some of cross-origin requests, like those for Google Analytics.
    51. if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
    52. // Stale-while-revalidate
    53. // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
    54. // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
    55. const cached = caches.match(event.request)
    56. const fixedUrl = getFixedUrl(event.request)
    57. const fetched = fetch(fixedUrl, { cache: 'no-store' })
    58. const fetchedCopy = fetched.then(resp => resp.clone())
    59. // Call respondWith() with whatever we get first.
    60. // If the fetch fails (e.g disconnected), wait for the cache.
    61. // If there’s nothing in cache, wait for the fetch.
    62. // If neither yields a response, return offline pages.
    63. event.respondWith(
    64. Promise.race([fetched.catch(_ => cached), cached])
    65. .then(resp => resp || fetched)
    66. .catch(_ => { /* eat any errors */ })
    67. )
    68. // Update the cache with the version we fetched (only for ok status)
    69. event.waitUntil(
    70. Promise.all([fetchedCopy, caches.open(RUNTIME)])
    71. .then(([response, cache]) => response.ok && cache.put(event.request, response))
    72. .catch(_ => { /* eat any errors */ })
    73. )
    74. }
    75. })

    注册

    现在,到 index.html 里注册它。这个功能只能工作在一些现代浏览器上,所以我们需要加个判断。

    index.html

    1. <script>
    2. if (typeof navigator.serviceWorker !== 'undefined') {
    3. navigator.serviceWorker.register('sw.js')
    4. }
    5. </script>

    体验一下

    发布你的网站,并开始享受离线模式的魔力吧!:ghost: 当然你现在看到的 docsify 的文档网站已经支持离线模式了,你可以关掉 Wi-Fi 体验一下。