如何使用 Service Worker 讓 Jekyll 博客離線工作

已發表: 2017-01-26

Short Bytes:你知道嗎,隨著 Service Worker 的出現,人們可以開始讓網站離線工作! 此類 Web 應用程序稱為 PWA(漸進式 Web 應用程序)。 在這個方法中,我將幫助你使用 service worker 來使基於 Jekyll 的博客/網站離線工作以及一些很酷的東西。

(注意文章中的代碼片段取自我博客的代碼庫。如果需要,可以參考。如果您是 Jekyll 新手,可以閱讀 CSS Tricks 3 系列文章。)

背景

之前有一個基於 yuk YAML 文件的 App Cache,它本質上是非常硬編碼的,不能用於動態緩存資產和網頁。 輸入,服務人員。 基於簡單純事件的 Javascript API 進行動態服務工作者緩存以存儲資產,以便在沒有網絡時可以使用它們來服務網頁。

服務人員於 2014 年登陸 Chrome Canary,但其規範仍在修改/添加和設計中。 2015 年和 2016 年,谷歌的 Chrome 團隊在瀏覽器中大力宣傳這項新技術。 只有 Apple 沒有在他們的設備上支持這一點(即使在撰寫本文時)(出於未知原因)[他們也沒有積極參與任何關於 service worker 的規範討論]。

什麼是服務人員? 基本上,它是一個使用類固醇的網絡工作者。 Web Worker 的一個特點是,Web Worker 的所有任務都與主 JavaScript 執行線程(事件循環)分開(異步)運行。 此功能有助於運行 CPU 或內存密集型任務,例如復雜的計算,而不會影響 Web 應用程序用戶界面的性能。

Service Worker 讓我們可以在瀏覽器的 Service Worker 緩存中緩存(存儲很長時間)資產,例如 JavaScript、CSS、HTML、圖像、字體文件,因此下次用戶加載該頁面時,它幾乎會立即加載. 而且由於在這種緩存策略中,瀏覽器首先從 service worker 緩存中查找資產的可用性,即使網頁處於離線狀態,也會提供網頁! 如果緩存中沒有任何資產,則會發送網絡請求以獲取它。

Service Worker 還啟用了當今許多網站上常見的推送通知,包括 Facebook、Web 上的 Whatsapp 和 Twitter。 我們將主要討論離線功能。 這個方法是特定於 Jekyll 的,但是,大多數 service worker 代碼通常可以應用於任何網站。

由於 Jekyll 提供靜態內容(它是一個靜態站點生成器,呵呵! ),我們的 service worker 代碼將非常基本且易於理解。

來吧:

在所有相關頁面上,都會執行以下腳本。 它正在做以下事情:

  1. 檢查瀏覽器中是否存在 service worker API 並註冊 service worker。
  2. 當 service worker 被激活後,向用戶發送一條漂亮的 toast/chip 消息,表明該網站現在可以離線使用了。
 功能 showOfflineToast() {
  let offlineToast = document.querySelector('.offline-ready');
  offlineToast.classList.add('active');
  設置超時(函數(){ 
    offlineToast.className = offlineToast.className.replace("active", "").trim();
  }, 5500);
}

// (1)
if (navigator.serviceWorker) {
  navigator.serviceWorker.register('/sw.js').then(function(reg) {
      如果(!reg.installing)返回;
      console.log("[*] ServiceWorker 正在安裝...");

      var worker = reg.installing;

      worker.addEventListener('statechange', function() {
          if (worker.state == '冗餘') {
              console.log('[*] 安裝失敗');
          }
          if (worker.state == '已安裝') {
              console.log('[*] 安裝成功!');
          }
          // (2)
          if (worker.state == '激活' && !navigator.serviceWorker.controller) {
            showOfflineToast();
          }
      });
  });
} 

gdad-s-river.github.io-(iPhone 6)

您可以將這段代碼添加到 Jekyll 代碼的include目錄中的serviceWorker.html文件中,並使用 Jekyll 的液體模板引擎將其包含在default.html

<!DOCTYPE html>
<html>

  {% 包括 head.html %}

  <正文>
    {% 包含 header.html %}

    <div class="頁面內容">
      <div class="包裝器">
        {{ 內容 }}
      </div>
    </div>

    {% 包括 footer.html %}

    <!-- 在腳本標籤中包含上述代碼-->
    {% 包括 serviceWorker.html %} 

    <div class="offline-ready">網站已準備好離線使用</div>
  </正文>

</html>

現在到真正發揮作用的服務工作者代碼。 此代碼位於 Jekyll 代碼根目錄下的sw.js中。

 //sw.js
---
佈局:空
---

const staticCacheName = "gdad-s-river-static-v61";

console.log("正在安裝 service worker");

常量文件緩存 = [
  "/",
  {% for page in site.html_pages %}
    '{{ page.url }}',
  {% endfor %}
  {% for post in site.posts %}
    '{{ post.url }}',
  {% endfor %}

  // 可以自動輸入而不是手動輸入
  "/assets/images/bhavri-github-callbacks.png",
  "/assets/images/bhavri-github-issues.png",
  "/assets/images/jakethecake-svg-line-anime.png",
  "/assets/images/svg-animated-mast-text-shapes-tweet.png",
  "css/main.css",
  “/關於/”,
  “/index.html”
];

