How do I message from background to my content script?

background.tsx
chrome.webNavigation.onCompleted.addListener(async(details) => {
if(details.frameType == "outermost_frame"){
console.info("The user has loaded my favorite website!");
console.log(details)
const tabId = details.tabId
chrome.tabs.sendMessage(tabId, {message: "Message from background script"}, function (response) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
} else {
console.log('Message sent to content script:');
}
});
}
}, filter);
chrome.webNavigation.onCompleted.addListener(async(details) => {
if(details.frameType == "outermost_frame"){
console.info("The user has loaded my favorite website!");
console.log(details)
const tabId = details.tabId
chrome.tabs.sendMessage(tabId, {message: "Message from background script"}, function (response) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
} else {
console.log('Message sent to content script:');
}
});
}
}, filter);
content.tsx
const handleMessage = (message, sender, sendResponse) => {
console.log('Message received in content.jsx:', message);
sendResponse({message: "Response from content.jsx"})
}
React.useEffect(() => {
console.log('content is loaded')
chrome.runtime.onMessage.addListener(handleMessage)
return () => {
chrome.runtime.onMessage.removeListener(handleMessage);
};
}, [])
const handleMessage = (message, sender, sendResponse) => {
console.log('Message received in content.jsx:', message);
sendResponse({message: "Response from content.jsx"})
}
React.useEffect(() => {
console.log('content is loaded')
chrome.runtime.onMessage.addListener(handleMessage)
return () => {
chrome.runtime.onMessage.removeListener(handleMessage);
};
}, [])
I want to send the tab details from my background to the content script. Any help is really appreciated. I'm so tired of trying to do this.
13 Replies
AB7zz
AB7zzOP•15mo ago
ive seen docs on how to send feom content to background. But Id really like it if someone helped me with background to content
filthytone
filthytone•15mo ago
Plasmo Docs
Messaging API – Plasmo
The Plasmo messaging API is a powerful tool for sending real-time messages between different parts of your extension.
filthytone
filthytone•15mo ago
look at Ports
AB7zz
AB7zzOP•15mo ago
@filthytone I'm trying to do as it says in the docs for ports. I'm facing this error when using const mailPort = usePort("mail"). It says
Argument of type 'string' is not assignable to parameter of type 'never'.
Argument of type 'string' is not assignable to parameter of type 'never'.
with a red underline below "mail". So when I Ctrl+left clicked usePort and when inside node_modules/@plasmohq/messaging/dist/hook.d.ts and checked the definition for usePort, it looks like this
declare const usePort: PlasmoMessaging.PortHook;
/**
* TODO: Perhaps add a way to detect if this hook is being used inside CS?
*/
declare const usePort: PlasmoMessaging.PortHook;
/**
* TODO: Perhaps add a way to detect if this hook is being used inside CS?
*/
Thats it? But on github it looks completely different.
export const usePort: PlasmoMessaging.PortHook = (name) => {
const portRef = useRef<chrome.runtime.Port>()
const reconnectRef = useRef(0)
const [data, setData] = useState()

useEffect(() => {
if (!name) {
return null
}

const { port, disconnect } = portListen(
name,
(msg) => {
setData(msg)
},
() => {
reconnectRef.current = reconnectRef.current + 1
}
)

portRef.current = port
return disconnect
}, [
name,
reconnectRef.current // This is needed to force a new port ref
])

return {
data,
send: (body) => {
portRef.current.postMessage({
name,
body
})
},
listen: (handler) => portListen(name, handler)
}
}
/**
* TODO: Perhaps add a way to detect if this hook is being used inside CS?
*/
export const usePort: PlasmoMessaging.PortHook = (name) => {
const portRef = useRef<chrome.runtime.Port>()
const reconnectRef = useRef(0)
const [data, setData] = useState()

useEffect(() => {
if (!name) {
return null
}

const { port, disconnect } = portListen(
name,
(msg) => {
setData(msg)
},
() => {
reconnectRef.current = reconnectRef.current + 1
}
)

portRef.current = port
return disconnect
}, [
name,
reconnectRef.current // This is needed to force a new port ref
])

return {
data,
send: (body) => {
portRef.current.postMessage({
name,
body
})
},
listen: (handler) => portListen(name, handler)
}
}
/**
* TODO: Perhaps add a way to detect if this hook is being used inside CS?
*/
Please help me solve this. I'd really appreciate it
filthytone
filthytone•15mo ago
it's because you also need to define background/ports/mail.ts and then do a dev build which will generate the types for that mail port once you have that, you'll see the typescript never error go away
AB7zz
AB7zzOP•15mo ago
@filthytone yo dude. Thanks a lot!! That solved my error. I thought I had put it in
background/ports/mail.ts
background/ports/mail.ts
but instead I did
backround/ports/mail.ts
backround/ports/mail.ts
and I ran the pnpm build and loading the dev build works perfectly fine now. I'm receiving the message on both sides. So relieved!
YAGPDB.xyz
YAGPDB.xyz•15mo ago
Gave +1 Rep to @filthytone
Asif
Asif•11mo ago
hello @AB7zz can you share how you solve that? @AB7zz sure. Native messaging is not working here. Plasmo messaging system is working fine. If i use this in my content script or anywhere chrome.runtime.onMessage.addListener(function (message) { console.log("details message", message) }) I found this error Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist. Can you help me to use native messaging system
banshee
banshee•8mo ago
When I was seeing that erorr, I just removed my extension and restarted Chrome. Added the extension back and everything worked fine.
Arcane
Arcane•8mo ago
@banshee has reached level 1. GG!
m
m•4mo ago
@Asif , @banshee I am also running into the same problem - very similar to the issue described here: https://discord.com/channels/946290204443025438/1268435446942273556 any guidance? @filthytone I am trying to use the messaging flow so that a content script button triggers background scripts, and depending on response the content script is updated. Would I use ports for this? I keep getting the issue referenced here: https://discord.com/channels/946290204443025438/1268435446942273556
filthytone
filthytone•3mo ago
it depends on how long the content script will wait for some response from the backend .. if it's a small amount of time, you can probably just send a message to the background and await its response ... but if you need to do something more long running then you could use ports ... as for what issue you're getting, can you be more specific?
Quinton42
Quinton42•2mo ago
Here is the solution I use for bidirectional communication: I created a new file lib/eventStore.ts
import { Storage } from "@plasmohq/storage"

const eventStore = new Storage({
area: "local"
})

export const pub = (event: string, data: any) => {
eventStore.set(event, data)
}

export const sub = (event: string, callback: (data: any) => void) => {
eventStore.watch({
[event]: (change: { newValue: any }) => {
callback(change.newValue)
}
})
}
import { Storage } from "@plasmohq/storage"

const eventStore = new Storage({
area: "local"
})

export const pub = (event: string, data: any) => {
eventStore.set(event, data)
}

export const sub = (event: string, callback: (data: any) => void) => {
eventStore.watch({
[event]: (change: { newValue: any }) => {
callback(change.newValue)
}
})
}
`
Want results from more Discord servers?
Add your server