2.预加载(preload)

学习记录:使用预加载脚本(教程第 3 部分)


一、本节位置与目标

|--------------|--------------------------------------------------------------|
| 项目 | 内容 |
| 教程位置 | 第 3 部分(前面:建项目、开窗口;后面:加功能、打包、发布) |
| 学习目标 | 理解预加载脚本;用 contextBridge 安全暴露 API;用 IPC 让主进程与渲染进程通信 |

本节要解决的核心问题 :主进程很强(Node + 系统),渲染进程很像网页(默认不能乱用 Node)------中间怎么安全地搭桥


二、三种进程能力对比(先建立表格)

|---------------|-----------------------|-----------------------------------------------------------------|-------------------------------|
| 进程 | 环境 | 能做什么 | 不能做什么 |
| 主进程 | 完整 Node.js + Electron | 生命周期、窗口、文件、系统 API | 不能直接操作页面 DOM |
| 渲染进程 | 类似浏览器网页 | DOM、Web API、Vue/React UI | 默认不能直接 require('fs') 等 Node |
| 预加载脚本 | 介于两者之间 | 在页面加载之前 注入;有限 Node/Electron;用 contextBridge 暴露白名单 API | 不是给用户随便写业务 UI 的地方 |

分工原则(背下来)

  • 主进程 ↔ 渲染进程:职责不可互换
  • 渲染器要「特权能力」→ 走 preload + contextBridge + IPC
  • 主进程要「页面信息」→ 也走 IPC,不要指望直接摸 DOM

三、什么是预加载脚本?

预加载脚本包含在浏览器窗口加载网页之前运行的代码。 其可访问 DOM 接口和 Node.js 环境,并且经常在其中使用contextBridge接口将特权接口暴露给渲染器。

由于主进程和渲染进程有着完全不同的分工,Electron 应用通常使用预加载脚本来设置进程间通信 (IPC) 接口以在两种进程之间传输任意信息。

通俗理解

