小编典典

使用服务人员和推送通知进行响应

reactjs

初步考虑:

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

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

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


阅读 264

收藏
2020-07-22

共1个答案

小编典典

可以使用Create React App自定义您的服务人员,但这可能非常困难且棘手。

开箱即用,CRA使用针线GenerateSW的WebPack插件生成service- worker.js的文件,你不能注入任何代码,它(你可能与CRA
@ 1,不宜与CRA以来@ 2更多)

您有几种策略,我将从最简单的策略开始。

解决方案1:提供您自己的服务人员文件

  • 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

  • public/文件夹中,创建custom-service-worker.js文件。的WebPack会复制它 的是build/文件夹

优点 :快速,肮脏的胜利

缺点 :您的自定义文件未使用Webpack处理(没有导入),并且由于绕过Workbox插件,您必须自己实现网络缓存逻辑(假设您需要PWA)

解决方案2:将代码附加到生成的服务人员

有一个模块: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-scriptsreact-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的配置(用于主应用程序的配置)。有待测试。

2020-07-22