Preload.js 需要问题

发布于 2025-01-14 17:29:55 字数 905 浏览 3 评论 0原文

最近我开始使用 Electron 框架练习 javascript,但我遇到了 preload.js 功能的问题。也许我不明白如何使用它,但我不能要求一些电子常量,因为它返回未定义的

我的 preload2.js:

const { BrowserWindow } = require("electron");
console.log(BrowserWindow);

在我的窗口控制台中它返回

Undefined

我排除了问题可能是我的预加载未正确执行但它可能是:

我的 main.js:

const { app, BrowserWindow } = require('electron');

function createWindow() {
    console.log(app.getAppPath());
    const win = new BrowserWindow({
        width: 1000,
        height: 600,
        //Web preferences può utilizzare il preload.js 
        webPreferences: {
            preload: app.getAppPath() + "\\preload2.js",
        }
    });
    win.loadFile('index.html');

}



app.whenReady().then(createWindow);



app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

请帮助我,我失去了理智

Recently I started practising javascript with the Electron framework but i've encountered a problem with the preload.js functionality. Maybe i didn't understand how to use it, but i can't require some of the electron constants because it returns undefined

My preload2.js:

const { BrowserWindow } = require("electron");
console.log(BrowserWindow);

In my window's console it returns

Undefined

I excluded the problem could be that my preload is not correctly executed but it may be:

My main.js:

const { app, BrowserWindow } = require('electron');

function createWindow() {
    console.log(app.getAppPath());
    const win = new BrowserWindow({
        width: 1000,
        height: 600,
        //Web preferences può utilizzare il preload.js 
        webPreferences: {
            preload: app.getAppPath() + "\\preload2.js",
        }
    });
    win.loadFile('index.html');

}



app.whenReady().then(createWindow);



app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

Please help me i'm losing my mind

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

落在眉间の轻吻 2025-01-21 17:29:56

如果没有结构良好的基本示例,很难掌握 Electron 的 preload.js 脚本的正确使用。互联网上的许多示例将预加载脚本的主要功能(即管理主线程和渲染线程之间的通信通道)与这些通道的实现相结合。

为了进一步了解您的知识,请仔细阅读 Electron 的流程模型,< a href="https://www. Electronjs.org/docs/latest/tutorial/context-isolation" rel="noreferrer">上下文隔离 和 进程间通信页面。

一旦您阅读了这些页面(但不一定理解它们),让我们开始将它们缝合在一起,以便它们作为一个整体工作。


如前所述,preload.js 脚本的目的是在主线程和渲染线程之间进行通信。如果向预加载脚本添加大量函数,预加载脚本很快就会变得不堪重负。

作为一种替代方法,我使用我的(唯一的)preload.js 脚本来仅管理 IPC(按通道名称)。这意味着我指定了在主线程和渲染之间传输或接收的白名单通道名称线程。任何不在白名单中的通道名称都将被拒绝通过。您还可以在发送通道名称时发送数据,以便另一端可以接收数据。

好的,让我们看一下 preload.js 文件。

preload.js(主线程)

// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;

// White-listed channels.
const ipc = {
    'render': {
        // From render to main.
        'send': [
            'message:fromRender'
        ],
        // From main to render.
        'receive': [
            'message:toRender'
        ],
        // From render to main and back again.
        'sendReceive': []
    }
};

// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
    // Allowed 'ipcRenderer' methods.
    'ipcRender', {
        // From render to main.
        send: (channel, args) => {
            let validChannels = ipc.render.send;
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, args);
            }
        },
        // From main to render.
        receive: (channel, listener) => {
            let validChannels = ipc.render.receive;
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`.
                ipcRenderer.on(channel, (event, ...args) => listener(...args));
            }
        },
        // From render to main and back again.
        invoke: (channel, args) => {
            let validChannels = ipc.render.sendReceive;
            if (validChannels.includes(channel)) {
                return ipcRenderer.invoke(channel, args);
            }
        }
    }
);

在上面的代码中,您将看到通道名称 message:fromRendermessage:toRender 已添加到白名单。

注意:诸如 BrowserWindow 之类的对象无法通过 IPC 发送,因为它们不可序列化。有关详细信息,请参阅对象序列化


现在,在 main.js 文件中,除了预加载脚本的路径之外,一切看起来都很好。让我们改变这一点。

main.js (主线程)

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;

const nodePath = require("path");

let win;

function createWindow() {
    const win = new electronBrowserWindow({
        x: 0,
        y: 0,
        width: 1000,
        height: 600,
        show: false,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            preload: nodePath.join(__dirname, 'preload.js')
        }
    });

    win.loadFile('index.html')
        .then(() => { win.show(); })
        // Send message to (win) render thread
        .then(() => { win.webContents.send('message:toRender', 'Hello from the main thread.' )};

    return win;
}

electronApp.on('ready', () => {
    win = createWindow();
});

electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        electronApp.quit();
    }
});

electronApp.on('activate', () => {
    if (electronBrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});

// Listen for message from (any) render thread.
electronIpcMain.on('message:fromRender', (event, message) => {
    console.log(message);
})

您会注意到我添加了 2 个新的代码部分。一种用于向渲染线程发送消息,另一种用于从渲染线程接收特定消息。


最后,让我们向基本的 index.html 文件添加功能。

index.html(渲染线程)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    
    <body>
        <label for ="button">Send message to main thread: </label>
        <input type="button" id="button" value="Send">        
    </body>
    
    <script>
        // Listen for message from the main thread
        window.ipcRender.receive('message:toRender', (message) => {
            console.log(message);
        });
        
        document.getElementById('button').addEventListener('click', () => {
            // Send a message to the main thread
            window.ipcRender.send('message:fromRender', 'Hello from the render thread.');
        });
    </script>
</html>

启动应用程序后,渲染线程控制台应显示Hello from the main thread

单击Send按钮后,主线程应显示来自渲染线程的Hello

如果您需要任何澄清或进一步解释,请告诉我。

The proper use of Electron's preload.js script is hard to grasp without a basic well-structured example. Many examples on the internet blend the primary function of the preload script (which is to manage the channels of communication between the main thread and render threads) with implementation of those channels.

To further your knowledge, have a good read of Electron's Process Model, Context Isolation and Inter-Process Communication pages.

Once you have read these pages (but not necessarily understood them) let's begin stitching them together so they all work as a whole.


As described earlier, the purpose of the preload.js script is to communicate between the main thread and render thread(s). Preload scripts can become overwhelming very quickly if you add a large number of functions to them.

As an alternative approach, I use my (one and only) preload.js script for management of IPC's (by channel name) only. What this means is that I specific whitelisted channel names that are transmitted or received between the main thread and render thread(s). Any channel names used that are not on the whitelist are denied passage. You can also send data when transmitting the channel name so the data can be received at the other end.

Ok, let's look at the preload.js file.

preload.js (main thread)

// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;

// White-listed channels.
const ipc = {
    'render': {
        // From render to main.
        'send': [
            'message:fromRender'
        ],
        // From main to render.
        'receive': [
            'message:toRender'
        ],
        // From render to main and back again.
        'sendReceive': []
    }
};

// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
    // Allowed 'ipcRenderer' methods.
    'ipcRender', {
        // From render to main.
        send: (channel, args) => {
            let validChannels = ipc.render.send;
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, args);
            }
        },
        // From main to render.
        receive: (channel, listener) => {
            let validChannels = ipc.render.receive;
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`.
                ipcRenderer.on(channel, (event, ...args) => listener(...args));
            }
        },
        // From render to main and back again.
        invoke: (channel, args) => {
            let validChannels = ipc.render.sendReceive;
            if (validChannels.includes(channel)) {
                return ipcRenderer.invoke(channel, args);
            }
        }
    }
);

In the above code you will see that the channel names message:fromRender and message:toRender have been added to the whitelist.

Note: Objects such as BrowserWindow cannot be sent via IPC as they are not serialisable. See Object serialization for more information.


Now, in your main.js file, everything looks good except for the path to the preload script. Let's change that.

main.js (main thread)

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;

const nodePath = require("path");

let win;

function createWindow() {
    const win = new electronBrowserWindow({
        x: 0,
        y: 0,
        width: 1000,
        height: 600,
        show: false,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            preload: nodePath.join(__dirname, 'preload.js')
        }
    });

    win.loadFile('index.html')
        .then(() => { win.show(); })
        // Send message to (win) render thread
        .then(() => { win.webContents.send('message:toRender', 'Hello from the main thread.' )};

    return win;
}

electronApp.on('ready', () => {
    win = createWindow();
});

electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        electronApp.quit();
    }
});

electronApp.on('activate', () => {
    if (electronBrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});

// Listen for message from (any) render thread.
electronIpcMain.on('message:fromRender', (event, message) => {
    console.log(message);
})

You will notice I have added 2 new sections of code. One to send a message to the render thread and one to receive a specific message from the render thread.


Finally, let's add functionality to our basic index.html file.

index.html (render thread)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    
    <body>
        <label for ="button">Send message to main thread: </label>
        <input type="button" id="button" value="Send">        
    </body>
    
    <script>
        // Listen for message from the main thread
        window.ipcRender.receive('message:toRender', (message) => {
            console.log(message);
        });
        
        document.getElementById('button').addEventListener('click', () => {
            // Send a message to the main thread
            window.ipcRender.send('message:fromRender', 'Hello from the render thread.');
        });
    </script>
</html>

Upon starting the application, the render thread console should display Hello from the main thread.

Upon clicking the Send button, the main thread should display Hello from the render thread.

If you need any clarification or further explanation just let me know.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文