预加载脚本 = 窗口里的「安检员 + 传话员」

  1. HTML/页面脚本加载之前 就先运行(类似 Chrome 扩展的 Content Script 注入时机)
  2. 能接触 一部分 Node / Electron API
  3. 通过 contextBridge.exposeInMainWorld,把你允许 的能力挂到页面的 window 上(主世界 worldId 0

Electron 20+:预加载默认沙盒化

从 Electron 20 起,preload 默认沙盒化,不再是「完整 Node 随便用」:

  • 只有 polyfill 过的 require,只能加载有限模块
  • 常见可用:Electron 模块、部分 Node 模块、部分全局对象

学习笔记 :不要假设 preload 里能 require 任意 npm 包;以官方「进程沙盒化」文档为准。


四、实战一:把版本号暴露给页面

4.1 流程(四步)

复制代码
main.js 指定 preload 路径
    ↓
preload.js 用 contextBridge 暴露 versions
    ↓
index.html 引入 renderer.js
    ↓
renderer.js 读 versions.xxx() 更新 DOM

4.2 关键代码与职责

① main.js ------ 挂上 preload

复制代码
webPreferences: {
  preload: path.join(__dirname, 'preload.js'),
}

|------------------|------------------------------------------|
| 概念 | 作用 |
| __dirname | 当前正在执行的脚本所在目录(你的 main.js 所在文件夹,一般是项目根) |
| path.join(...) | 拼跨平台路径,避免手写 \ / / |

你项目里已配置:

复制代码
webPreferences: {
  preload: path.join(__dirname, 'preload.js'),
},

② preload.js ------ 暴露 API(目标:主世界 world 0)

复制代码
contextBridge.exposeInMainWorld('versions', {
  node: () => process.versions.node,
  chrome: () => process.versions.chrome,
  electron: () => process.versions.electron,
})

你项目在教程基础上还多了练习代码:myfnmyObjnum1process 等------有助于理解「能暴露函数、对象、嵌套」,但 process: () => process********整包暴露要谨慎(安全与克隆规则),生产环境更推荐只暴露需要的字段。

③ renderer.js ------ 当普通网页 JS 用

复制代码
versions.chrome()   // 等价 window.versions.chrome()

你当前实现:

复制代码
const information = document.getElementById('info')
information.innerText = `... ${versions.chrome()} ...`
// + myfn、myObj 等

④ index.html

  • <p id="info"></p> 占位
  • <script src="./renderer.js"></script>
  • CSP:script-src 'self' → 只加载本地脚本,符合安全基线

五、实战二:IPC ------ 主进程与渲染进程说话

5.1 为什么需要 IPC?

|-----------------------|---------------------------------------|
| 需求 | 正确做法 |
| 页面按钮 → 读本地文件 | 渲染器 invoke → 主进程 handle 读文件 |
| 主进程 → 通知页面更新 | webContents.send + preload 里封装 on |
| 渲染器直接 require('fs') | ❌ 默认不应这样做 |

5.2 教程里的 ping / pong 完整链路

复制代码
sequenceDiagram
  participant R as renderer.js (world 0)
  participant P as preload.js (world 999)
  participant M as main.js (主进程)

  R->>P: window.versions.ping()
  P->>M: ipcRenderer.invoke('ping')
  M-->>P: return 'pong'
  P-->>R: Promise resolve 'pong'

|------------|-------------|------------------------------------------|
| 步骤 | 文件 | 代码要点 |
| 1 暴露封装好的调用 | preload.js | ping: () => ipcRenderer.invoke('ping') |
| 2 主进程注册处理 | main.js | ipcMain.handle('ping', () => 'pong') |
| 3 页面发起调用 | renderer.js | await window.versions.ping() |

preload 已写好 ping

复制代码
ping: () =>ipcRenderer.invoke('ping')

待补全(对照教程)

  1. main.jsapp.whenReady() 里、createWindow()********之前注册:

    const { ipcMain } = require('electron')
    app.whenReady().then(() => {
    ipcMain.handle('ping', () => 'pong')
    createWindow()
    })

  2. renderer.js 里异步测试:

    const func = async () => {
    const response = await window.versions.ping()
    console.log(response) // 'pong'
    }
    func()

5.3 IPC 安全(必背红线)

复制代码
// ❌ 永远不要这样
contextBridge.exposeInMainWorld('ipc', ipcRenderer)

// ✅ 只暴露白名单方法
ping: () => ipcRenderer.invoke('ping')

原因 :整包 ipcRenderer 会让页面代码能向主进程发任意频道的消息,等于把后台钥匙交给前台,恶意脚本危害极大。

Web 类比 :像只提供 api.getUser(),而不是把整个 fetch + 管理员 Token 挂在 window 上。


六、和你已学知识的串联

|-----------------------------------|--------------------------------------------|
| 前面学过的 | 本节怎么用 |
| app / BrowserWindow | webPreferences.preload 把脚本绑到窗口 |
| contextBridge.exposeInMainWorld | 注入到 world 0 ,给 renderer.js / Vue |
| exposeInIsolatedWorld | 本节教程不用;日常开发也极少用 |
| Web 的 window.SDK | ≈ exposeInMainWorld('versions', {...}) |
| Web 的 fetch 调后端 | ≈ invoke 调主进程 |


七、对接 Vue3 的预习笔记

复制代码
main.js          → 创建窗口、ipcMain.handle
preload.js       → contextBridge.exposeInMainWorld('electronAPI', {...})
src/main.ts (Vue) → window.electronAPI.ping()

建议统一一个名字(如 electronAPI),Vue 里可再包一层 composable:useElectron(),组件不直接散落 window.xxx


八、本节文件职责清单(复习用)

|---------------------|------------|-------------------------------|
| 文件 | 角色 | 本节要点 |
| main.js | 主进程 | preload 路径;ipcMain.handle |
| preload.js | 预加载(隔离世界) | contextBridge;封装 invoke |
| index.html | 页面结构 | CSP;#info;引 renderer |
| renderer.js | 渲染逻辑(主世界) | 用 versionsawait ping() |


九、官方摘要 + 你的复盘句

官方摘要

  • Preload 在网页加载之前 运行,常用 contextBridge 把特权接口交给渲染器。
  • 主/渲染分工不同,靠 preload + IPC 传信息。

你的复盘句(背这句)

主进程管系统和窗口;渲染进程管界面;preload 在页面加载前用 contextBridge********只暴露白名单 API;跨进程办事用 IPC,且只封装 invoke/on****,绝不暴露整个**** ipcRenderer****。****

相关推荐
TrisighT1 小时前
Electron 本地图片在鸿蒙 PC 上白图,我注册了个自定义协议
electron·harmonyos
森叶2 小时前
Electron 多进程下的“库引入“全解析:核心模块、Electron API、第三方依赖与 utilityProcess 的依赖处理
运维·javascript·electron
古怪今人3 小时前
手工搭建PC端:pnpm + Vite + Vue3 + Element Plus + Electron
前端·vue.js·electron
小雨下雨的雨1 天前
数独算法与求解器鸿蒙PC Electron框架完成深度解析
javascript·人工智能·算法·游戏·华为·electron·鸿蒙系统
薛定谔的猫-菜鸟程序员1 天前
从Electron到Tauri,Rust+Vue(Tauri) 实现超高性能桌面日志应用开发,以及开发避坑指南
vue.js·rust·electron
小雨下雨的雨1 天前
井字棋AI机器人实现详解 - Minimax算法实战-鸿蒙PC Electron框架完成
前端·人工智能·算法·华为·electron·鸿蒙
TrisighT2 天前
Electron 窗口切后台,我的轮询怎么停了?排查一下午才发现是浏览器搞的鬼
electron·harmonyos
怕浪猫2 天前
Electron 开发实战(十二):安全性最佳实践|彻底杜绝漏洞、代码执行与数据泄露
前端·javascript·electron
AI_零食3 天前
鸿蒙PC Electron跨平台应用开发:24时区时间表应用详解
前端·华为·electron·开源·harmonyos·鸿蒙
提子拌饭1333 天前
爆发效果技术——基于鸿蒙PC Electron框架实现
华为·架构·electron·开源·harmonyos·鸿蒙·鸿蒙系统