
Electron 新版本中,渲染进程无法直接使用 require('electron') 或访问 ipcRenderer,必须通过启用上下文隔离(Context Isolation)并配合 preload 脚本桥接 API,才能安全、可靠地触发主进程通信。
electron 新版本中,渲染进程无法直接使用 `require('electron')` 或访问 `ipcrenderer`,必须通过启用上下文隔离(context isolation)并配合 preload 脚本桥接 api,才能安全、可靠地触发主进程通信。
在 Electron 12+(尤其是 v20+ 默认强制启用)中,直接在 HTML 的 <script> 标签内 require("electron") 已被彻底禁用——这不是语法错误或 ID 写错的问题,而是 Electron 为防范原型污染、代码注入等安全风险而实施的核心架构变更。若按钮点击无响应且控制台静默(无报错),极大概率是因 require 失败导致脚本中断,后续 querySelector 和 addEventListener 实际未执行。</script>
✅ 正确做法是:分离信任边界,用 preload.js 安全暴露有限能力
首先,创建 preload.js(与 main.js 同级目录):
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
sendIpcMessage: (channel, data) => {
// ✅ 严格校验 channel 名称,防止任意 IPC 调用
if (!['key', 'log', 'save'].includes(channel)) {
throw new Error(`Forbidden IPC channel: ${channel}`);
}
ipcRenderer.send(channel, data);
},
// 可选:添加 on 接收主进程消息(需配合 handle 或 on)
// onIpcMessage: (channel, listener) => ipcRenderer.on(channel, listener),
});
然后,在 main.js 中显式挂载该 preload 脚本,并启用上下文隔离(推荐保持默认 true):
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('node:path');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true, // ✅ 必须为 true(新版本默认值)
nodeIntegration: false, // ❌ 禁用 nodeIntegration(与 contextIsolation 互斥)
}
});
// 监听渲染进程发来的消息
ipcMain.on('key', (event, message) => {
console.log('[Main] Received:', message); // 替代 alert,避免阻塞
// event.reply('response', 'ack') 可用于双向通信
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
最后,更新你的 HTML,移除所有 require 调用,仅通过 window.electron 访问预定义方法:
<!-- index.html -->
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Gangway App</title><link rel="stylesheet" href="assets/bootstrap.min.css"><h1>gangway app</h1>
<button class="btn btn-primary" id="sendBtn">Send</button>
<script>
// ✅ 安全访问:确保 preload 已加载且 electron 对象存在
if (typeof window.electron === 'undefined') {
console.error('Preload script not loaded — check webPreferences.preload path.');
throw new Error('Electron bridge unavailable');
}
const { sendIpcMessage } = window.electron;
const sendBtn = document.querySelector('#sendBtn');
if (!sendBtn) {
console.warn('Button #sendBtn not found in DOM');
} else {
sendBtn.addEventListener('click', () => {
alert('Alert triggered!'); // 仅用于调试,生产环境建议用 Toast
sendIpcMessage('key', 'Gangway Test');
});
}
</script>
⚠️ 关键注意事项:
- 路径必须准确:preload.js 的 path.join(__dirname, ...) 需指向真实文件路径,建议用 VS Code 打开终端执行 ls preload.js 验证;
- 禁用 nodeIntegration:若设为 true,contextIsolation 将自动失效,失去安全保护;
- 避免全局污染:exposeInMainWorld 中只暴露必要方法,禁止透传 ipcRenderer 全对象;
- 调试技巧:在渲染进程 DevTools 控制台输入 window.electron,应返回含 sendIpcMessage 的对象;若为 undefined,说明 preload 未生效。
遵循此模式,即可在保障安全的前提下,让按钮点击正常触发 IPC 通信——这是 Electron 现代化开发的必备实践。










