Preload scripts not being executed in webview iframes

Viewed 1961

Webview tag that is present in the renderer process, somewhere in <body>:

<webview src="http://somewebpage.com" preload="somescript.js">

somescript.js is executed in somewebpage, but if somewebpage has <iframe>s in it, the script will not run in the iframe.

How can I make it run? And before any other script in the iframe?

I found this issue on github that seems related: https://github.com/electron/electron/pull/19260 but it doesn't make any sense...

I tried adding nodeintegrationinsubframes and changing values from false to true

<webview src="somewebpage" preload="somescript.js" nodeintegrationinsubframes="false">

but it has no effect :(

3 Answers

main.js

mainWindow = new BrowserWindow({
    width: 1024,
    height: 728,
    webPreferences: {
        nodeIntegrationInSubFrames: true,
        webviewTag: true,
        nodeIntegration: true
    }
});

renderer

<webview
            src="https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_iframe"
            preload="./preload.js"
            style='width: 100%; height: 800px'
            nodeIntegrationInSubFrames
        />

preload.js

process.once("loaded", () => {
    alert(window.location);
});

You can specify where you are going to execute javascript based on the window.location This above code will show the locations of every sub iframes.

This works for me very well.

I was having the same problems with my project and updating the electron to the latest beta version solved for me.

I assume you know how to do this:

npm install electron@11.0.0-beta.6

You still have to consider the stability concerns of using a development version of the package.

By scratching on electron's documentation perhaps this could be helpful as an alternative.

app.js

let win
app.whenReady().then(() => {
  win = new BrowserWindow({
    webPreferences: {
      nodeIntegrationInSubFrames: true,
      webviewTag: true,
      nodeIntegration: false,
      preload: path.join(app.getAppPath(), 'preload.js') // Specifies a script that will be loaded before other scripts run in the page. This script will always have access to node APIs no matter whether node integration is turned on or off. The value should be the absolute file path to the script. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope.
    }
  })
  ...
})

renderrer

<webview 
src="https://somewebpage.com" 
preload="./preload.js" 
nodeintegrationinsubframes>

preload.js

/* It can be used by the preload script to add removed Node global symbols back to the global scope when node integration is turned off */
const _setImmediate = setImmediate
const _clearImmediate = clearImmediate
process.once('loaded', () => {
  global.setImmediate = _setImmediate
  global.clearImmediate = _clearImmediate
})

My answer is based on the following resources:

Related