我有一个使用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代码捆绑起来,就像它是一个单独的应用一样问题是您需要确保输出名称是正确的(没有哈希值,并且导入/注册它的应用程序使用相同的名称),以确保您始终运行主应用程序构建步骤和服务工作者构建步骤,并在开发模式下并行运行它们。老实说,不是我想维护的东西。
是否有任何干净便捷的方法来包含云消息传递所需的服务工作者,而不会有任何提到的妥协?我做了大量的研究和调查,除了解决方案外,我什么也没找到。
1条答案
按热度按时间ig9co6j11#
我想在我的项目两个服务工人,一个是firebase-messaging-sw.js,它没有发挥好与VitePWA,我想写他们在 typescript ,所以我最终做了一个插件像你一样转译他们,并把他们放入dist/src目录,所以他们与HMR和开发工作.仍然不是一个惊人的解决方案,但它为我工作. https://github.com/x8BitRain/vite-plugin-ts-sw-hmr
至于导入部分,我最终只是使用以下内容来导入必要的脚本以使其工作,而不是捆绑本地依赖项。