staticCacheName是緩存版本,每次我對緩存的響應進行一些更改時都會更新它(例如,我在 CSS 文件或博客文章中進行更改)。 而且,我只是定義了我想要攔截和緩存在數組中的請求(在下一個片段中使用)。

 //sw.js

self.addEventListener("安裝", function(e){
  self.skipWaiting();
  e.等待直到(
    caches.open(staticCacheName).then(function(cache){
      返回 cache.addAll(filesToCache);
    })
  )
});

self.skipWaiting ,就是說,每次這個sw.js文件更改時,新版本的服務工作者不應該排隊,而是立即激活(可以要求用戶提示刷新頁面,給出如下消息網頁已更新/更改,單擊刷新以加載新帖子或其他任何內容。 ),丟棄舊版本。

java-and-android-square-ad-1

e.waitUntil引用 MDN 網站:

ExtendedEvent.waitUntil()方法延長了事件的生命週期。 在服務工作者中,延長事件的生命週期可以防止瀏覽器在事件中的異步操作完成之前終止服務工作者。”

我打開一個名為gdad-s-river-static-v61 的緩存,它返回一個帶有我的緩存名稱的承諾,然後我調用cache.addAll (它在後台使用 fetch API),它獲取所有請求數組提供並緩存它們。

進入下一個片段!

 //sw.js

self.addEventListener("激活", function(e){
  e.等待直到(
    caches.keys().then(function(cacheNames){
      返回 Promise.all(
        緩存名稱.過濾器(功能(緩存名稱){
          return cacheName.startsWith("gdad-s-river-static-")
            && 緩存名稱 != 靜態緩存名稱;
        }).map(函數(cacheName){
          返回緩存。刪除(緩存名稱);
        })
      )ß
    })
  )
});

當服務工作者激活時,我確保所有不是最新版本的服務工作者都會被刪除。 例如,如果我的最新緩存版本是gdad-s-river-static-v61 ,並且有人仍在gdad-s-river-static-v58上,那麼在他/她下次訪問時,我希望該客戶不關心一次抽一個版本,但直接刪除該版本以安裝最新版本。

 //sw.js

self.addEventListener("fetch", function(e){
  e.respondWith(
     caches.match(e.request).then(function(response) {
       返迴響應 || 獲取(e.request);
     })
   )
});

在 fetch 事件中,我只是告訴服務工作者,如何響應發出的特定請求(因為我們劫持了響應賦予權力,服務工作者只在安全的又名 https 原始網站上工作)。 我告訴它將請求與瀏覽器中緩存的請求相匹配,如果它沒有找到對請求的特定響應,則通過網絡獲取它,否則從緩存中提供它。

多田! Service Worker 使 Jekyll 驅動的博客離線!

驚喜! 很酷的事情:

Bummer:這在 iOS 設備上不起作用。

如果您在項目的根目錄中添加一個 Web 應用manifest.json文件,如下所示:

 {
  “名稱”:“gdad-s-河”,
  "short_name": "gdad-s-river",
  "theme_color": "#2196f3",
  "background_color": "#2196f3",
  “顯示”:“獨立”,
  “範圍”: ”/”,
  "start_url": "/",
  “圖標”:[
    {
     "src": "assets/images/favicon_images/android-icon-36x36.png",
     “尺寸”:“36x36”,
     "type": "圖片\/png",
     “密度”:“0.75”
    },
    {
     "src": "assets/images/favicon_images/android-icon-48x48.png",
     “尺寸”:“48x48”,
     "type": "圖片\/png",
     “密度”:“1.0”
    },
    {
     "src": "assets/images/favicon_images/android-icon-72x72.png",
     “尺寸”:“72x72”,
     "type": "圖片\/png",
     “密度”:“1.5”
    },
    {
     "src": "assets/images/favicon_images/android-icon-96x96.png",
     “尺寸”:“96x96”,
     "type": "圖片\/png",
     “密度”:“2.0”
    },
    {
     "src": "assets/images/favicon_images/android-icon-144x144.png",
     “尺寸”:“144x144”,
     "type": "圖片\/png",
     “密度”:“3.0”
    },
    {
     "src": "assets/images/favicon_images/android-icon-192x192.png",
     “尺寸”:“192x192”,
     "type": "圖片\/png",
     “密度”:“4.0”
    }
  ]
}

並將其添加到 head 標籤內的head.html文件中,

 <頭部>
 <!-- 一些東西 -->
	<link rel="manifest" href="/manifest.json">
 <!-- 一些東西 -->
</head>

然後,在您第二次訪問您的網站時(5 分鐘內),將提示用戶將您的網站添加到您的主屏幕(以圖標形式駐留,就像其他本地應用程序一樣),您將參與其中,就像一個應用程序。

截圖_20170123-232947

資源

  • Service Worker 的離線功能和緩存策略的詳細信息可以在這本很棒的 Jake Archibald 的離線食譜中找到。
  • 一個非常詳細的免費 Udacity 課程,介紹您需要了解的有關服務人員和 IndexDB 的所有信息。

你覺得 Jekyll 博客上的這篇文章有趣且有用嗎? 不要忘記分享您的觀點和反饋。

另請閱讀:Ecosia——種植樹木的搜索引擎