【问题标题】:How do I convert an application cache manifest to a service worker如何将应用程序缓存清单转换为服务工作者
【发布时间】:2020-06-23 20:24:51
【问题描述】:

application cache is now deprecatedChrome are removing support 等浏览器。

我们有一个应用程序可以 100% 离线工作,同时将数据存储在 indexeddb 中,并在用户重新在线时进行同步。 我们需要将此站点从使用应用程序缓存转换为服务工作者。我们将使用Workbox 作为我们的服务人员。

我们必须隐藏缓存清单的三个主要部分。

缓存部分 这是要预缓存的资产列表。这可能是最直接的过渡,因为我们使用的是workbox to precache these files

网络部分 我们在这里使用 *(可能是最常见的),所以这可能不会成为问题。

FALLBACK 部分 我们在后备部分中有很多条目。基本上它们会重定向到登录页面,以防有人离线刷新页面。

例子:

FALLBACK:
/search /login
/customer-edit /login
/foo-bar-baz /login
...

我的问题:

是否有 1) 将应用程序缓存/缓存清单转换为 Service Worker 的一般指南,或 2) 将 FALLBACK 部分转换为 Service Worker 中的等效功能的一些具体指南。

Google 和 Duck Duck Go 的帮助不大。

现有项目将应用缓存升级到服务工作者,但大多数看起来都非常测试,例如来自 Google Chrome 实验室:github.com/GoogleChromeLabs/sw-appcache-behavior

