在 Next-js 應用中實現 service workers

原文作者:Elijah Agbonze

原文地址:https://blog.logrocket.com/implementing-service-workers-next-js/

翻譯:一川

多年來,開發人員嘗試了許多不同的策略,以使 Web 應用程序在用戶體驗方面儘可能接近native app。需要解決的一個重大問題是網絡連接丟失時會發生什麼。

作爲native app用戶,你仍希望能夠訪問應用的數據。但在 Web 應用程序中,情況有所不同。

有許多解決方案可以嘗試解決此問題,但端點問題一直是緩存資產和發出自定義網絡請求。Service workers 修復了此問題。

藉助Service workers ,您可以通過將應用設置爲使用緩存 assets 來提供離線優先體驗。這樣,當用戶處於脫機狀態時,他們仍然可以訪問以前的數據。

在本文中,我們將瞭解如何在 Next.js 中實現Service workers

什麼是 service workers?

Service workers是在網頁後臺運行的腳本。它們與主瀏覽器線程完全分開,因此,它們是非阻塞的,無法訪問 DOM。

由於Service workers充當網頁和網絡之間的代理,因此它們可以提供脫機支持、推送通知和後臺更新等功能。它們攔截網頁發出的網絡請求,並直接修改或響應它們,而不涉及頁面本身。

Service workers設計爲完全異步。因此,XHR 和 Web 存儲等 API(包括兩者 sessionStorage 兼而有之) localStorage 不能在Service workers中使用。

請務必注意,Service workers僅在 HTTPS 上運行,但 localhost 服務器除外。通過 HTTPS 運行有助於防止可能危及應用及其用戶的惡意安全威脅。因此,僅在開發中使用 HTTP。

Next.js 中Service workers的用例

在我們深入探討在 Next.js 應用中實現Service workers之前,讓我們看一下它可用於的一些功能。

緩存

緩存 assets 可以爲用戶提供離線優先的體驗。

爲此,您必須使用緩存 API 將資產存儲在瀏覽器緩存中,也稱爲預緩存。當連接不可用時,用戶可以從緩存中獲取 assets,也稱爲運行時緩存。

PWA

漸進式 Web 應用程序需要Service workers來執行自定義網絡請求、脫機支持、快速加載、推送通知和許多其他功能。

Push notifications

使用Service workers,可以偵聽推送通知事件,這將使應用能夠接收通知,即使應用未在瀏覽器中主動運行也是如此。推送通知對於需要提供實時更新的應用程序(例如社交網絡)非常有用。

後臺同步

Service workers可以在頁面和服務器之間啓用數據的後臺同步,即使應用未主動運行也是如此。後臺同步使用戶的數據以及服務器始終保持最新狀態,這將降低數據丟失的風險。

Analytics

Service workers可用於在不中斷用戶體驗的情況下收集分析數據。分析對於提供對應用性能的見解非常有幫助。

Service workers的工作方式

在我們開始在 Nextjs 中實現Service workers之前,讓我們看一下它們傳統上是如何工作的。使用Service workers時,執行三個主要步驟:

現在讓我們逐一介紹這些步驟。

註冊Service workers

下面是註冊Service workers的示例:

window.addEventListener('load'() ={
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js');
  };
})

在這裏,我們檢查了瀏覽器是否支持並激活了 ServiceWorker API,然後再繼續註冊。函數 register 的第一個參數是Service workers文件的路徑。

安裝和激活Service workers

現在,在Service workers文件中,您需要安裝Service workers並分別使用 install 和 activate 事件激活它:

self.addEventListener('install'() ={
  console.log('service worker installed')
});

self.addEventListener('activate'() ={
  console.log('service worker activated')
});

self 類似於在常規網頁的上下文 window 中。使用它而不是 window 爲了避免與它混淆,因爲全局 window 對象在Service workers中不可用。

目前,我們僅將消息記錄到控制檯,以指示這些事件發生的時間。但是,在這些函數中還有很多事情可以做。

例如,我們可以創建一個緩存,並在 install 事件完成後向其添加 assets。我們將在下一節中看到各種實現的示例。

在 Next.js 中實現Service workers

在本節中,我們將構建一個基本的 Next.js 應用程序,並使用Service workers使其脫機可用。若要按照本教程進行操作,應熟悉如何使用 Next.js 進行開發。

