Firebase version: 9.6.6
firebase-messaging.js - inside a src folder
import firebase from "firebase/compat";
import "firebase/messaging";
const firebaseConfig = {
//api
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
export const requestForToken = async () => {
const swRegistration = await navigator.serviceWorker.register(`${process.env.PUBLIC_URL}/firebase-messaging-sw.js`);
const token = await messaging.getToken({
serviceWorkerRegistration: swRegistration,
});
return token;
};
export const onMessageListener = () =>
new Promise((resolve) => {
messaging.onMessage((payload) => {
resolve(payload);
});
});
firebase-messaging-sw.js - inside a public folder
import { initializeApp } from "firebase/app";
import { getMessaging } from "firebase/messaging/sw";
const firebaseApp = initializeApp({
//api
});
const messaging = getMessaging(firebaseApp);
Inside App.js
useEffect(()=> {
if (!fcm_token) {
requestForToken()
.then(r => {
console.log("token: ", r);
dispatch(setFCMToken(r));
})
.catch(error => {
console.log("error while receiver fcm token from firebase: ", error)
});
} else {
console.log("fcm token: ", fcm_token);
}
}, [])
onMessageListener()
.then(value => console.log("notification msg: ", value))
.catch(err => console.log("error: ", err))
When I run the project
Failed to register a ServiceWorker for scope ('http://localhost:3000/build/')
with script ('http://localhost:3000/build/firebase-messaging-sw.js'):
ServiceWorker script evaluation failed
this error shows up, even though the code is correct according to documentation.
Error persists even if I change the way I import inside firebase-messaging-sw.js file to "importScripts(' ')".
Only after removing everything in firebase-messaging-sw.js file, that error do not show up and I can receive the FCM token.
However, when I send test messages from firebase console to FCM token received in my react app, no messages are showing up in console.
Question: How should I change my code to be able to receive notifications and show them in console or as a notification in browser.
If you're using latest version there is alittle bit modifications in registering service worker file, this is complete process of notification configuration
register service worker as below in your service worker file:
export const registerServiceWorker = () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('firebase-messaging-sw.js')
.then(function (registration) {
return registration.scope;
})
.catch(function (err) {
return err;
});
}
};
import service worker, and call function in your index.js File:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { registerServiceWorker } from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
registerServiceWorker();
After this configuration, you will see fire base notification in console, and if firebase-messaging.js file is configured well with no error, your feature will work
Related
I created an Express.js Back-End that runs on port 4000. Also React (Vite) app runs on port 5173. I try to make some axios requests to my Back-End. Eventhough the URL looks wrong on DevTools when I make any request from my home page, it is still able to hit the Back-End and fetch the data (I can log the request on the Back-End console). But when I try to make a request from another page such as "127.0.0.1:5173/quiz", the request URL also includes "quiz". That's why I get 404.
So it shows "http://127.0.0.1:5173/quiz/api/quiz/:quizId"
But it needs to be "http://127.0.0.1:4000/api/quiz/:quizId"
But like I said, it works when I make a request on home page:
"http://127.0.0.1:5173/api/quiz" - This works, and fetches the quiz list.
Btw, to solve CORS issues, I tried to add "proxy" on package.json, but it didn't work. Then I add some configurations on vite.config.ts, it worked, but like I said I kept seeing "http://127.0.0.1:5173" on Dev Tools Network tab instead of "http://127.0.0.1:4000".
Here's my vite.config.ts:
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": {
target: "http://localhost:4000",
changeOrigin: true,
secure: false,
},
},
},
});
Here's my request code
import { useState } from "react";
import { useAuthContext } from "./useAuthContext";
import { useQuizContext } from "./useQuizContext";
import { QuizType, Types as QuizActionTypes } from "../context/quiz/types";
import axios from "axios";
export const useQuiz = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { state: authState } = useAuthContext();
const { dispatch } = useQuizContext();
const getQuiz = async (id: string) => {
setIsLoading(true);
setError(null);
const queryParams: string[] = [];
// If it's a logged in user
if (authState.user.token) {
queryParams.push(`userId=${authState.user._id}`);
}
// If it's a participant who's done with the quiz
if (localStorage.getItem("gifQuizUser")) {
queryParams.push("participantCompleted=true");
}
const uri =
queryParams.length > 0
? `api/quiz/${id}?${queryParams.join("&")}`
: `api/quiz/${id}`;
console.log(uri);
// Fetch & Dispatch
try {
const response = await axios.get(uri);
if (!response.data.error) {
dispatch({
type: QuizActionTypes.GetQuiz,
payload: response.data,
});
setIsLoading(false);
}
} catch (err: any) {
if (err.response.data.error) {
setIsLoading(false);
setError(err.response.data.error);
}
}
};
return { isLoading, error, getQuizzes, getQuiz };
};
Thank you for your time.
I am using react and electron building an electron app.
I am new to react and electron and I got a problem on how to import a function in react index.js to electron main.js
Why I need to import that function to main.js file?
Because I need to pass the dependencies of my react app from main.js and most of these dependecies are function dependencies.
Here is the function in index.js which receive the dependencies. Look at the function dependency
mport React from 'react';
import ReactDOM from 'react-dom/client';
import './App.scss'
import './configFile'
import './fonts/NotoSansSC.otf'
import { init as initConfigFile } from './configFile'
import { init as initLanguage } from './international/language'
import App from './App';
export function dependency(config, saveConfigFile, createNewUser) {
}
const root = ReactDOM.createRoot(document.getElementById('root'))
initLanguage()
initConfigFile({
parentPwd: null,
qa: {
'configQuestion1': '123',
'configQuestion2': '123',
'configQuestion3': '123'
},
timeRangesNotAllowToUseTheComputer: [
],
language: 'en',
onlyWorkForTheUsers: ['test'],
usernames: ['onTheRoad', 'test'],
timeZones: { '中国': 'cn', '英国': 'uk' },
choosedTimeZone: 'uk'
}, null, null)
root.render(
<App />
)
Here is the main.js file
const path = require('path');
const { app, BrowserWindow } = require('electron');
const isDev = require('electron-is-dev');
function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 800,
webPreferences: {
nodeIntegration: true,
},
});
// and load the index.html of the app.
// win.loadFile("index.html");
win.loadURL(`file://${path.join(__dirname, '../build/index.html')}`);
// Open the DevTools.
if (isDev) {
win.webContents.openDevTools({ mode: 'detach' });
}
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bars to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
I tried to import the file use require
const index = require('./index.js')
when I build the react app there is no error throwed but when I start the electron with electron . got error like this:
A JavaScript error occurred in the main process
Uncaught Exception:
/home/zxw/Desktop/bsd/src/index.js:1
import React from 'react';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1040:15)
at Module._compile (node:internal/modules/cjs/loader:1076:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1175:10)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:829:12)
at c._load (node:electron/js2c/asar_bundle:5:13339)
at Module.require (node:internal/modules/cjs/loader:1012:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/home/zxw/Desktop/bsd/public/main.js:4:15)
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
And then I tried to load the function by import statement like below
import {dependency} from '../src/index'
When I build react app there is no error throwed but when I start the electron app I got error like this
A JavaScript error occurred in the main process
Uncaught Exception:
/home/zxw/Desktop/bsd/public/main.js:4
import {dependency} from '../src/index'
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1040:15)
at Module._compile (node:internal/modules/cjs/loader:1076:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1175:10)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:829:12)
at c._load (node:electron/js2c/asar_bundle:5:13339)
at loadApplicationPackage (/home/zxw/Desktop/bsd/node_modules/electron/dist/resources/default_app.asar/main.js:121:16)
at Object.<anonymous> (/home/zxw/Desktop/bsd/node_modules/electron/dist/resources/default_app.asar/main.js:233:9)
at Module._compile (node:internal/modules/cjs/loader:1120:14)
libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
Is there is a way to pass the dependencies to the index.js from main.js ?
I fix it by throgh a dump way
First install the axios and the express
Then in the react src file add a file called appDependency
Here is the code
import axios from 'axios'
export function saveConfigFile(config) {
try {
axios.put('http://localhost:8888/config', config).then(response => {
if (response.status !== 200) {
throw response.data
}
})
} catch (e) {
console.error(`Error occrred while saving the config file: ${e}`)
throw e
}
}
export function createNewUser(username, pwd) {
try {
axios.post('http://localhost:8888/users', {
username: username,
pwd: pwd
}).then((response) => {
if (response.status !== 200) {
throw response.data
}
})
} catch (e) {
console.error(`Error occrred while creating new user. ${e}`)
throw e
}
}
async function fetchTheConfig() {
return await axios.get('http://localhost:8888/config').then((response) => {
console.log(`The response is ${JSON.stringify(response.data)}`)
if (response.status !== 200) {
throw response.data
} else {
return response.data
}
})
}
export function getConfigFile() {
try {
return fetchTheConfig()
} catch (e) {
console.error(`err occurred while fetching the config file. ${e}`)
throw e
}
}
And in the electron main.js file I use express created a server
const path = require('path');
const { app, BrowserWindow } = require('electron');
const express = require('express')
const exApp = express()
exApp.use(express.urlencoded())
exApp.use(express.json())
const config = {
parentPwd: null,
qa: {
'configQuestion1': '123',
'configQuestion2': '123',
'configQuestion3': '123'
},
timeRangesNotAllowToUseTheComputer: [
],
language: 'en',
onlyWorkForTheUsers: ['test'],
usernames: ['onTheRoad', 'test'],
timeZones: { '中国': 'cn', '英国': 'uk' },
choosedTimeZone: 'uk'
}
function configFile(req, res) {
console.log(`request received getConfigFile`)
res.status(200).send(config)
}
function saveConfigFile(req, res) {
console.log(`The body is ${req.body.timeRangesNotAllowToUseTheComputer}`)
res.status(200).send()
}
function createNewUser(req, res) {
console.log(`The req is `)
}
function appDependecys() {
exApp.get('/config', configFile)
exApp.put('/config', saveConfigFile)
exApp.post('/users', createNewUser)
exApp.listen(8888)
}
appDependecys()
In the react index.js I made the change to
import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.scss'
import './configFile'
import './fonts/NotoSansSC.otf'
import { init as initConfigFile } from './configFile'
import { init as initLanguage } from './international/language'
import App from './App';
import { getConfigFile, saveConfigFile, createNewUser } from './appDependency'
const root = ReactDOM.createRoot(document.getElementById('root'))
getConfigFile().then((cfg) => {
console.log(`The fucking config is ${cfg}`)
initLanguage()
initConfigFile(cfg, saveConfigFile, createNewUser)
root.render(
<App />
)
})
I'm using react-msal to my application. I need to acquire the access token and attach it to the axios globally, but unfortunately, they only provide hooks to get the access token (as far as I know).
So far, here's my api.js file.
import axios from "axios";
import { useMsal } from "#azure/msal-react";
const axiosInstance = axios.create({
baseURL: "https://localhost:4211/api",
});
const { instance, accounts } = useMsal();
instance
.acquireTokenSilent({
...loginApiRequest,
account: accounts[0],
})
.then((response) => {
axiosInstance.defaults.headers.common[
"Authorization"
] = `Bearer ${response.accessToken}`;
})
.catch((error) => {
console("Error acquiring access token");
});
export default axiosInstance;
And here's I call my API in my component.
api.get('/foods').then(response => {
alert(response.data)
}).catch(error => {
console.log(error.response)
})
But I'm getting an issue that says: Error: Invalid hook call. Hooks can only be called inside of the body of a function component. which is obvious but I need alternatives to get the access token and assign it to my axios globally as part of the header so I don't need to rewrite header each time I need to call an endpoints. Any help?
This is a React application, right?
You can't call hooks from outside of your React components, or other hooks.
https://reactjs.org/docs/hooks-rules.html
You could do something like this:
const App = () => {
const { instance, accounts } = useMsal();
useEffect(() => {
instance.acquireTokenSilent()
.then(() => {})
.catch(() => {})
},[]);
};
You can use PublicClientApplication instance passed into the MsalProvider.
To get the accounts call instance.getAllAccounts().
You can't access the inProgress value outside of a component or context, but since you're just using acquireTokenSilent you probably will not need it.
below is my working sample.
import axios from 'axios';
import * as App from '../index'
import * as utils from './utils'
const instance = axios.create({
baseURL: utils.getEndpoint(),
timeout: 15000
});
instance.interceptors.request.use(function (config) {
const instance = App.msalInstance;
const accounts = instance.getAllAccounts();
const accessTokenRequest = {
scopes: ["user.read"],
account: accounts[0],
};
return instance
.acquireTokenSilent(accessTokenRequest)
.then((accessTokenResponse) => {
// Acquire token silent success
let accessToken = accessTokenResponse.accessToken;
// Call your API with token
config.headers.Authorization = `Bearer ${accessToken}`;
return Promise.resolve(config)
})
}, function (error) {
return Promise.reject(error);
});
instance.interceptors.response.use((response) => {
if(response.status === 401) {
// Clear local storage, redirect back to login
window.location.href = "/logout"
}
return response;
}, (error) => {
return Promise.reject(error);
});
export default instance
and index.js below
import React from "react";
import ReactDOM from "react-dom";
import { PublicClientApplication, EventType } from "#azure/msal-browser";
import { msalConfig } from "./authConfig";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
export const msalInstance = new PublicClientApplication(msalConfig());
// Default to using the first account if no account is active on page load
if (!msalInstance.getActiveAccount() && msalInstance.getAllAccounts().length > 0) {
// Account selection logic is app dependent. Adjust as needed for different use cases.
msalInstance.setActiveAccount(msalInstance.getAllAccounts()[0]);
}
// Optional - This will update account state if a user signs in from another tab or window
msalInstance.enableAccountStorageEvents();
msalInstance.addEventCallback((event) => {
if (event.eventType === EventType.LOGIN_SUCCESS && event.payload.account) {
const account = event.payload.account;
msalInstance.setActiveAccount(account);
}
});
ReactDOM.render(<App pca={msalInstance} />,
document.getElementById("app"),
);
serviceWorker.unregister();
I am using Firebase for auth in my project. After user authenticates, I set his/her id token in cookies, so that next time any request is made to auth-only page, I can verify the token server-side for SSR.
However, the wrapper function I wrote for this errors out as 'ReferenceError' when used in getServerSideProps.
lib/firebase-admin.ts
import { initializeApp, App, AppOptions } from 'firebase-admin/app'
import { getAuth, Auth } from 'firebase-admin/auth'
import { credential } from 'firebase-admin'
import serviceAccount from '../secrets/firebase-admin-sdk.json'
// Firebase Admin app configs
const firebaseAdminConfig: AppOptions = {
credential: credential.cert(JSON.stringify(serviceAccount))
}
// Get app admin instance and export it
const app: App = initializeApp(firebaseAdminConfig)
export default app
// Get auth admin and export
export const auth: Auth = getAuth(app)
utils/auth-server.ts
import { auth } from '../lib/firebase-admin'
import { DecodedIdToken } from 'firebase-admin/auth'
import AuthErrorMessages from '../constants/auth'
// Export function to verify id token in server side
interface IVerifyIdToken {
status: boolean
message?: string
token?: DecodedIdToken
}
export const verifyIdToken = async (idToken: string): Promise<IVerifyIdToken> => {
try {
const decodedIdtoken = await auth.verifyIdToken(idToken, true)
console.log(decodedIdtoken)
return { status: true, token: decodedIdtoken }
} catch (e) {
return { status: false, message: e }
}
}
components/test.tsx
import { GetServerSideProps, GetServerSidePropsContext, InferGetServerSidePropsType } from 'next'
import nookies from 'nookies'
import { verifyIdToken } from '../utils/auth-server'
export const getServerSideProps: GetServerSideProps = async (ctx: GetServerSidePropsContext) => {
const cookies = nookies.get(ctx)
if (cookies.token) {
const idToken = await verifyIdToken(cookies.token) // ERROR HERE
console.log(idToken)
return {
props: {
email: 'DUMMY'
}
}
} else {
return {
props: {
email: "NO EMAIL (not logged in)"
}
}
}
}
export default function Test({ email }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<p>Your email: {email}</p>
)
}
Error while opening /test
ReferenceError: Cannot access 'auth' before initialization
at Module.auth (webpack-internal:///./lib/firebase-admin.ts:5:53)
at verifyIdToken (webpack-internal:///./utils/auth-server.ts:12:87)
at getServerSideProps (webpack-internal:///./pages/test.tsx:20:96)
at Object.renderToHTML (/home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/render.js:479:26)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async doRender (/home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/next-server.js:1392:38)
at async /home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/next-server.js:1487:28
at async /home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/response-cache.js:63:36
I fixed the problem! (thanks #ArneHugo the hint)
So, what happened was not really a cyclic dependency, but files getting compiled asynchronously, because of which there was no actual control over what got compiled first.
I fixed this by making a small change:
lib/firebase-admin.ts
.
.
.
const serviceAccount = require('../secrets/firebase-admin-sdk.json') // Earlier -> import serviceAccount from '../secrets/firebase-admin-sdk.json'
.
.
.
credential: credential.cert(serviceAccount) // Earlier -> credential: credential.cert(JSON.stringify(serviceAccount))
.
.
.
// REPLACE ENTIRE BELOW PORTION WITH THIS
// Get app admin instance and export it
if (getApps().length === 0) { // To make sure only one instance is created and referred to at a time
initializeApp(firebaseAdminConfig)
}
// Get auth admin and export
export const auth: Auth = getAuth(getApp()) // To make sure auth from only the one app instance we have is exported
I tried to implement web push notification using firebase into my REact js Project.
Index.js
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import './App.css';
import { createStore, compose, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension/developmentOnly";
import { Provider } from "react-redux";
import thunk from "redux-thunk";
import {messaging} from "./config/FirebaseConfig"
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import rootReducer from "./reducers/rootReducer";
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(thunk))
);
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register(`./firebase-messaging-sw.js`)
.then(function(registration) {
messaging.useServiceWorker(registration);
console.log("Registration successful, scope is:", registration.scope);
})
.catch(function(err) {
console.log("Service worker registration failed, error:", err);
});
}
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
serviceWorker.register();
Above file is the main source file which is located into src folder.
I added firebase-messaging-sw.js like as below:
importScripts("https://www.gstatic.com/firebasejs/5.9.4/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/5.9.4/firebase-messaging.js");
firebase.initializeApp({
messagingSenderId: "XXXXXX",
});
const messaging = firebase.messaging();
messaging.usePublicVapidKey("XXXXXXXXXXXXXXXXXXXXX")
messaging.setBackgroundMessageHandler(function(payload) {
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
return registration.showNotification("my notification title");
});
return promiseChain;
});
self.addEventListener('notificationclick', function(event) {
// do what you want
// ...
});
I added request permission code on the amount method of the Main component and it looks like as below:
componentDidMount()
{
messaging.requestPermission()
.then(async function() {
const token = await messaging.getToken();
console.log("token", token)
})
.catch(function(err) {
console.log("d to get permission to notify.", err);
});
navigator.serviceWorker.addEventListener("message", (message) => console.log(message));
messaging.onMessage((payload) => console.log('Message received. ', payload));
const fetchOptions = {
method: "POST",
headers: {
"Authorization": "key=l9oalOyzXcU-NqCI4LZyVrLuF3X3_4tiOHpMUYK_AxC4G...",
"Content-Type": "application/json"
},
body: JSON.stringify({
to:"e56_nKx5Ejm1HyWHKcvZFq:APA91bH-...-nKE9YEILYu7RQBBiyCs_CUo2IC0DX-87cMgmMcYwvYQ1yg0BmqWfAgbbkfPtfzXGGOdzmvxVX2wBlwhnnK5oUxjtXalQ4T5CM7IQOhertbXc",
notification : {
"title": "Message recieived from:",
"body": message,
"click_action": "http://localhost:3000/",
"icon": "http://url-to-an-icon/icon.png"
},
})
}
fetch("https://fcm.googleapis.com/fcm/send", fetchOptions)
.then(response =>console.log(response))
.then(data => console.log(data));
}
Also add the code for serviceWorker.js file which is used in index.js file
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more,'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
I am running the application on port 3000 and I can see that google chrome will throw the error like :
Service worker registration failed. I don't know what I did wrong.
Would you please help me to resolve the issue? Also, let me know if you require anything else from me.
1.you should use onBackgroundMessage instead setBackgroundMessageHandler in firebase-messaging-sw.js
2.put
export const initializeFirebase = () => {
firebase.initializeApp({
apiKey: "***",
authDomain: "***",
databaseURL: "***",
projectId: "***",
storageBucket: "***",
messagingSenderId: "***",
appId: "***",
measurementId: "G-***"
});
const messaging = firebase.messaging();}
and
export const askForPermissioToReceiveNotifications = async (registration) => {
try {
const messaging = firebase.messaging();
await messaging.onMessage(notification => {
console.log('Notification received!', notification);
message.info(notification?.data?.title + ':' + notification?.data?.body)
});
const registration = await navigator.serviceWorker
.register('firebase-message-sw.js', {scope: "/", updateViaCache: 'none'})
.then((registration) => {
return registration;
}).catch(e => {
});
await Notification.requestPermission().then((callBack) => {
console.log(callBack)
}).catch(e => {
});
const token = await messaging.getToken({
vapidKey: 'BML-',
serviceWorkerRegistration: registration
});
await //send token
console.log('token do usuário:', token);
return token;
} catch (error) {
console.error(error);
}}
in your firebase.js file
3.call initializeFirebase() and askForPermissioToReceiveNotifications() in index.js before serviceworker.register();
it works well for me ...