Integrate Electron To Existing React App That Uses API iFrame

I am attempting to make an Electron app with an existing React application, which uses the Jitsi API iFrame with a build of my own and on my own server. The video and audio work well on Windows & Linux, but then Screen Sharing does not work on any OS. I installed and tried to configure the jitsi-meet-electron-utils to setupScreenSharing but even that does not work. I followed most of the code from the jitsi-meet-electron build on Github but with no hope. Anyone knows how to make it work or if there is a good tutorial out there?

By the way, I did not use Webpack in the original React app but added it later to work with Electron but with no success.

Thanks!

Please be specific. How does it not work? Do you get the picker? Do you see any error in the JS console?

Okay so the first issue I faced was that it cannot seem to load the preload.js file. Second thing is that the file openExternalLink is returning an error, even though I copied the one in the Github repo. The last issue is that when I open a meeting, I get the error TypeError: Cannot read properties of undefined (reading 'setupRenderer') in the console.

Why not?

What error?

That’s because the preload failed, since it’s the one exposing the globals.

Basically this is how my app is structured:

  • Src folder which has all the React files
  • Public folder that has all the electron configurations, including the preload.js, openExternalLink.js, and electron.js

The electron.js file is almost the same as the one on Github for jitsi/jitsi-meet-electron, same thing with the preload.js and the openExternalLink.js.

In the root, I have the two webpack files: webpack.main.js and webpack.renderer.js.

The webpack.main.js looks like this:

const path = require('path');

module.exports = {
    target: 'electron-main',
    entry: { 
        main: './public/electron.js',
        preload: './public/preload.js' 
    },
    output: {
        path: path.resolve('./build'),
        filename: '[name].js'
    },
    node: {
        __dirname: true
    },
    externals: [ {
        '@jitsi/electron-sdk': 'require(\'@jitsi/electron-sdk\')',
        'electron-debug': 'require(\'electron-debug\')',
        'electron-reload': 'require(\'electron-reload\')'
    } ],
    resolve: {
        modules: [
            path.resolve('./node_modules')
        ]
    }
};

And the webpack.renderer.js looks like this:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {ProvidePlugin} = require('webpack')
const ELECTRON_VERSION = require('./package.json').devDependencies.electron;

module.exports = {
    // The renderer code rus in BrowserWindow without node support so we must
    // target a web platform.
    target: 'web',
    entry: { app: './src/index.js' },
    performance: {
        maxAssetSize: 1.5 * 1024 * 1024,
        maxEntrypointSize: 1.5 * 1024 * 1024
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html'
        }),
        new ProvidePlugin({
            process: 'process/browser',
        }),
    ],
    output: {
        path: path.resolve('./build'),
        filename: 'bundle.js'
    },
    node: {
        __dirname: true
    },
    module: {
        noParse: /external_api\\.js/,
        rules: [
            {
                loader: 'babel-loader',
                options: {
                    babelrc: false,
                    presets: [
                        [
                            require.resolve('@babel/preset-env'),
                            {
                                modules: false,
                                targets: {
                                    electron: ELECTRON_VERSION
                                }
                            }
                        ],
                        require.resolve('@babel/preset-flow'),
                        [require.resolve('@babel/preset-react'), {"runtime": "automatic"}]
                    ],
                    plugins: [
                        require.resolve('@babel/plugin-transform-flow-strip-types'),
                        require.resolve('@babel/plugin-proposal-class-properties'),
                        require.resolve('@babel/plugin-proposal-export-namespace-from')
                    ]
                },
                test: /\.js$/
            },
            {
                use: [
                    { loader: 'style-loader' },
                    { loader: 'css-loader' }
                ],
                test: /\.css$/
            },
            {
                use: 'file-loader',
                test: /\.png$/
            },
            {
                test: /\.svg$/,
                use: [ {
                    loader: '@svgr/webpack',
                    options: {
                        dimensions: false,
                        expandProps: 'start'
                    }
                } ]
            }
        ]
    },
    externals: [ {
        '@jitsi/electron-sdk': 'require(\'@jitsi/electron-sdk\')'
    } ],
    resolve: {
        modules: [
            path.resolve('./node_modules')
        ],
        alias: {
            process: "process/browser"
        },
    }
};

In order to build the app, I run:

webpack --config ./webpack.main.js --mode production && webpack --config ./webpack.renderer.js --mode production

It compiled successfully but upon running the app, I get these errors in the console log:

node:electron/js2c/renderer_init:73 Unable to load preload script: /home/user/myapp/electron/preload.js
(anonymous) @ node:electron/js2c/renderer_init:73
node:electron/js2c/renderer_init:73 /home/user/myapp/electron/public/openExternalLink.js:13
export function openExternalLink(link) {
^^^^^^

SyntaxError: Unexpected token 'export'
    at new Script (node:vm:100:7)
    at createScript (node:vm:257:10)
    at Object.runInThisContext (node:vm:305:10)
    at wrapSafe (node:internal/modules/cjs/loader:1027:15)
    at Module._compile (node:internal/modules/cjs/loader:1072:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1169:10)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Module._load (node:internal/modules/cjs/loader:829:12)
    at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
    at Function.o._load (node:electron/js2c/renderer_init:33:356)

Hello, i am having the same issue. does anyone know how to fix this?

Is that file required from preload.js ?

Yes, it is used here:

window.jitsiNodeAPI = {
    openExternalLink,
    setupRenderer,
    ipc: {
        on: (channel, listener) => {
            if (!whitelistedIpcChannels.includes(channel)) {
                return;
            }

            return ipcRenderer.on(channel, listener);
        },
        send: channel => {
            if (!whitelistedIpcChannels.includes(channel)) {
                return;
            }

            return ipcRenderer.send(channel);
        },
        removeListener: (channel, listener) => {
            if (!whitelistedIpcChannels.includes(channel)) {
                return;
            }

            return ipcRenderer.removeListener(channel, listener);
        }
    }
};

I managed to be able to access the preload.js file from the React part. But now when I attempt to share the screen, I get the below error:

Uncaught (in promise) Error: Called JitsiMeetElectron.obtainDesktopStreams but it is not defined

The electron file has the following:

const { 
  setupScreenSharingMain 
} = require("@jitsi/electron-sdk");

setupScreenSharingMain(mainWindow, appName, "org.myApp.myApp-meet");

And the React Jitsi component has:

this.api = new window.JitsiMeetExternalAPI(this.domain, options);
this.api.addEventListeners({
    readyToClose: () => {
        this.props.navigation('/')
        return
    }
})
window.jitsiNodeAPI.setupScreenSharingRender(this.api)

The version I use of each of the tools is:

  • Electron - 17.4.1
  • electron-builder - 22.11.11
  • React - 17.0.2

Hey @saghul , Have you had time to look into it?

Your code looks ok, not sure what is wrong. Can you please create the smallest possible test project so I can try to repro?

Alright I built a new React app with npx create-react-app and added two routes, Home and Jitsi, routed using the HashRouter. I added just 1 button to Home Page to generate a random number and navigate you to the Jitsi page.

The Jitsi page looks like this:

// import { setupScreenSharingRender } from '@jitsi/electron-sdk';
import React, { useEffect } from 'react';
import { useParams } from 'react-router-dom';

function JitsiComponent() {
    const params = useParams();

    useEffect(() => {
        if (window.JitsiMeetExternalAPI) {
            startMeet();
        } else {
            alert("Jitsi not available");
        }
    })
   
    function startMeet() {

        let isMuted = false;
        
        const options = {
            roomName: params.id,
            configOverwrite: {
                disableDeepLinking: true,
                startWithVideoMuted: isMuted,
                startWithAudioMuted: isMuted,
            },
            parentNode: document.querySelector('#meet'),
            userInfo: {
                displayName: "John Doe",
            },
        }

        let api = new window.JitsiMeetExternalAPI('<domain here>', options)
        api.addEventListeners({
            readyToClose: () => {
                this.props.navigation('/')
                return
            }
        })
        window.jitsiNodeAPI.setupRenderer(api, {
            enableRemoteControl: false,
            enableAlwaysOnTopWindow: true
        });
    }

    return (
        <>
            <div id="meet" style={{width: "100%", height: "100vh"}}></div>
        </>
    )
}

export default JitsiComponent;

The webpack files (renderer and main), electron file, and preload file, are the exact same as the ones in the Github Repo for jitsi-meet-electron.

The error I get if require the @jitsi/electron-sdk is that the whole application does not work. If I use the current method in the code above, the application works (Home page) but once I enter the Jitsi page, I get the following error:

Uncaught TypeError: Cannot read properties of undefined (reading 'setupRenderer')

@saghul Have you had the chance to test it out or see the code I wrote in the last reply?

Please share a repository.

@saghul

Here you go!

Please let me know if there is anything wrong with what I did. Thank you!

I’ll take a look.

Have you had time to check it out?

After changing up the code I have for my own application, I noticed this error appearing in the console:

Uncaught DOMException: Blocked a frame with origin "file://" from accessing a cross-origin frame.
    at ScreenShareRenderHook._onIframeApiLoad

No, I haven’t had the chance yet. Try adding this line: jitsi-meet-electron/main.js at master · jitsi/jitsi-meet-electron · GitHub