У меня был sw.js, который получает веб-уведомления.
Но недавно я установил vite-PWA-плагин, и теперь я не могу добавлять уведомления по умолчанию.
Как я могу настроить этот vite.config.ts для добавления в сгенерированную реализацию serviceWorker.js webpush?
vite.config.ts:
import {defineConfig} from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
import path from 'path';
import {VitePWA} from "vite-plugin-pwa";
const manifest = {
"theme_color" : "#2B2B2B",
"background_color": "#2B2B2B",
"display" : "standalone",
"scope" : "/",
"start_url" : "/farm",
"name" : "ColorBit",
"short_name" : "Mining",
"description" : "...",
"icons" : [
{
"src" : "icons/icon-192x192.png",
"sizes": "192x192",
"type" : "image/png"
},
// ...
{
"src" : "icons/maskable_icon.png",
"sizes" : "682x682",
"type" : "image/png",
"purpose": "maskable"
}
]
};
const getCache = ({ name, pattern, strategy = "CacheFirst" }: any) => ({
urlPattern: pattern,
handler: strategy,
options: {
cacheName: name,
expiration: {
maxEntries: 500,
maxAgeSeconds: 60 * 60 * 24 * 60 // 2 months
},
cacheableResponse: {
statuses: [0, 200]
}
}
});
export default defineConfig({
plugins: [
laravel({
input : [ 'resources/js/app.tsx',],
refresh: true,
}),
react({
fastRefresh: false
}),
VitePWA({
registerType: 'autoUpdate',
outDir : path.resolve(__dirname, 'public'),
manifest : manifest,
manifestFilename: 'manifest.webmanifest', // Change name for app manifest
injectRegister : false, // I register SW in app.ts, disable auto registration
workbox : {
globDirectory: path.resolve(__dirname, 'public'), // Directory for caching
globPatterns : [
'{build,images,sounds,icons}/**/*.{js,css,html,ico,png,jpg,mp4,svg}'
],
navigateFallback: null, // Say that we don't need to cache index.html
swDest : 'public/serviceWorker.js',
runtimeCaching: [
// Google fonts cache
getCache({
pattern: /^https://fonts\.googleapis\.com/.*/i,
name: "google-fonts-cache",
}),
// Google fonts api cache
getCache({
pattern: /^https://fonts\.gstatic\.com/.*/i,
name: "gstatic-fonts-cache"
}),
// Dynamic cache for assets in storage folder
getCache({
pattern: /.*storage.*/,
name: "dynamic-images-cache",
}),
]
}
})
],
resolve: {
alias : {
'@' : path.resolve(__dirname, 'resources/js'),
'@hooks' : path.resolve(__dirname, 'resources/js/hooks'),
'@assets' : path.resolve(__dirname, 'resources/js/assets/'),
'@components': path.resolve(__dirname, 'resources/js/components')
},
extensions: ['.js', '.ts', '.tsx', '.jsx'],
},
});Старая реализация webpush в sw.js:
// ^^^ Activate, Install, Fetch... ^^^
/* Webpush Notifications */
// Receive push notifications
self.addEventListener('push', function (e) {
if (!(
self.Notification &&
self.Notification.permission === 'granted'
)) {
//notifications aren't supported or permission not granted!
return;
}
if (e.data) {
let message = e.data.json();
e.waitUntil(self.registration.showNotification(message.title, {
body: message.body,
icon: message.icon,
actions: message.actions
}));
}
});
// Click and open notification
self.addEventListener('notificationclick', function(event) {
event.notification.close();
if (event.action === 'farm') clients.openWindow("/farm");
else if (event.action === 'home') clients.openWindow("/");
else if (event.action === 'training') clients.openWindow("/mining-training");
else if (event.action === 'dns') clients.openWindow("/shops/dns");
else if (event.action === 'ali') clients.openWindow("/shops/aliexpress");
else clients.openWindow("/farm");
}, false);


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Следует использовать параметр inject manifest и написать собственный serviceWorker с помощью подготовленных методов рабочего ящика (я так думаю, что документация по рабочему ящику очень плохая. Вы можете использовать некоторые методы из моей конфигурации)
vite.config.ts:
export default defineConfig({
plugins: [
laravel({
input: ['resources/js/app.tsx', ],
refresh: true,
}),
react({
fastRefresh: false
}),
VitePWA({
registerType: 'autoUpdate',
outDir: path.resolve(__dirname, 'public'),
manifest: manifest,
manifestFilename: 'manifest.webmanifest', // Change name for app manifest
injectRegister: false, // I register SW in app.ts, disable auto registration
// HERE! For custom service worker
srcDir: path.resolve(__dirname, 'resources/js/'),
filename: 'serviceWorker.js',
strategies: 'injectManifest',
workbox: {
globDirectory: path.resolve(__dirname, 'public'),
globPatterns: [
'{build,images,sounds,icons}/**/*.{js,css,html,ico,png,jpg,mp4,svg}'
],
},
})
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/js'),
'@hooks': path.resolve(__dirname, 'resources/js/hooks'),
'@assets': path.resolve(__dirname, 'resources/js/assets/'),
'@components': path.resolve(__dirname, 'resources/js/components')
},
extensions: ['.js', '.ts', '.tsx', '.jsx'],
},
// define: {
// // By default, Vite doesn't include shims for NodeJS/
// // necessary for React-joyride. And probably for another libs
// global: {},
// },
});/resouces/js/serviceWorker.js:
import {ExpirationPlugin} from 'workbox-expiration';
import {createHandlerBoundToURL, precacheAndRoute, cleanupOutdatedCaches} from 'workbox-precaching';
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response/CacheableResponsePlugin';
// Register precache routes (static cache)
precacheAndRoute(self.__WB_MANIFEST || []);
// Clean up old cache
cleanupOutdatedCaches();
// Google fonts dynamic cache
registerRoute(
/^https://fonts\.googleapis\.com/.*/i,
new CacheFirst({
cacheName: "google-fonts-cache",
plugins: [
new ExpirationPlugin({maxEntries: 500, maxAgeSeconds: 5184e3}),
new CacheableResponsePlugin({statuses: [0, 200]})
]
}), "GET");
// Google fonts dynamic cache
registerRoute(
/^https://fonts\.gstatic\.com/.*/i, new CacheFirst({
cacheName: "gstatic-fonts-cache",
plugins: [
new ExpirationPlugin({maxEntries: 500, maxAgeSeconds: 5184e3}),
new CacheableResponsePlugin({statuses: [0, 200]})
]
}), "GET");
// Dynamic cache for images from `/storage/`
registerRoute(
/.*storage.*/, new CacheFirst({
cacheName: "dynamic-images-cache",
plugins: [
new ExpirationPlugin({maxEntries: 500, maxAgeSeconds: 5184e3}),
new CacheableResponsePlugin({statuses: [0, 200]})
]
}), "GET");
// Install and activate service worker
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', () => self.clients.claim());
// Receive push notifications
self.addEventListener('push', function (e) {
if (!(
self.Notification &&
self.Notification.permission === 'granted'
)) {
//notifications aren't supported or permission not granted!
console.info('nononono')
return;
}
if (e.data) {
let message = e.data.json();
e.waitUntil(self.registration.showNotification(message.title, {
body: message.body,
icon: message.icon,
actions: message.actions
}));
}
});
// Click and open notification
self.addEventListener('notificationclick', function(event) {
event.notification.close();
if (event.action === 'farm') clients.openWindow("/farm");
else if (event.action === 'home') clients.openWindow("/");
else if (event.action === 'training') clients.openWindow("/mining-training");
else if (event.action === 'dns') clients.openWindow("/shops/dns");
else if (event.action === 'ali') clients.openWindow("/shops/aliexpress");
else if (event.action === 'avito') clients.openWindow("/avito");
else if (event.action === 'friends') clients.openWindow("/friends");
else if (event.action === 'locations') clients.openWindow("/locations");
else if (event.action === 'vk-chat') clients.openWindow("https://vk.me/join/au1/k0nOTjLasxMO6wX50QuyPfYosyWdPEI = ");
else clients.openWindow(event.action); // Open link from action
}, false);В vite-pwa-plugin есть только немного информации о возможности создания webpush - документация
Я нашел некоторый код для сервис-воркера в этом репозитории и скопировал некоторый код из старого по умолчанию, сгенерированного конфигом vite.config.ts.
Пришлось сделать это сегодня с уведомлениями Firebase. Вот что я сделал на случай, если это поможет кому-то еще в будущем
Создал файл сервис-воркера (включил полную версию, потому что мне было трудно найти информацию о том, как добавлять уведомления)
importScripts("https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/8.2.0/firebase-messaging.js");
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("../firebase-messaging-sw.js")
.then(function (registration) {
console.info("Registration successful, scope is:", registration.scope);
})
.catch(function (err) {
console.info("Service worker registration failed, error:", err);
});
}
// Initialize the Firebase app in the service worker by passing the generated config
var firebaseConfig = {
apiKey: "your apiKey",
authDomain: "your authDomain",
projectId: "you get the point by now right?",
storageBucket: "",
messagingSenderId: "",
appId: "",
};
firebase.initializeApp(firebaseConfig);
// Retrieve firebase messaging
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (payload) {
console.info("Received background message ", payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: "/images/yourLogo.png",
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
В моем (React) приложении я зарегистрировался для уведомлений переднего плана, подобных этому
import { initializeApp } from "firebase/app";
import { getMessaging, getToken, onMessage } from "firebase/messaging";
const firebaseConfig = {
apiKey: "your apiKey",
authDomain: "your authDomain",
projectId: "you get the point by now right?",
storageBucket: "",
messagingSenderId: "",
appId: "",
};
const firebaseApp = initializeApp(firebaseConfig);
const messaging = getMessaging(firebaseApp);
export const getFirebaseToken = (setTokenFound) => {
return getToken(messaging, {
vapidKey: "key is generated for you on firebase",
})
.then((currentToken) => {
if (currentToken) {
console.info("current token for client: ", currentToken);
setTokenFound(true);
// Track the token -> client mapping, by sending to backend server
// show on the UI that permission is secured
} else {
console.info("No registration token available. Request permission to generate one.");
setTokenFound(false);
// shows on the UI that permission is required
}
})
.catch((err) => {
console.info("An error occurred while retrieving token. ", err);
// catch error while creating client token
});
};
export const onMessageListener = () =>
new Promise((resolve) => {
onMessage(messaging, (payload) => {
console.info("payload", payload);
resolve(payload);
});
});
и назвал это в моем файле App.tsx следующим образом. Итак, теперь мы получаем приглашение, запрашивающее разрешение на уведомление, и мы можем видеть токен пользователя в консоли, если он принимает
getFirebaseToken(setTokenFound);
isTokenFound ? console.info("Token found") : console.info("Token not found");
onMessageListener()
.then((payload) => {
toast.success(payload.notification.title, payload.notification.body);
console.info(payload);
})
.catch((err) => console.info("failed: ", err));
В моем vite.config.js на верхнем уровне объекта, из которого я возвращаюсь defineConfig(), все, что мне нужно было сделать, это импортировать скрипт вот так
workbox: {
importScripts: ["./firebase-messaging-sw.js"],
},
Этот последний бит занял у меня больше всего времени, чтобы понять .... надеюсь, что это кому-то поможет