disfunction to send message from an iframe page to background and others
wrap one of the extension pages as an iframe is an new extension design pattern, which is recommended by quasar. but there are some communication problems when I use webext-bridge to this pattern.
for example, I use the options/index.html as the iframe page, (https://github.com/antfu/vitesse-webext as the base template)
so, in contentScripts/index.ts
const iFrame = document.createElement('iframe')
const defaultFrameHeight = '200px'
/**
* Set the height of our iFrame housing our BEX
* @param height
*/
const setIFrameHeight = (height) => {
iFrame.height = height
}
/**
* Reset the iFrame to its default height e.g The height of the top bar.
*/
const resetIFrameHeight = () => {
setIFrameHeight(defaultFrameHeight)
}
/**
* The code below will get everything going. Initialize the iFrame with defaults and add it to the page.
* @type {string}
*/
iFrame.id = 'bex-app-iframe'
iFrame.width = '100%'
resetIFrameHeight()
// Assign some styling so it looks seamless
Object.assign(iFrame.style, {
position: 'fixed',
top: '0',
right: '0',
bottom: '0',
left: '0',
border: '0',
// scrolling: 'no',
allowfullscreen: 'true',
zIndex: '9999999', // Make sure it's on top
overflow: 'visible',
})
iFrame.src = browser.runtime.getURL('dist/options/index.html')
document.body.prepend(iFrame)
then, in options/index.html, I add an button of which the handler function is test to start the sendmessage test
async function test(){
console.group('webext-bridge')
const result = await sendMessage('test', 'ping')
console.log(result)
console.groupEnd('webext-bridge')
}
in background.ts
onMessage('test', async (payload) => {
console.log(payload)
return 'pong'
})
send I open an new page and clicked the test button in the iframe some times, the console show as the follow:

console of background (nothing!)
it proved that it's failed to send messages to background.
that I open the options/index.html directly through the menu on popup icon. and replay the test again.
this time, it's successful.
console of options/index.html

console of background

@antfu @zikaari How can I do to enable the communication from an iframe to background with webext-bridge?
I found in such context that the portId has the format option.[frameId], which can't be parsed by function parseEndpoint correctly.
internal.ts line: 104:
if (context === 'background') {
browser.runtime.onConnect.addListener((incomingPort) => {
// when coming from devtools, it's should pre-fabricated with inspected tab as linked tab id
let portId = incomingPort.name || `content-script@${incomingPort.sender.tab.id}`
const portFrame = incomingPort.sender.frameId
if (portFrame)
portId = `${portId}.${portFrame}`
...
for example: the result of parseEndpoint("options.123") is {context: undefined, tabId: NaN, frameId: undefined} which can't be handled by the program well. (it only consider the situations such as [email protected] which can be parsed to {context: 'options', tabId: 567, frameId: 123})
so I temporarily modified two places of code:
internal.ts
line: 108
let portId = incomingPort.name || `content-script@${incomingPort.sender.tab.id}`
const portFrame = incomingPort.sender.frameId
change to
const portTabId = incomingPort.sender?.tab?.id
if (portId === 'options' && portTabId)
portId = `${portId}@${portTabId}`
const portFrame = incomingPort.sender.frameId
line 212:
let resolvedDestination = ['popup', 'options'].includes(destName)
? destName
: (`${(destName === 'window' ? 'content-script' : destName)}@${(destTabId || srcTabId)}`)
change to
let resolvedDestination = ['popup', 'options'].includes(destName)
? `${destName}@${destTabId}`
: (`${(destName === 'window' ? 'content-script' : destName)}@${(destTabId || srcTabId)}`)
now, send message from an iframe to background can effects!
I found in such context that the portId has the format
option.[frameId], which can't be parsed by function parseEndpoint correctly.
internal.tsline: 104:if (context === 'background') { browser.runtime.onConnect.addListener((incomingPort) => { // when coming from devtools, it's should pre-fabricated with inspected tab as linked tab id let portId = incomingPort.name || `content-script@${incomingPort.sender.tab.id}` const portFrame = incomingPort.sender.frameId if (portFrame) portId = `${portId}.${portFrame}` ...for example: the result of parseEndpoint("options.123") is
{context: undefined, tabId: NaN, frameId: undefined}which can't be handled by the program well. (it only consider the situations such as[email protected]which can be parsed to{context: 'options', tabId: 567, frameId: 123})so I temporarily modified two places of code:
internal.tsline: 108
let portId = incomingPort.name || `content-script@${incomingPort.sender.tab.id}` const portFrame = incomingPort.sender.frameIdchange to
const portTabId = incomingPort.sender?.tab?.id if (portId === 'options' && portTabId) portId = `${portId}@${portTabId}` const portFrame = incomingPort.sender.frameIdline 212:
let resolvedDestination = ['popup', 'options'].includes(destName) ? destName : (`${(destName === 'window' ? 'content-script' : destName)}@${(destTabId || srcTabId)}`)change to
let resolvedDestination = ['popup', 'options'].includes(destName) ? `${destName}@${destTabId}` : (`${(destName === 'window' ? 'content-script' : destName)}@${(destTabId || srcTabId)}`)now, send message from an iframe to background can effects!
This is a good find. You should create a pull request for this change.