使用 workbox 协助构建 PWA 应用

使用 workbox 协助构建 PWA 应用

1. 说明

workbox 是 GoogleChrome 团队推出的一套解决方案,提供站点离线访问能力,可以更方便、更简单的解决 Service Workers 绝大多数问题

重要文件版本

  • workbox-build ‘3.0.0’

2. workbox 简单使用

  1. workbox 是协助 Service worker 使用的,与一般的 Service worker 一样,首先需要在文件中注册 Service worker
<script>
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker
            .register('./sw.js')
            .then(registration => {
                console.log('SW registered: ', registration);
            })
            .catch(registrationError => {
                console.log('SW registration failed: ', registrationError);
            });
    });
}
</script>
  1. 在注册的 Service worker 文件 sw.js 中使用 workbox 处理资源的缓存
// sw.js

// 引入核心文件
importScripts(
    'https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'
);

// 设置缓存名称前缀
workbox.core.setCacheNameDetails({ prefix: 'gulp-pwa-demo' });

/*
    一下两个接口对应 service worker 中的
    self.skipWaiting() 强制等待中的 Service Worker 被激活
    self.clients.claim() 新的 Service Worker 被激活后使其立即获得页面控制权
 */

workbox.skipWaiting();
workbox.clientsClaim();

// 要 precache 预先缓存的文件
self.__precacheManifest = [
    {
        url: 'index.html',
        revision: 'dbd40fec5ea49691d7c6c775192f66f5'
    },
    {
        url: 'scripts/index.js',
        revision: 'd7968e072cb4b90efcbaf72e94ba00c9'
    },
    {
        url: 'styles/index.css',
        revision: '9707c6dcc441f4704f5ede55bf2f7d55'
    }
].concat(self.__precacheManifest || []);

workbox.precaching.suppressWarnings();

// precacheAndRoute 预缓存静态文件
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

/*
    registerRoute 路由请求缓存
    第一个参数可以是正则、完整路径字符串、或者是返回布尔值的函数
    第二个参数 workbox.strategies.networkFirst() 是一个路由缓存策略,用来确定资源缓存方式
 */

workbox.routing.registerRoute(
    new RegExp('.*.js'),
    workbox.strategies.networkFirst()
);

路由缓存策略

  • staleWhileRevalidate 请求的路由有对应的 cache 缓存就直接返回,同时在后台再次发起请求并更新 Cache
  • networkFirst 请求后,首先尝试拿到网路请求的返回结果,请求到就直接返回并且更新 cache,否则返回缓存中的内容
  • cacheFirst 请求后,直接从 Cache 中取得结果,没有的话在发起网络请求
  • networkOnly 强制使用网络请求
  • cacheOnly 强制使用 Cache 资源
    *

3. 结合 gulp 使用 workbox

gulp 中使用 workbox 需要引入 workbox-build

sudo yarn add --dev workbox-build

在 gulpfile.js 中配置,全部的 workbox 配置都要写在 workbox.generateSW(options) 中, workbox-build 工具会根据这个配置生成对应的 Service worker 文件,但是主文件中注册Service worker 还是需要手动写的,如果要实现‘添加到主屏幕功能’ 同样需要自己配置 manifest.json

workbox.generateSW(options)workbox.InjectManifest(options) 方法都是用来生成 Service worker 文件的,区别在于前者不需要模板文件,后者必须配置 swSrc: 'sw.js'指明模板来源,相当于在 模板 Service worker 中插入了 workbox 的代码

const gulp = require('gulp');
const workbox = require('workbox-build');

/*
    配置 PWA,API 与直接在 sw.js 中写是有区别的
 */