【问题讨论】:

    标签: html service-worker offline-caching html5-appcache


    【解决方案1】:

    这是我使用Google's workbox 提出的解决方案。

    旁注:Workbox 似乎为大多数常见的 Service Worker 用例提供了解决方案,并且具有非常灵活的分发模型,无论是在 vanilla js 环境中还是在您选择的框架中,都非常容易使用。

    我们最终转换了我们的服务器端 AppCache(缓存清单代码)来生成一个服务工作者。 (How to precaching an url list coming from a json file?)

    根据您的服务器端语言,您的代码会有所不同,但这是对我们有用的最终产品:

    service-worker.js(生成的服务器端)

    
        const productVersion = "3.01";
    
        importScripts('/assets/workbox/workbox-sw.js');
    
        workbox.setConfig({
            modulePathPrefix: '/assets/workbox/'
        });
    
        const { precacheAndRoute, createHandlerBoundToURL } = workbox.precaching;
        const { NavigationRoute, registerRoute, setCatchHandler } = workbox.routing;
    
        precacheAndRoute([
            // cache index html
            {url: '/', revision: '3.01' },
    
            // web workers
            {url: '/assets/some-worker.js?ver=3.01', revision: '' },
            {url: '/assets/other-worker.js?ver=3.01', revision: '' },
            // other js files
            {url: '/assets/shared-function.js', revision: '3.01' },
            // ... removed for brevity
            // css
            {url: '/assets/site.css', revision: '3.01' },
            {url: '/assets/fonts/fonts.css', revision: '3.01' },
            // svg's
            {url: '/assets/images/icon.svg', revision: '3.01' },
            {url: '/assets/images/icon-2.svg', revision: '3.01' },
    
            // png's
            {url: '/assets/images/img-1.png', revision: '3.01' },
            {url: '/assets/images/favicon/apple-touch-icon-114x114.png', revision: '3.01' },
            // ...
            // ...
    
            // fonts
            {url: '/assets/fonts/lato-bla-webfont.eot', revision: '3.01' },
            {url: '/assets/fonts/lato-bla-webfont.ttf', revision: '3.01' },
    
            // sounds
            {url: '/assets/sounds/keypress.ogg', revision: '3.01' },
            {url: '/assets/sounds/sale.ogg', revision: '3.01' },
        ]);
    
        // Routing for SPA
        // This assumes DEFAULT_URL has been precached.
        const DEFAULT_URL = '/';
        const handler = createHandlerBoundToURL(DEFAULT_URL);
        const navigationRoute = new NavigationRoute(handler, {
            denylist: [
                new RegExp('/ping'),
                new RegExp('/upgrade'),
                new RegExp('/cache.manifest'),
          ],
        });
        registerRoute(navigationRoute);
    
        // This allows the main window to signal the service worker that
        // it should go ahead and install if it's waiting.
        addEventListener('message', (event) => {
            if (event.data && event.data.type === 'SKIP_WAITING') {
                skipWaiting();
            }
        });
    
    
    
    1. 还有一些其他事项需要注意。我们必须弄清楚如何从 App?Cache 平滑升级到 Service Worker。事实证明,为我们生成一个空的缓存清单起到了作用。
    2. 我们已经有一个升级过程(提示用户升级或使用倒数计时器强制自动升级),因此我们必须做一些工作才能使其与服务人员一起使用。注意服务工作者文件的末尾有addEventListener 代码。我们实际上是从升级页面调用它以获得平滑的升级过程。它是这样的:

    A) 升级脚本检测到有新版本可用(执行此操作的方法很多,api 调用轮询等)

    B) 如果用户接受或计时器到期,则将用户重定向到upgrade 页面。这一步至关重要,因为您无法在应用仍在运行的情况下更新服务人员。所以导航到升级页面,等待服务工作者安装,然后告诉它跳过等待并重定向到主(登录)屏幕。

    C) 用户正在愉快地运行新版本的应用程序。

    升级页面代码: (这是显示某种类型的“更新”用户界面的好页面)

    <script type="module">
            import { Workbox } from '/assets/workbox/workbox-window.prod.mjs';
    
            if ('serviceWorker' in navigator) {
                const wb = new Workbox('/serviceworker');
    
                // This code exists b/c a service worker can't update with just a refresh/reload in the
                // browser. This is b/c on a reload, the old and new page exist simultaneously and the old MUST
                // unload before the new service worker can automatically assume control. Also if multiple pages
                // are open, this blocks the service worker from taking control (multiple pages should not an issue with this app).
                // This code activates a waiting service worker and _then_ redirects back to the app.
    
                // Add an event listener to detect when the registered
                // service worker has installed but is waiting to activate.
                wb.addEventListener('waiting', (event) => {
    
                    // Set up a listener that will reload the page as soon as the previously waiting
                    // service worker has taken control.
                    wb.addEventListener('controlling', (event) => {
                        window.location.replace('/login');
                    });
    
                    // Send a message telling the service worker to skip waiting.
                    // This will trigger the `controlling` event handler above.
                    wb.messageSW({type: 'SKIP_WAITING' });
    
                });
    
                wb.register();
            }
    
            // set a timeout in case the service worker has already installed.
            setTimeout(function () {
                window.location.replace('/login');
            }, 30000);
    </script>
    
    

    主页(index.html等) (处理用户是否带着准备激活的服务器工作者进入应用程序,因此需要刷新才能加载正确的资产/代码)

    <script type="module">
            import { Workbox } from '/assets/workbox/workbox-window.prod.mjs';
    
            if ('serviceWorker' in navigator) {
                const wb = new Workbox('/serviceworker');
    
                wb.addEventListener('activated', (event) => {
                    // `event.isUpdate` will be true if another version of the service
                    // worker was controlling the page when this version was registered.
                    if (!event.isUpdate) {
                        // service worker was updated and activated for the first time.
                        // If your service worker is configured to precache assets, those
                        // assets should all be available now.
                        // this will only happen if the browser was closed when a new version was made available
                        // and it will only happen once per service worker install.
                        // Reload to so all libs are correct version.
                        window.location.reload(true);
                    }
                });
    
                wb.register();
            }
        </script>
    
    

    【讨论】:

      猜你喜欢
      • 2019-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-02
      • 2016-08-11
      相关资源
      最近更新 更多