【问题标题】:How to implement skipWaiting with Create React App?如何使用 Create React App 实现 skipWaiting?
【发布时间】:2018-10-20 09:54:39
【问题描述】:

我希望用户能够在有新的服务人员可用并等待时当场更新?当有新的更新可用时,我已经能够显示一个弹出窗口,但我想添加一个按钮来强制当场更新。我知道这可以通过调用 skipWaiting 来实现,但不确定如何使用 Create React App 来实现它。有没有人能够做到这一点?将不胜感激。谢谢!

【问题讨论】:

    标签: reactjs service-worker create-react-app


    【解决方案1】:

    CRA build\service-worker.js 文件现在(v3 plus)包含处理 skipWaiting 的代码:

    self.addEventListener('message', (event) => {
      if (event.data && event.data.type === 'SKIP_WAITING') {
        self.skipWaiting();
      }
    });
    

    index.js 中调用的注册函数serviceWorker.js 文件现在接受一个配置参数:

    serviceWorker.register({
      onUpdate: registration => {
        const waitingServiceWorker = registration.waiting
    
        if (waitingServiceWorker) {
          waitingServiceWorker.addEventListener("statechange", event => {
            if (event.target.state === "activated") {
              window.location.reload()
            }
          });
          waitingServiceWorker.postMessage({ type: "SKIP_WAITING" });
        }
      }
    });
    

    这将跳过等待,然后在应用更新后刷新页面。

    【讨论】:

    • 如何处理用户重新加载页面而不点击“更新可用”横幅?事件“onUpdate”不会在下一次加载时触发
    【解决方案2】:

    serviceWorker.js文件可以找到这段代码

    if (config && config.onUpdate) {
        config.onUpdate(registration);
     }
    

    所以实现config.onUpdate函数

    创建一个文件swConfig.js

    export default {
     onUpdate: registration => {
       registration.unregister().then(() => {
       window.location.reload()
     })
    },
    onSuccess: registration => {
      console.info('service worker on success state')
      console.log(registration)
     },
    }
    

    index.js将实现函数发送给serviceWorker

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import * as serviceWorker from './serviceWorker';
    import swConfig from './swConfig'
    
    ReactDOM.render(<App />, 
    document.getElementById('root'));
    serviceWorker.register(swConfig);
    

    查看此存储库 https://github.com/wgod58/create_react_app_pwaupdate

    【讨论】:

      【解决方案3】:

      我使用了一个名为https://github.com/bbhlondon/cra-append-sw 的包来附加以下代码来调用触发器skipWaiting:

      self.addEventListener('message', event => {
        if (event.data === 'skipWaiting') {
          self.skipWaiting();
        }
      });
      

      【讨论】:

      【解决方案4】:

      @user10532439 的回答对我不起作用。我最终使用了https://github.com/bbhlondon/cra-append-sw 并添加

      // @ts-ignore
      workbox.skipWaiting();
      
      // @ts-ignore
      workbox.clientsClaim();
      

      随着

      "build": "react-scripts build && cra-append-sw -s ./src/custom-sw.js",
      

      【讨论】:

        【解决方案5】:

        我知道它已经得到解答,但我找到了一个不需要任何额外包的解决方案,当然除了工作箱。

        package.json

        "build": "react-scripts build && node ./src/serviceWorkerBuild"
        

        serviceWorkerBuild.js

        const workboxBuild = require('workbox-build');
        
        // NOTE: This should be run *AFTER* all your assets are built
        const buildSW = () => {
          // This will return a Promise
          return workboxBuild.injectManifest({
            swSrc: 'src/serviceWorkerRules.js',
            swDest: 'build/sw.js',
            globDirectory: 'build',
            globPatterns: [
              '**\/*.{js,css,html,png}',
            ]
          }).then(({count, size, warnings}) => {
            // Optionally, log any warnings and details.
            warnings.forEach(console.warn);
            console.log(`${count} files will be precached, totaling ${size} bytes.`);
          });
        };
        
        buildSW();
        

        serviceWorkerRules.js 您可以在其中添加规则:

        importScripts(
            'https://storage.googleapis.com/workbox-cdn/releases/3.5.0/workbox-sw.js'
        );
        /* global workbox */
        if (workbox) {
            console.log('Workbox is loaded');
        
          self.addEventListener('install', event => {
            self.skipWaiting();
          });
        
            /* injection point for manifest files.  */
            workbox.precaching.precacheAndRoute([]);
        
        /* custom cache rules*/
        workbox.routing.registerNavigationRoute('/index.html', {
            blacklist: [/^\/_/, /\/[^\/]+\.[^\/]+$/],
            });
        
        workbox.routing.registerRoute(
            /\.(?:png|gif|jpg|jpeg|svg)$/,
            workbox.strategies.cacheFirst({
                cacheName: 'images',
                plugins: [
                    new workbox.expiration.Plugin({
                        maxEntries: 60,
                        maxAgeSeconds: 5 * 24 * 60 * 60, // 5 Days
                    }),
                ],
            }),
            );}
        

        还在第 78 行的 serviceWorker.js 中添加 window.location.reload();

        【讨论】:

        • 这里,拿这个`}`你忘了关闭serviceWorkerRules.js中的if块
        • @Jkarttunen tnx
        【解决方案6】:

        您应该在 service worker 的 install 事件中调用 skipWaiting 方法。 Service Worker 与 UI/React 代码分离。所以与真正的反应无关。

        现在我有一个模式,我将安装事件代码重构为自己的方法,所以我的服务人员看起来像这样:

        self.addEventListener( "install", function ( event ) {
        
            event.waitUntil( installServiceWorker() );
        
        } );
        
        function installServiceWorker() {
        
            self.skipWaiting();
        // do stuff here like pre-caching site core assets
        //most likely returning a promise
        
        }

        另外:如果您需要将缓存资产与活动 UI 同步,请不要调用 skipWaiting。如果您的 service worker 正在更新并且可能会破坏 UI,那么不要调用 skipWaiting。而是等待用户刷新页面。 您可以使用消息传递基础架构来通知用户有可用的更新,例如让他们刷新。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多