美文网首页
angular service worker搭配workbox使

angular service worker搭配workbox使

作者: 琢磨先生lf | 来源:发表于2018-06-25 12:52 被阅读179次

    原文链接
    略过前言直接进入主题

    什么是 Service Worker?

    Service Worker是一个相对较新的技术,用于在应用中运行执行Javascript代码,即使用户还没有打开页面。通过它我们可以在浏览器中注册代码片段、对某些事件进行处理,甚至在我们的例子中,可以对请求进行缓存生成离线应用。

    service worker可以设想成浏览器域名下的一个代理,流量通过Service Worker分发,Worker决定数据是从缓存还是从网络获取。缓存是通过service worker API接口定义的,我们可以通过service worker定制自己的缓存策略。

    今天我们不打算这样做,事实上,自己实现缓存非常麻烦。幸运的是我们不需要自己造轮子,已经有可用的库提供高级的接口来实现我们需求。本文中我们使用谷歌的Workbox

    不是所有的浏览器都支持service worker,但是它们都宣称未来会支持

    为什么选择 Workbox?

    angular-cli集成了service worker,在angular-cli配置service worker非常容易

    新建 angular 项目

    ng new angular-service-worker
    

    使用npm i加载依赖

    下一步,下载Workbox build API

    npm i workbox-build --save-dev
    

    环境以及搭建完成。

    为 angular 项目搭建一个 Service Worker 缓存

    我们以及下载了Workbox build API,接下来我们就可以去生成angular service worker,为什么我们要生成一个,而不是通过代码配置?

    要缓存静态文件,service worker需要知道其文件名,使用 angular-cli 构建项目的时候,目标文件名每次都会改变,angular-cli 在文件名上加了hash值,浏览器可以为新文件作缓存又避免就文件缓存影响

    目标文件名每次都会改变,我们无法在 worker-script 去配置,那样每次构建完都要去更改配置,所以我们使用Workbox build API 接口实现。

    Workbox build API 允许我们通过 node.js 脚本文件扫描目标文件目录生成 service worker 脚本文件,目标文件大概这样:
    dist/sw.js

    ...
    const fileManifest = [
      {
        "url": "index.html",
        "revision": "2a59e6e03216061ad8eebe5d302b63be"
      },
      {
        "url": "inline.5f8f26e0d9e0b566019d.bundle.js",
        "revision": "590f7d098ab30195f9f4761bf79ec18c"
      },
      {
        "url": "main.c0c528c8c7636a1ce8fc.bundle.js",
        "revision": "f1646bf6ca91be91e46d35a173846e5b"
      },
      {
        "url": "polyfills.67d068662b88f84493d2.bundle.js",
        "revision": "ad4076ac41e8c08e5b5f872136081192"
      },
      {
        "url": "styles.d41d8cd98f00b204e980.bundle.css",
        "revision": "d41d8cd98f00b204e9800998ecf8427e"
      },
      {
        "url": "vendor.dd97be8fb65ee0109dba.bundle.js",
        "revision": "dad8873f5866215d28f6a9d07764de3b"
      }
    ];
    workboxSW.precache(fileManifest);
    ...
    

    缓存静态内容

    现在我们开始写脚本文件,我们在项目根目录下新建一个 generate-service-worker.js 文件

    const build = require("workbox-build");
    const SRC_DIR = "./";
    const BUILD_DIR = "dist";
    
    const options = {
      swDest: `${BUILD_DIR}/sw.js`, // target directory
      globDirectory: BUILD_DIR,
      navigateFallback: "/index.html", // redirect all reqest to the fallback, if no explicit route matches
      clientsClaim: true
    };
    
    build.generateSW(options).then(() => {
      console.log("Generated service worker with static cache");
    });
    

    这段脚本代码中,我们定义了一些变量并将其传递给 builder 的 generateSW 方法,然后 builder 在 BUILD_DIR 指定的目录下创建 service worker 文件

    基本就是这样,依靠 angular 生成的 service worker 会缓存所有静态文件。然而,大多数应用程序依赖动态内容,动态内容此时还没被缓存

    缓存动态内容

    要缓存动态内容,我们需要告诉 Workbox 内容来源,比如说我们有一个接口地址,它提供与应用程序同域下的内容,缓存这类内容,我们需要使用 Workbox builder 的 runtimeCaching 方法,举例说明:
    generate-service-worker.js

    const options = {
      swDest: `${BUILD_DIR}/sw.js`,
      globDirectory: BUILD_DIR,
      navigateFallback: "/index.html",
      clientsClaim: true,
      runtimeCaching: [
        {
          urlPattern: //api/(.*)/, // reg ex
          handler: "networkFirst" // caching strategy
        }
      ],
      handleFetch: true
    };
    

    现在,所有/api/* 下的数据都会被缓存

    缓存策略

    你还可以定义不同的缓存策略,这是缓存策略

    拓展 Service Worker

    更多时候,builder 提供的选项不满足我们的应用场景, 比如推送通知缓存到 service worker. 好在service worker 提供用户自定义选项,builder 会通过swSource属性合并两份文件成一个 service worker.
    generate-service-worker.js

    const options = {
      swSource: `${SRC_DIR}/service-worker.js`,
      swDest: `${BUILD_DIR}/sw.js`,
      globDirectory: BUILD_DIR,
      navigateFallback: "/index.html",
      clientsClaim: true,
      runtimeCaching: [
        {
          urlPattern: //api/(.*)/, // reg ex
          handler: "networkFirst" // caching strategy
        }
      ],
      handleFetch: true
    };
    

    同时我们将方法名从generateSW() 改为 injectManifest()
    generate-service-worker.js

    build.injectManifest(options).then(() => {
        
    });
    

    为 Service Worker 配置构建脚本

    到这一步,使用 Workbox 不会比 使用 angular-cli service worker 复杂

    要想在构建时自动生成 generate-service-worker.js ,我们需要手动在构建脚本关联 service worker。

    有一个办法是定制angular-cli 使用 Workbox Webpack pluign,这个可以让 generate-service-worker.js 运行良好,但会破坏angular-cli结构

    我们可以在运行 "npm start" 启动项目的时候,通过 express 运行 node.js 脚本,这两个都不算是最佳方案,如果你更好的方案,请联系我
    这是 npm package.json

    ...
    "scripts": {
        "ng": "ng",
        "start": "ng build --prod && npm run gn-sw && node server/server.js",
        "build": "ng build --prod && npm run gn-sw",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e",
        "gn-sw": "node generate-service-worker.js"
      },
    ...
    
    const express = require("express");
    const app = express();
    
    app.use(express.static(__dirname + "/../dist/"));
    
    app.listen(process.env.PORT || 8080, () => {});
    

    相关文章

      网友评论

          本文标题:angular service worker搭配workbox使

          本文链接:https://www.haomeiwen.com/subject/ouaeyftx.html