This is related to my previous question and the response I got about using the chrome.offscreen API.
I am working to adapt the example from this repository into my React / Vite app.
I created an offscreen.html
page and added it as an entry point in my vite.config.js
:
import { defineConfig } from 'vite';
import { fileURLToPath } from 'url';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
optimizeDeps: {
include: ['@supabase/supabase-js'],
},
build: {
outDir: 'dist',
rollupOptions: {
input: {
index: './index.html',
offscreen: './offscreen.html',
background: fileURLToPath(new URL('./public/background.js', import.meta.url)),
},
},
},
define: {
'process.env': {},
},
});
I added the permission in my manifest.json
:
{
"name": "Supabase Chrome Extension",
"version": "0.0.1",
"description": "",
"manifest_version": 3,
"author": "cpppatrick",
"icons": {
"16": "extension_icon16.png",
"32": "extension_icon32.png",
"48": "extension_icon48.png",
"128": "extension_icon128.png"
},
"action": {
"default_popup": "index.html",
"default_title": "Open extension"
},
"background": {
"service_worker": "background.js",
"type": "module"
},
"permissions": ["tabs", "storage", "offscreen"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"]
}
],
"externally_connectable": {
"matches": ["http://127.0.0.1:5173/*", "https://127.0.0.1:5173/*"]
}
}
I updated my background.js
to create the offscreen document and send a message to it when a user signs in to my web app:
const OFFSCREEN_DOCUMENT_PATH = '/offscreen.html';
async function sendMessageToOffscreenDocument(type, data) {
if (!(await hasDocument())) {
try {
await chrome.offscreen.createDocument({
url: OFFSCREEN_DOCUMENT_PATH,
reasons: [chrome.offscreen.Reason.LOCAL_STORAGE],
justification: 'Use localStorage',
});
} catch (error) {
console.error(error);
}
}
setTimeout(() => {
console.log('in setTimeout', type, data);
chrome.runtime.sendMessage({
type,
target: 'offscreen',
data,
});
}, 2000);
}
async function closeOffscreenDocument() {
if (!(await hasDocument())) {
return;
}
await chrome.offscreen.closeDocument();
}
async function hasDocument() {
const matchedClients = await clients.matchAll();
for (const client of matchedClients) {
if (client.url.endsWith(OFFSCREEN_DOCUMENT_PATH)) {
return true;
}
}
return false;
}
chrome.runtime.onMessageExternal.addListener(async ({ message, session }) => {
if (message === 'SIGN_IN') {
sendMessageToOffscreenDocument('setUserSession', { message, session });
} else if (message === 'SIGNED_OUT') {
console.log('Handle sign out');
}
});
I created an offscreen.js
file that is loaded by the offscreen.html
page:
import { createClient } from '../node_modules/@supabase/supabase-js';
// This console.log never runs.
console.log('offscreen is loaded');
chrome.runtime.onMessage.addListener(handleMessages);
async function handleMessages(message) {
console.log('handleMessages message', message);
// Return early if this message isn't meant for the offscreen document.
if (message.target !== 'offscreen') {
return false;
}
// Dispatch the message to an appropriate handler.
switch (message.type) {
case 'setUserSession':
setUserSession(message.data);
break;
default:
console.warn(`Unexpected message type received: '${message.type}'.`);
return false;
}
}
async function setUserSession(sessionData) {
console.log('sessionData', sessionData);
}
const options = {
auth: {
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
storage: {
async getItem(key) {
const storage = await chrome.storage.local.get(key);
return storage?.[key];
},
async setItem(key, value) {
await chrome.storage.local.set({
[key]: JSON.parse(value),
});
},
async removeItem(key) {
await chrome.storage.local.remove(key);
},
},
},
};
export const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY,
options
);
I get the following error when I send a message to my extension after logging into my web app:
Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.
I don't know how to proceed with debugging this error. I can see that the offscreen document is being created, I have it logged in the above image.
In the extension details page, I see that there are two different views. But when I click on offscreen.html
, it takes me to the background.js
Service Worker inspector, and there is no other option in the dropdown menu on Chrome DevTools.
Is there something wrong in my setup that is causing the connection to not be made? I've been researching other SO answers related to this error message but haven't found anything that solves my problem.
Update: I tried to rework my code to match the example here, since the code is different from what is in the GitHub repo, and I'm still getting the same error.