swyxio / swyxdotio

This is the repo for swyx's blog - Blog content is created in github issues, then posted on swyx.io as blog pages! Comment/watch to follow along my blog within GitHub
https://swyx.io
MIT License
325 stars 43 forks source link

How to allow popups in dynamically created webviews in Electron.js #487

Closed swyxio closed 10 months ago

swyxio commented 10 months ago

category: note slug: electron-webview-popups

My smol menubar project utilizes Electron's special webview tag to dynamically generate a list of sub browser windows for chat. For the last couple months I've had an issue with the SSO popups in this, namely that they just don't work at all, presumably because Electron blocks popups for you by default.

Electron's webview has an allowpopups tag that allows this if you make the webview statically, but if you add it dynamically this fails to work.

const webview = document.createElement('webview');
webview.id = provider.webviewId;
webview.src = provider.url;
webview.setAttribute('allowpopups', 'true'); // adding dynamically...

I also have it here:

import { ProviderInterface } from 'lib/types';

export default function Pane({ provider }: { provider: ProviderInterface }) {
    return (
        <div key={provider.paneId()} className="page darwin">
            <webview
                // @ts-ignore - we need this to be here or it will not show up in electron and then the allowpopups doesnt work
                allowpopups="true"
                id={provider.webviewId}
                src={provider.url}
                useragent={
                    provider.getUserAgent() ? provider.getUserAgent() : undefined
                }
            />
        </div>
    );
}

but produces a TypeError: this._windowOpenHandler is not a function error.

image

naively using setWindowOpenHandler does not seem to work.

After about half an hour of searching I found this stackoverflow answer. Commenting here for others to find.

The solution is that you have to set it inside of your main process:

    app.on('web-contents-created', (e, wc) => {
        // wc: webContents of <webview> is now under control
        wc.setWindowOpenHandler((handler) => {
                return {action : "allow"}; // deny or allow
        });
    });

PR Here: https://github.com/smol-ai/menubar/pull/116/commits/89585ee94f27760e220efee5dc03e5480b8ca078