gulp.task('generate-service-worker', () => {
    return workbox
        .generateSW({
            cacheId: 'gulp-pwa-demo', // 设置前缀
            globDirectory: './build', //匹配根目录
            globPatterns: ['**/*.{html,js,css,png.jpg}'], // 匹配的文件
            globIgnores: ['sw.js'], // 忽略的文件
            swDest: `./build/sw.js`, // 输出 Service worker 文件
            clientsClaim: true, // Service Worker 被激活后使其立即获得页面控制权
            skipWaiting: true, // 强制等待中的 Service Worker 被激活
            runtimeCaching: [
                // 配置路由请求缓存 对应 workbox.routing.registerRoute
                {
                    urlPattern: /.*\.js/, // 匹配文件
                    handler: 'networkFirst' // 网络优先
                },
                {
                    urlPattern: /.*\.css/,
                    handler: 'staleWhileRevalidate', // 缓存优先同时后台更新
                    options: {
                        // 这里可以设置 cacheName 和添加插件
                        plugins: [
                            {
                                cacheableResponse: {
                                    statuses: [0, 200]
                                }
                            }
                        ]
                    }
                },
                {
                    urlPattern: /.*\.(?:png|jpg|jpeg|svg|gif)/,
                    handler: 'cacheFirst', // 缓存优先
                    options: {
                        plugins: [
                            {
                                expiration: {
                                    maxAgeSeconds: 24 * 60 * 60, // 最长缓存时间,
                                    maxEntries: 50 // 最大缓存图片数量
                                }
                            }
                        ]
                    }
                },
                {
                    urlPattern: /.*\.html/,
                    handler: 'networkFirst'
                }
            ]
        })
        .then(() => {
            console.info('Service worker generation completed.');
        })
        .catch(error => {
            console.warn('Service worker generation failed: ' + error);
        });
});

// 压缩输出, 将 generate-service-worker 任务添加到末尾
gulp.task('build', cb => {
    runSequence(
        'clean-build',
        'minify-html',
        ['minify-css', 'minify-js', 'move-libs-build'],
        'minify-img',
        'build-json',
        'generate-service-worker',
        cb
    );
});

执行后生成的 service-worker 文件如下,与直接写 service-worker 是一样的

importScripts(
    'https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'
);

workbox.core.setCacheNameDetails({ prefix: 'gulp-pwa-demo' });

workbox.skipWaiting();
workbox.clientsClaim();

/**
 * The workboxSW.precacheAndRoute() method efficiently caches and responds to
 * requests for URLs in the manifest.
 * See https://goo.gl/S9QRab
 */
self.__precacheManifest = [
    {
        url: 'index.html',
        revision: 'ffed06b43693a980d15df9eb95171465'
    },
    {
        url: 'libs/jquery-3.2.1.min.js',
        revision: 'c9f5aeeca3ad37bf2aa006139b935f0a'
    },
    {
        url: 'pages/aboutus.html',
        revision: '1bd0eef5e0e1a30063fe89ba68860f24'
    },
    {
        url: 'scripts/index.js',
        revision: 'd7968e072cb4b90efcbaf72e94ba00c9'
    },
    {
        url: 'scripts/registerServiceWorker.js',
        revision: '998c0ec9841a4e1f12872b37e4223d61'
    },
    {
        url: 'styles/aboutus.css',
        revision: '96895554b989e2f194169fe7e4d2a8b5'
    },
    {
        url: 'styles/index.css',
        revision: '9707c6dcc441f4704f5ede55bf2f7d55'
    }
].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

workbox.routing.registerRoute(
    /.*\.js/,
    workbox.strategies.networkFirst(),
    'GET'
);
workbox.routing.registerRoute(
    /.*\.css/,
    workbox.strategies.staleWhileRevalidate({
        plugins: [{ cacheableResponse: { statuses: [0, 200] } }]
    }),
    'GET'
);
workbox.routing.registerRoute(
    /.*\.(?:png|jpg|jpeg|svg|gif)/,
    workbox.strategies.cacheFirst({
        plugins: [{ expiration: { maxAgeSeconds: 86400, maxEntries: 50 } }]
    }),
    'GET'
);
workbox.routing.registerRoute(
    /.*\.html/,
    workbox.strategies.networkFirst(),
    'GET'
);

参考

其他相关

猜你喜欢

转载自blog.csdn.net/mjzhang1993/article/details/79570731
PWA