今天开始学习NodeJs 关于 桌面应用的内容,长期目标是 React + electron 实现一个桌面应用。
今天先实现一个简单的目标,搭建一个Electron + ts 项目架构,并实现主业务线程 和前端渲染线程的交互
一、代码结构和配置
例子项目结构大致如下:
package.json
{
"name": "electron-ts-demo",
"version": "1.0.0",
"main": "dist/main.js",
"scripts": {
"build": "tsc && xcopy /y src\\renderer\\*.html dist\\renderer\\",
"watch": "tsc -w",
"start": "electron .",
"dev": "concurrently \"npm run watch\" \"npm run start\""
},
"devDependencies": {
"concurrently": "^9.2.0",
"electron": "^37.3.0",
"typescript": "^5.3.2"
},
"dependencies": {}
}
这里用到一个concurrently 包 是实现多条命令并行执行的工具。
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"sourceMap": true,
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
二、代码实现
preload.ts
预处理实现
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('electronAPI', {
sendMessage: (message: string) => ipcRenderer.send('message-from-renderer', message),
onReply: (callback: (response: string) => void) =>
ipcRenderer.on('message-reply', (event, response) => callback(response))
});
实现渲染线程(页面) 发送信息到 主线程,主返回信息到渲染线程 (通过回调的形式)
main.ts
import { app, BrowserWindow, ipcMain } from 'electron';
import path from 'path';
let mainWindow: BrowserWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true
}
});
mainWindow.loadFile('dist/renderer/index.html');
ipcMain.on('message-from-renderer', (event, msg: string) => {
console.log('Received:', msg);
event.reply('message-reply', `Main process received: ${msg}`);
});
}
app.whenReady().then(() => {
createWindow();
//macBook 兼容
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
上面实现了一个简单的生成一个窗口的例子。使用我们预先准备的preload.js预处理。
通过 ipcMain 监听 发生消息和返回回调。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Electron TS Demo</title>
<style>
body {
font-family: Arial;
padding: 20px;
}
button {
padding: 8px 16px;
}
</style>
</head>
<body>
<h1>Electron + TypeScript Demo</h1>
<button id="sendBtn">Send Message</button>
<div id="response"></div>
<script src="renderer.js"></script>
</body>
</html>
renderer.ts
const sendBtn = document.getElementById('sendBtn')!;
const responseDiv = document.getElementById('response')!;
sendBtn.addEventListener('click', () => {
console.log("sendBtn Click");
window?.electronAPI.sendMessage('Hello from TypeScript');
});
window?.electronAPI.onReply((response: string) => {
console.log(response);
responseDiv.textContent = response;
});
这里添加监听 给主线程发送消息,通过 window.electronAPI 预处理暴露到主页面的对象设置监听方法监听主线程 返回消息。