【问题标题】:Create React App with Service Workers使用 Service Worker 创建 React 应用程序
【发布时间】:2017-09-04 13:02:26
【问题描述】:

我已将我的 CRA 升级到版本 3.10.8,因为它内置了对 PWA 的支持。 作为下一步,我在 index.js 中注册了我的服务工作者,我认为它已成功注册。 现在我的主要目标是为我们的 API 调用(Rails 中的后端)提供一些离线缓存,以便在没有网络时可以提供缓存的响应。 我还需要做些什么来提供缓存的 API 响应。 当我使用 Create react App 构建我的应用程序时,它所做的只是创建了一个名为 registerServiceWorker.js 然后从 index.js 调用它。

此外,我们正在构建的最终应用程序是使用 Codova 打包的,因此大部分资产将位于本地,我们的主要目标是缓存 API 调用。这是正确的方法吗。我们正在使用 Redux 进行状态管理,但到目前为止还没有使用任何持久性。 任何帮助/提示将不胜感激。

registerServiceWorker.js 代码如下...

    // In production, we register a service worker to serve assets from local cache.

// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.


const isLocalhost = Boolean(
  window.location.hostname === 'localhost' ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === '[::1]' ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(
      /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
    )
);

export default function register() {
  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
    // The URL constructor is available in all browsers that support SW.
    const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
    if (publicUrl.origin !== window.location.origin) {
      // Our service worker won't work if PUBLIC_URL is on a different origin
      // from what our page is served on. This might happen if a CDN is used to
      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
      return;
    }

    window.addEventListener('load', () => {
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

      if (!isLocalhost) {
        // Is not local host. Just register service worker
        registerValidSW(swUrl);
      } else {
        // This is running on localhost. Lets check if a service worker still exists or not.
        checkValidServiceWorker(swUrl);
      }
    });
  }
}

function registerValidSW(swUrl) {
  navigator.serviceWorker
    .register(swUrl)
    .then(registration => {
      registration.onupdatefound = () => {
        const installingWorker = registration.installing;
        installingWorker.onstatechange = () => {
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              // At this point, the old content will have been purged and
              // the fresh content will have been added to the cache.
              // It's the perfect time to display a "New content is
              // available; please refresh." message in your web app.
              console.log('New content is available; please refresh.');
            } else {
              // At this point, everything has been precached.
              // It's the perfect time to display a
              // "Content is cached for offline use." message.
              console.log('Content is cached for offline use.');
            }
          }
        };
      };
    })
    .catch(error => {
      console.error('Error during service worker registration:', error);
    });
}

function checkValidServiceWorker(swUrl) {
  // Check if the service worker can be found. If it can't reload the page.
  fetch(swUrl)
    .then(response => {
      // Ensure service worker exists, and that we really are getting a JS file.
      if (
        response.status === 404 ||
        response.headers.get('content-type').indexOf('javascript') === -1
      ) {
        // No service worker found. Probably a different app. Reload the page.
        navigator.serviceWorker.ready.then(registration => {
          registration.unregister().then(() => {
            window.location.reload();
          });
        });
      } else {
        // Service worker found. Proceed as normal.
        registerValidSW(swUrl);
      }
    })
    .catch(() => {
      console.log(
        'No internet connection found. App is running in offline mode.'
      );
    });
}

export function unregister() {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.ready.then(registration => {
      registration.unregister();
    });
  }
}

【问题讨论】:

标签: react-redux offline-caching create-react-app progressive-web-apps


【解决方案1】:

我正在使用 Create-react-app 版本 3。

更改条件语句,删除代码 (process.env.NODE_ENV === 'production' &&) 它应该只有 if('serviceWorker' in navigator)。

在公用文件夹中创建您的 custom-service-worker 文件,将以下代码重写为 const swUrl = ${process.env.PUBLIC_URL}/service-worker.js as swUrl = ./custom-service-worker.js。

在 public 文件夹的 custom-service-worker.js 文件中添加以下代码,请参考示例外部 api 调用(将您的 api url 放置为缓存)

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

        if (workbox) {
                console.log('workbok loaded', workbox.routing)
        }

        //to cache the css html js and images files
        workbox.routing.registerRoute(
                /\.(?:js|html|css|images|svg)$/,
                new workbox.strategies.NetworkFirst()

        );
        workbox.routing.registerRoute(
                'http://localhost:3000',
                new workbox.strategies.NetworkFirst()
        );

        //to cache the external api calls
        workbox.routing.registerRoute(
                new RegExp('https://jsonplaceholder.typicode.com/users'),
                new workbox.strategies.StaleWhileRevalidate()
        );

        //to cache the external api calls
        workbox.routing.registerRoute(new RegExp('http://insight.dev.schoolwires.com/HelpAssets/C2Assets/C2Files/C2ImportUsersSample.csv'),
                new workbox.strategies.StaleWhileRevalidate()
        );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-22
    • 1970-01-01
    • 2019-02-22
    • 2018-11-21
    • 2017-02-05
    • 2019-02-16
    • 1970-01-01
    • 2018-03-12
    相关资源
    最近更新 更多