查看此項目的現場演示。您還可以通過 GitHub[https://github.com/Elijah-trillionz/nextjs-service-worker] 訪問代碼。

設置一個 Next.js 項目

首先,讓我們創建一個 Next.js 項目。爲此,請運行以下命令:

npx create-next-app@latest

安裝後,在首選代碼編輯器中打開項目並在終端窗口中運行 npm run dev

在本教程中,我們將創建一個名爲 docs 。因此,轉到 pages 該目錄,創建一個名爲 docs.js 的新文件,然後將以下內容粘貼到其中:

import Head from 'next/head';
import Image from 'next/image';
import styles from '@/styles/Home.module.css';

export default function Docs() {
  return (
    <>
      <Head>
        <title>Next.js Service Workers Docs</title>
        <meta name='description' content='Generated by create next app' />
        <meta name='viewport' content='width=device-width, initial-scale=1' />
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <main className={styles.main}>
        <div className={styles.description}>
          <p>Service Worker Docs</p>
          <div>
            <a
              href='https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app'
              target='_blank'
              rel='noopener noreferrer'
            >
              By not{' '}
              <Image
                src='/vercel.svg'
                alt='Vercel Logo'
                className={styles.vercelLogo}
                width={100}
                height={24}
                priority
              />
            </a>
          </div>
        </div>

        <div className={styles.center}>
          <Image
            className={styles.logo}
            src='/next.svg'
            alt='Next.js Logo'
            width={180}
            height={37}
            priority
          />
        </div>
      </main>
    </>
  );
}

此頁面類似於我們在 index.js 。現在,當您在瀏覽器中打開項目時,打開瀏覽器的 DevTools 並導航到您的應用程序。選擇Service workers選項卡:

在這裏,您將看到所有Service workers的運行情況,即在安裝、激活和使用的過程中。

選中 “離線” 框並重新加載您的頁面。顯然,您的瀏覽器會指示沒有互聯網。

然後,查看我們項目的演示網站 [https://next-sw.netlify.app/] 並檢查 “離線” 選項。您應該注意到頁面仍然加載正常。在本教程結束時,您的也將能夠做到這一點。

添加Service workers

在 Next.js v10 之前中使用Service workers需要本地服務器。但是,從 Next.js v10 開始,可以在沒有本地服務器的情況下使用Service workers。這類似於在 vanilla JS 中實現它。

爲此,我們需要做兩件事:

首先,讓我們通過在函數中添加以下內容_app.js來註冊Service workers

useEffect(() ={
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker
        .register('/service-worker.js')
        .then((registration) => console.log('scope is: ', registration.scope));
    }
  }[]);

我註冊此Service workers _app.js 的原因是我希望它能夠訪問整個網站——所有 assets、頁面和所有內容。在大型應用程序中,您可能只需要一個特定的Service workers來處理某一組頁面,而另一個Service workers用於另一組頁面。

如前所述,該方法 register 的第一個參數是Service workers的路徑。瀏覽器應該能夠訪問此路徑。在 Next.js 中,對於瀏覽器要訪問的路徑,它將位於 public 目錄中。

轉到 public 目錄並創建一個名爲 service-worker.js 。這是我們將在其中安裝和激活Service workers的文件,以及執行其他有趣的操作,例如緩存、推送通知等。

在進入緩存之前,讓我們先安裝並激活Service workers。將以下內容粘貼到 service-worker.js 文件中:

const installEvent = () ={
  self.addEventListener('install'() ={
    console.log('service worker installed');
  });
};
installEvent();

const activateEvent = () ={
  self.addEventListener('activate'() ={
    console.log('service worker activated');
  });
};
activateEvent();

您應該從上面的安裝和激活Service workers概述中識別出此代碼。

保存文件並在瀏覽器中重新加載頁面,確保在 “開發人員工具” 面板中取消選中 “Offline”。您還應該選中“Update on reload” 選項,以便在重新加載頁面時更新Service workers

您應該會在您的圖像上看到類似上圖的內容。狀態當前指示Service workers已激活並正在運行。

使用Service workers 緩存 Next.js 的 assets

讓我們爲我們的頁面添加離線支持。傳統上,我們要做的是列出我們所有的 assets 和頁面,並緩存每一個。

然而,對於 Next.js 項目來說,這是大量的工作——你必須找到每個 CSS 文件的唯一 ID,並在構建應用程序後列出代表你的頁面的每個 JavaScript 靜態文件。

一種更簡單的方法是一次緩存用戶所在頁面的所有資產。我們可以通過在Service workers的事件處理程序中使用 Response fetch 對象 clone() 的方法來實現這一點。

將以下內容添加到您的 service-worker.js 文件中:

const cacheName = 'v1'

const cacheClone = async (e) ={
  const res = await fetch(e.request);
  const resClone = res.clone();

  const cache = await caches.open(cacheName);
  await cache.put(e.request, resClone);
  return res;
};

const fetchEvent = () ={
  self.addEventListener('fetch'(e) ={
    e.respondWith(
      cacheClone(e)
        .catch(() => caches.match(e.request))
        .then((res) => res)
    );
  });
};

fetchEvent();

緩存中應該有這樣的東西:

現在選中 “Offline” 選項並重新加載頁面。

請注意,該 /docs 頁面尚未包含在緩存中。這是因爲它沒有被訪問過。導航到該頁面後,該頁面將與該頁面相關的任何其他新資產一起添加到緩存中。

對於具有大量 assets 的大型應用程序,這可能不是一個很好的做法。因此,您可能需要考慮僅緩存到Service workers的有限範圍。

例如,如果Service workers範圍僅限於頁面,則不會緩存 /docs/index 頁面及其 assets。在註冊Service workers時,可以使用該 scope 屬性爲Service workers指定作用域,如下所示:

 useEffect(() ={
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker
        .register('/service-worker.js'{ scope: '/docs' })
        .then((registration) => console.log('scope is: ', registration.scope));
    }
  }[]);

