typescript 使用VITE设置Firebase消息服务工作者的正确方法

cgh8pdjw  于 2023-04-13  发布在  TypeScript
关注(0)|答案(1)|浏览(168)

我有一个使用SolidJS,typescript和Vite构建的项目。我已经有一个使用vite PWA插件的服务工作者,使用生成服务工作者策略。现在我想使用Firebase云消息添加通知(FCM)和他们的文档指导您创建一个非常simple file that is meant to be bundled as a service worker.这是一个挑战,因为Vite并不真正意味着要与多个入口点一起使用,这在某种程度上是正确地包括该文件所必需的。
我尝试了几种方法,但我对其中任何一种都不满意。所有的方法都很粗糙,似乎都不是最佳的。以下是我尝试过的方法,按成功率从高到低排列。

使用injectManifest策略添加另一个vite PWA插件示例。

这是我目前使用的策略,因为它在方便性和作为一个工作解决方案之间取得了最佳平衡。在vite-pwa-plugin documentation中没有一行说使用多个插件示例是可能的或鼓励的,但也没有任何反对它的地方。所以我做的是示例化插件两次,一次是我的应用程序使用的“合法/真实的”服务工作者,另一个使用inject manifest策略捆绑所需的firebase-messaging-sw.js服务工作者:
Vite配置:

export default defineConfig({
plugins: [
// Abuse the plugin API to bundle the messaging service worker
    VitePWA({
      strategies: 'injectManifest',
      srcDir: 'src',
      filename: 'firebase-messaging-sw.ts',
      workbox: {
        globPatterns: [],
        globIgnores: ['*'],
      },
    }),
// Real legit service worker for my app
    VitePWA({
      registerType: 'autoUpdate',
      devOptions: { enabled: true },
      // minimum PWA
      includeAssets: ['favicon.ico', 'robots.txt', '*.svg', '*.{png,ico}'],
      workbox: { 
      // bla bla bla

Service worker文件firebase-messaging-sw.js

// Import and configure the Firebase SDK
import { initializeApp } from 'firebase/app';
import { getMessaging } from 'firebase/messaging/sw';
import firebaseConfig from './firebase-config.json';
// Line below makes typescript happy by importing the definitions required for ServiceWorkerGlobalScope
import { precacheAndRoute as _ } from 'workbox-precaching';

declare let self: ServiceWorkerGlobalScope;

const firebaseApp = initializeApp(firebaseConfig);
getMessaging(firebaseApp);
console.info('Firebase messaging service worker is set up');
// If we don't include a point to inject the manifest the plugin will fail.
// Using just a variable will not work because it is tree-shaked, we need to make it part of a side effect to prevent it from being removed
console.log(self.__WB_MANIFEST);

正如你所看到的,这种方法似乎是在滥用插件API,并且有一些讨厌的副作用,除了防止捆绑失败之外,没有任何目的。然而,它工作,不需要单独的构建文件或配置,并且它的所有内容都在一个vite配置中。讨厌,但方便

创建自己的插件,单独捆绑service worker

我尝试创建一个本地插件来处理firebase-messaging-sw.js文件的导入,并将其作为单独的块发出。但是,当文件注册为service worker时,我会收到错误,因为文件被捆绑在一起,就好像它是应用程序的一部分,因此,它依赖于在service worker环境中不可用的bundle功能(如导入)。插件代码看起来像这样:

import { Plugin } from 'vite';
const print = (obj) => console.dir(obj, { depth: 8 });
export function renameFirebaseSw(): Plugin {
  const virtualId = 'virtual:firebase-messaging-sw';
  const resolvedVirtualModuleId = '\0' + virtualId;
  return {
    name: 'vite:rename-firebase-sw',
    // enforce: 'post',
    resolveId(id) {
      if (id === virtualId) return resolvedVirtualModuleId;
    },
    buildStart() {
      print('start');
    },
    load(id) {
      if (id === resolvedVirtualModuleId) {
        const ref1 = this.emitFile({
          type: 'chunk',
          fileName: 'firebase-messaging-sw.js',
          id: './src/firebase-messaging-sw.ts',
        });
        console.log({ ref1 });
        return `export default import.meta.ROLLUP_FILE_URL_${ref1}`;
      }
    },
  };
}

然后,您从应用程序中的任何位置导入虚拟模块,插件将拦截它并发出一个单独的块和消息传递服务工作者文件。正如我之前提到的,这没有正确地捆绑服务工作者代码并失败,更不用说它在开发中不起作用,只有在为生产构建时才起作用

vite配置独立

最后,你可以使用一个单独的vite配置来捆绑service worker文件,这种方法看起来是最干净的,因为你只是把service worker代码捆绑起来,就像它是一个单独的应用一样问题是您需要确保输出名称是正确的(没有哈希值,并且导入/注册它的应用程序使用相同的名称),以确保您始终运行主应用程序构建步骤和服务工作者构建步骤,并在开发模式下并行运行它们。老实说,不是我想维护的东西。
是否有任何干净便捷的方法来包含云消息传递所需的服务工作者,而不会有任何提到的妥协?我做了大量的研究和调查,除了解决方案外,我什么也没找到。

ig9co6j1

ig9co6j11#

我想在我的项目两个服务工人,一个是firebase-messaging-sw.js,它没有发挥好与VitePWA,我想写他们在 typescript ,所以我最终做了一个插件像你一样转译他们,并把他们放入dist/src目录,所以他们与HMR和开发工作.仍然不是一个惊人的解决方案,但它为我工作. https://github.com/x8BitRain/vite-plugin-ts-sw-hmr
至于导入部分,我最终只是使用以下内容来导入必要的脚本以使其工作,而不是捆绑本地依赖项。

importScripts('https://www.gstatic.com/firebasejs/9.5.0/firebase-app-compat.js')
importScripts(
  'https://www.gstatic.com/firebasejs/9.5.0/firebase-messaging-compat.js'
)

相关问题