vite-plugin-firebase-messaging-sw
v0.3.0
Published
Vite plugin to generate a Firebase Cloud Messaging service worker with env-aware configs and dev no-store preview.
Maintainers
Readme
vite-plugin-firebase-messaging-sw
Generate a Firebase Cloud Messaging (FCM) service worker for any Vite app — env-aware config, a no-store dev preview that honors your Vite
base, and zero runtime dependencies.
Features
- 🔧 Generates
firebase-messaging-sw.jsat build time (emitted to your buildoutDir). - 🧪 Dev preview with
no-store+ weakETag, served under your Vitebase. - 🔑 Firebase config inline, via a context function, or from
FIREBASE_*env vars. - 📊 Optional analytics hooks for impression / open tracking.
- 💾 Optional on-disk mirror (
outputDir) for frameworks that serve a static folder. - 🪶 Built-in light minifier; full
transform(code)escape hatch. - 🟢 Zero runtime dependencies.
Installation
npm i -D vite-plugin-firebase-messaging-sw
# or: pnpm add -D vite-plugin-firebase-messaging-sw
# or: yarn add -D vite-plugin-firebase-messaging-swRequires Node ≥ 18 and Vite ≥ 4.
Usage
// vite.config.ts
import { defineConfig } from 'vite';
import { generateFirebaseMessagingSw } from 'vite-plugin-firebase-messaging-sw';
export default defineConfig({
plugins: [
generateFirebaseMessagingSw({
firebase: {
apiKey: process.env.FIREBASE_API_KEY!,
authDomain: process.env.FIREBASE_AUTH_DOMAIN!,
projectId: process.env.FIREBASE_PROJECT_ID!,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET!,
messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID!,
appId: process.env.FIREBASE_APP_ID!,
measurementId: process.env.FIREBASE_MEASUREMENT_ID, // optional
},
outputDir: 'static', // optional: SvelteKit serves /static at the site root
analytics: {
impressionUrl: 'https://your-tracker/impression',
openUrl: 'https://your-tracker/open',
},
}),
],
});| Phase | Behavior |
|-------|----------|
| dev (vite) | Served at the SW route under your Vite base with Cache-Control: no-store + weak ETag. The SW is built once per dev session (stable across requests). |
| build (vite build) | Emitted as a build asset to the root of your build outDir. |
| outputDir | Also written to disk (dev & build), skipped when unchanged. |
The Firebase service worker must be served from the site root for FCM to register it. If you deploy under a sub-path or your build root differs from your web root, use
outputDir(e.g."static"/"public") to place it where it'll be served at/firebase-messaging-sw.js.
Config from environment variables
Any field omitted from firebase falls back to the matching env var, so you can pass firebase: {} and rely entirely on the environment:
| Field | Env var |
|-------|---------|
| apiKey | FIREBASE_API_KEY |
| authDomain | FIREBASE_AUTH_DOMAIN |
| projectId | FIREBASE_PROJECT_ID |
| storageBucket | FIREBASE_STORAGE_BUCKET |
| messagingSenderId | FIREBASE_MESSAGING_SENDER_ID |
| appId | FIREBASE_APP_ID |
| measurementId | FIREBASE_MEASUREMENT_ID |
Explicit firebase values win over env vars. If any required field is still missing, the plugin throws with the exact list of missing fields.
Per-environment config
generateFirebaseMessagingSw({
firebase: ({ mode }) =>
mode === 'production' ? prodFirebaseConfig : devFirebaseConfig,
});Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| firebase | FirebaseConfig \| (ctx) => FirebaseConfig | required | Firebase web config or a resolver. ctx is { mode, command, config }. |
| filename | string | "firebase-messaging-sw.js" | Output filename. |
| outputDir | string | — (no mirror) | Also write the SW to this directory on disk. |
| firebaseCompatVersion | string | "9.22.2" | Firebase compat SDK version loaded from the gstatic CDN. Bump to a newer release as needed. |
| meta.appEnv | string | current mode | Arbitrary environment label embedded in the SW. |
| meta.target | string | "web" | Arbitrary target label. |
| analytics | FcmAnalytics | { srcParam: 'src', cidParam: 'cid', srcValue: 'fcm' } | Tracking endpoints + query-param names. |
| minify | boolean | true in production | Apply the built-in light minifier. |
| transform | (code: string) => string | — | Final transform over the generated SW (runs after minify — plug in your own minifier here if you want). |
FirebaseConfig
type FirebaseConfig = {
apiKey: string;
authDomain: string;
projectId: string;
storageBucket: string;
messagingSenderId: string;
appId: string;
measurementId?: string;
};Generated output (excerpt)
/* Auto-generated at 2025-09-09T13:45:00.000Z */
importScripts("https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.22.2/firebase-messaging-compat.js");
(function(){
const firebaseConfig = { /* your config */ };
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.onBackgroundMessage((payload) => {
self.registration.showNotification(
payload.notification?.title || "Notification",
{ body: payload.notification?.body || "", data: payload.data || {} }
);
});
self.addEventListener("notificationclick", (event) => {
event.notification.close();
event.waitUntil(clients.openWindow(event.notification?.data?.url || "/"));
});
})();The firebase/analytics values are safely escaped before being embedded, so URLs containing quotes or backslashes won't break the generated script. Customize the handlers via transform(code).
License
MIT © dev.zarghami
