【问题标题】:React w/ Service Worker & Push NotificationsReact w/ Service Worker 和推送通知
【发布时间】:2019-02-19 15:58:07
【问题描述】:

一些初步考虑:

"react": "^16.8.2",
"react-scripts": "2.1.5"

我创建了一个新的 react 应用程序,我需要实现推送通知。 按照this 教程,我能够在 5 分钟内启动并运行,但现在我必须在 React 应用程序中实施相同的策略(有点)。

我面临的问题是我能够订阅 Notification API,但我不确定如何编辑 service-worker.js 文件以添加事件侦听器来捕获 push 事件 (Handle a Push Event谷歌指南中的章节)

【问题讨论】:

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


    【解决方案1】:

    使用 Create React App 自定义您的 Service Worker 是可能的,但可能非常困难和 hacky。

    开箱即用,CRA 使用 Workbox GenerateSW webpack 插件生成 service-worker.js 文件,您不能向其中注入任何代码(您 could 使用 CRA@1,自 CRA@2 起不再使用)

    你有几种策略,我从最简单的一种开始。

    解决方案 1:提供您自己的 service-worker 文件

    • src/index.js启用服务工作者:
      // serviceWorker.unregister()
      serviceWorker.register()
      
    • src/serviceWorker.js注册您的自定义文件:

      // if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
      if ('serviceWorker' in navigator) {
      
      // const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
      const swUrl = `${process.env.PUBLIC_URL}/custom-service-worker.js`;
      

      运行开发服务器时必须更改名称,CRA 为service-worker.js 提供了一个mock

    • public/ 文件夹中,创建custom-service-worker.js 文件。 Webpack 会将其原样复制到build/ 文件夹中

    优点:快速,肮脏的胜利

    缺点:你的自定义文件没有被 Webpack 处理(没有导入),你必须自己实现网络缓存逻辑(假设你想要一个 PWA),因为您正在绕过 Workbox 插件

    解决方案 2:将代码附加到生成的 service-worker

    它有一个模块:cra-append-sw。 您负责提供附加代码。

    优点:易于设置,利用 GenerateSW

    缺点:附加代码使用 Babel/Webpack 处理,但不使用 CRA 的配置(您可以选择退出)。仍然使用为您处理网络缓存的 GenerateSW。在本地开发时不确定它是否有效

    解决方案 3:在自定义 service-worker 文件中使用 Workbox

    • 应用解决方案 #1 的前两个步骤:更改 src/index.jssrc/serviceWorker.js

    • src/ 文件夹中,创建custom-service-worker.js 文件。会被 Webpack 处理,所以可以使用 ES2016/TypeScript 语法和导入模块

      /* eslint no-restricted-globals: "off" */
      import * as precaching from 'workbox-precaching'
      // your own imports
      
      if (self.__precacheManifest) {
      precaching.precacheAndRoute(self.__precacheManifest)
      }
      
      // your own code
      
    • 安装react-app-rewire

      • npm add --save-dev react-app-rewired
      • package.json 中,在"scripts" 中,将react-scripts 替换为react-app-rewired
    • 调整 webpack 配置:在根文件夹中创建 config-overrides.js

      const WebpackBeforeBuildPlugin = require('before-build-webpack')
      const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
      const path = require('path')
      const merge = require('lodash.merge')
      const fs = require('fs')
      
      // from https://www.viget.com/articles/run-multiple-webpack-configs-sequentially/
      class WaitPlugin extends WebpackBeforeBuildPlugin {
      constructor(file, interval = 100, timeout = 60e3) {
       super(function(stats, callback) {
         const start = Date.now()
      
         function poll() {
           if (fs.existsSync(file)) {
             callback()
           } else if (Date.now() - start > timeout) {
             throw Error(`Couldn't access ${file} within ${timeout}s`)
           } else {
             setTimeout(poll, interval)
           }
         }
         poll()
       })
      }
      }
      
      const swOutputName = 'custom-service-worker.js'
      const workerSource = path.resolve(__dirname, 'src', swOutputName)
      
      module.exports = {
      webpack: (config, env) => {
       // we need 2 webpack configurations:
       // 1- for the service worker file.
       //    it needs to be processed by webpack (to include 3rd party modules), and the output must be a
       //    plain, single file, not injected in the HTML page
       const swConfig = merge({}, config, {
         name: 'service worker',
         entry: workerSource,
         output: {
           filename: swOutputName
         },
         optimization: {
           splitChunks: false,
           runtimeChunk: false
         }
       })
       delete swConfig.plugins
      
       // 2- for the main application.
       //    we'll reuse configuration from create-react-app, without a specific Workbox configuration,
       //    so it could inject workbox-precache module and the computed manifest into the BUILT service-worker.js file.
       //    this require to WAIT for the first configuration to be finished
       if (env === 'production') {
         const builtWorkerPath = path.resolve(config.output.path, swOutputName)
         config.name = 'main-application'
         config.plugins.push(
           new WorkboxWebpackPlugin.InjectManifest({
             swSrc: builtWorkerPath,
             swDest: swOutputName
           }),
           new WaitPlugin(builtWorkerPath)
         )
       }
      
       // remove Workbox service-worker.js generator
       const removed = config.plugins.findIndex(
         ({ constructor: { name } }) => name === 'GenerateSW'
       )
       if (removed !== -1) {
         config.plugins.splice(removed, 1)
       } 
      
       const result = [swConfig, config]
       // compatibility hack for CRA's build script to support multiple configurations
       // https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/scripts/build.js#L119
       result.output = { publicPath: config.output.publicPath }
       return result
      }
      }
      

    优点:您可以在 service-worker 文件中使用 ES2016/TypeScript 代码。您仍然可以从 Workbox 网络缓存设施中受益,并且可以完全控制它

    缺点:复杂而脆弱,因为有多个配置破解。

    我使用了最后一个解决方案,因为我需要来自 Workbox 的缓存代码和一些 import 在我的 service worker 文件中。

    react-app-rewire-workbox 可能有助于简化 Webpack 配置(用于主应用程序的配置)。待测试。

    【讨论】:

      【解决方案2】:

      创建 React App 4 - 2020 年 10 月发布

      从 Create React App 4 开始,您可以完全控制 通过创建您自己的来自定义此服务工作者中的逻辑 src/service-worker.js 文件,或者自定义由 cra-template-pwa(或 cra-template-pwa-typescript)模板。你可以 使用 Workbox 项目中的其他模块,添加推送 通知库,或者删除一些默认的缓存逻辑。

      https://create-react-app.dev/docs/making-a-progressive-web-app/#customization

      【讨论】:

        猜你喜欢
        • 2016-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-04
        • 1970-01-01
        • 2023-03-31
        • 2016-10-30
        • 1970-01-01
        相关资源
        最近更新 更多