Service workers中使用推送 API 進行推送通知

推送 API 使 Web 應用能夠從服務器接收推送通知並將其顯示給用戶。

請記住,Service workers在應用的後臺運行。因此,應用無需在瀏覽器中運行,瀏覽器即可接收推送通知並顯示給用戶。

讓我們看一個基本示例,說明如何使用 Next.js Service workers實現推送 API。

訂閱推送通知

首先,您必須向瀏覽器註冊您的應用程序以獲取推送通知:

navigator.serviceWorker
 .register("/service-worker.js")
 .then((registration) =>
   registration.pushManager.subscribe({
     userVisibleOnly: true,
     applicationServerKey,
   })
 );

userVisibleOnly 選項指示來自推送訂閱的消息僅對用戶可見。

applicationServerKey 選項用於指定推送服務提供商將用於對服務器進行身份驗證的公鑰。

此密鑰 [https://blog.logrocket.com/jwt-authentication-best-practices/] 可以是從服務器發送的 JWT,用於訂閱過程。

偵聽消息

最後要做的是偵聽來自服務器的消息並將其顯示給用戶。通過註冊 Web 應用程序以獲取推送通知,可以使用PushEvent來偵聽來自經過身份驗證的服務器的通知:

self.addEventListener('push',(event) ={
 const data = event.data.json();
 const title = data.title;
 const body = data.message;
 const icon = 'some-icon.png';
 const notificationOptions = {
   body: body,
   tag: 'simple-push-notification-example',
   icon: icon
 };

 return self.Notification.requestPermission().then((permission) ={
   if (permission === 'granted') {
     return new self.Notification(title, notificationOptions);
   }
 });
});

在 Next.js 中使用Service workers的缺點

在深入研究在 Next.js 應用程序中使用Service workers之前,您應該注意一些常見問題。

失效緩存

有時,確保緩存的 assets 始終是最新的可能具有挑戰性。這可能會導致用戶在您的網站上使用過時的資源。

爲了解決這個問題,強烈建議對緩存進行版本控制(正如我們在本文中看到的那樣)。對於每個新 assets 或資源,創建具有不同版本的新緩存。

有限的瀏覽器支持

雖然現代流行的瀏覽器支持Service workers,但也值得注意的是,有一些較舊的瀏覽器不支持Service workers

傳統上,Service workers僅爲現有網站提供額外的增強功能。換句話說,它們爲您的網站帶來了改進的功能,例如離線可用性、後臺同步、推送通知、分析等。

因此,不支持Service workers的瀏覽器不會破壞您的應用程序;它們的工作方式類似於您現有網站不依賴的開箱即用插件。

性能降低

Service workers可以提高 Web 應用的性能。但是,如果實施不當,它們可能會對應用的性能產生負面影響。

例如,緩存過多 assets 可能會導致加載時間變慢。若要防止此問題,請考慮限定服務輔助角色的範圍,如前所述。

安全風險

在不安全的協議上使用Service workers可能會對您和您的用戶構成安全威脅。這是因爲Service workers可用於攔截網絡請求和響應,這些請求和響應可用於從用戶那裏竊取敏感信息。

Service workers還可能被利用來執行惡意攻擊,例如網絡釣魚和垃圾郵件,這可能會對應用的聲譽構成威脅。因此,您不應該冒險在生產中使用 HTTP 上的Service workers

總結

在本文中,我們瞭解了什麼是Service workers,它們的一些常見用例,以及如何在 Next.js 中實現它們。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/l0E7QIHyygdYTowq2Q9Smg