渲染进程中的 Web 技术
本教程共 45 篇 · 第 16 篇 · 更新于 2026-08-03
16. 渲染进程中的 Web 技术
本节目标
- 理解渲染进程本质是 Chromium 渲染的网页
- 弄清为什么默认不能用 CommonJS 的 require
- 掌握在渲染进程中使用 ES Module 的方法
- 了解 React、Vue 等前端框架的接入思路
Electron 应用打开一个窗口,你看到的那块界面,本质上就是一个网页。它跑在渲染进程里,由 Chromium 负责绘制。你之前写过的 HTML、CSS、JavaScript,在这里几乎都能直接复用。
本章专门讲渲染进程里的 Web 技术。我们先确认它和浏览器网页的相同点,再说清它的边界:哪些能力被收走了,哪些能力可以打开。最后聊聊怎么把 React、Vue 这类框架接进来。
16-1 渲染进程就是一块网页
渲染进程(renderer process)承载你 loadFile 或 loadURL 加载的页面。它内部就是 Chromium 的渲染引擎,遵循 W3C 标准。你在网页里用过的标签、选择器、事件、Fetch、localStorage,在这里照常工作。
这意味着前端积累的经验基本都能平移。你能用 document.querySelector 操作 DOM,用 fetch 请求接口,用 canvas 画图形,用 CSS Grid 做布局。Electron 没有发明一套新的界面语言。
不同之处在于运行环境。浏览器里的网页被关在安全沙箱里,权限很小。Electron 的渲染进程则介于两者之间:默认情况下它不能碰 Node.js,但可以通过 preload 这座桥,间接调用主进程暴露的系统能力。
也正因如此,渲染进程既是「网页」,又比网页多一点可能性。它不能像 Node 脚本那样随意读文件、起进程,却能在需要时用 IPC 借主进程之手完成这些事。理解这一点,是写好 Electron 界面层的关键。
16-2 不能直接用 CommonJS 的 require
这是新手最容易踩的坑。在浏览器网页里,你不能用 require 加载模块,因为根本没有 Node.js 环境。渲染进程默认也一样。
在 v43.2.0 的安全默认下,渲染进程里写出下面这种代码会直接报错:
// 渲染进程 index.html 内联脚本(不要这样做)
const fs = require('fs') // ReferenceError: require is not defined
原因是 nodeIntegration 默认是 false。Electron 故意不把 Node 能力直接暴露给网页,避免远程内容拿到文件系统权限。这是安全红线,千万不要为了省事把它设回 true。
那渲染进程想用 Node 模块怎么办?答案是走 preload 桥接。
preload 脚本运行在一个独立的隔离世界里,可以 require('electron') 拿到 ipcRenderer,再用 contextBridge 把封装好的函数挂到 window 上。真正读文件、调系统的活儿在主进程完成,渲染进程只负责调用这个安全对象。
要注意 preload 自己也在沙箱内,能引入的模块同样有限(详见第 10 章)。它的定位是「转发」,不是「干活」。
// preload.js(预加载脚本,运行在渲染进程的隔离世界里)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('fileAPI', {
readConfig: () => ipcRenderer.invoke('read-config')
})
// 渲染进程内(只调用暴露出来的接口)
window.fileAPI.readConfig().then((text) => {
document.getElementById('out').innerText = text
})
16-3 可以用 ES Module
虽然不能用 CommonJS 的 require,但渲染进程完全支持现代 ES Module。你可以直接在 HTML 里用 <script type="module">,或者给 <script> 加 type="module" 后再用 import。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>渲染进程示例</title>
</head>
<body>
<button id="btn">点我</button>
<p id="out"></p>
<script type="module" src="./renderer.js"></script>
</body>
</html>
// renderer.js(渲染进程,使用 ES Module 语法)
import { greet } from './util.js'
document.getElementById('btn').addEventListener('click', () => {
document.getElementById('out').innerText = greet('Electron')
})
// util.js
export function greet(name) {
return `你好,${name}!`
}
这里有个坑要提前说。渲染进程的 ESM 由 Chromium 的加载器负责,规则和网页完全一致,所以 import 只能加载相对路径或 URL,没法直接引入 npm 包和 Node 内置模块。
// 渲染进程:下面这行不会生效
// import { readFile } from 'node:fs' // ❌ Chromium 加载器不认识它
另外 file:// 协议没有合法的源,Chromium 对它下的模块脚本有跨源限制,<script type="module"> 可能直接加载失败。稳妥的做法是用 Vite、Webpack 这类工具打包,或者开发阶段挂个本地服务器,用 loadURL 加载。
16-4 与前端框架的关系
Electron 不绑定任何前端框架。React、Vue、Angular、Svelte 都能用,因为它们最终都编译成 HTML、CSS、JavaScript。渲染进程只关心产物,不关心你用什么写的。
典型的接法有两种。第一种是「打包后交给 Electron 加载」:你用 Vite 起一个前端项目,构建出 dist/ 目录,主进程用 loadFile('dist/index.html') 打开它。
// main.js(主进程)
const { app, BrowserWindow } = require('electron/main')
const path = require('node:path')
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
// 框架产物是本地静态文件,preload 仍负责桥接系统能力
preload: path.join(__dirname, 'preload.js')
}
})
// 加载前端框架构建后的页面
win.loadFile(path.join(__dirname, 'dist/index.html'))
})
第二种是「开发时热更新」:前端跑在 localhost:5173 这类开发服务器上,主进程用 loadURL('http://localhost:5173') 加载。发布时再切换成 loadFile。无论哪种,系统能力都通过 preload 暴露,框架代码本身不感知 Electron。
16-5 渲染进程能碰什么、不能碰什么
把边界说清楚,能少走很多弯路。渲染进程能做的事情:处理 DOM、绑定事件、发网络请求、用 Web Storage、用 Canvas/WebGL、跑前端框架。这些都是标准 Web 能力。
渲染进程默认不能做的事情:读写本地文件、启动子进程、调用 Electron 的 clipboard、dialog 等主进程模块。这些都被 nodeIntegration: false 和 contextIsolation: true 拦住了。
要区分清楚的是,标准 Web API 该能用还是能用。比如 navigator.clipboard 读写剪贴板文本就没问题,被挡住的是 Node 和 Electron 主进程那套能力。
需要这些能力时,统一走 IPC。渲染进程发请求,主进程执行真实操作再返回结果。这样既拿到了系统能力,又守住了安全边界。下面的写法是正确的桥接范式:
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('system', {
getAppVersion: () => ipcRenderer.invoke('get-app-version')
})
// main.js(主进程)
const { app, ipcMain } = require('electron/main')
ipcMain.handle('get-app-version', () => {
return app.getVersion()
})
16-6 渲染进程里的调试
开发时,渲染进程就是网页,所以浏览器那套调试手段都用得上。最直接的办法是在主进程里调用 win.webContents.openDevTools(),打开后就能查看 DOM、控制台和网络请求。
如果你没有自定义应用菜单,Electron 的默认菜单里带了「Toggle Developer Tools」,快捷键在 Windows 和 Linux 上是 Ctrl+Shift+I,macOS 上是 Cmd+Option+I。注意这不是浏览器的 F12,Electron 默认并没有绑定这个键。
如果用了前端框架,建议在开发模式让框架的热更新(HMR)跑起来,配合 DevTools 断点,排错效率和写网页时一模一样。记住:渲染进程的报错、性能问题,优先在 DevTools 里看,不要绕到主进程去猜。
16-7 常见误区
第一个误区是「渲染进程能直接 require」。在默认安全配置下会直接报错,正确做法永远是经 preload 桥接。第二个误区是「为了能用 Node 就把 nodeIntegration 打开」,这等于把本机文件系统权限送给网页,是严重的安全倒退。
第三个误区是认为「用了 Electron 就不能用前端框架」。恰恰相反,React、Vue 只是产出网页,Electron 完全不关心你怎么写界面。你真正要关心的,只是系统能力那座 preload 桥怎么搭。
16-8 小结
渲染进程是 Electron 里最像前端的一块。它跑在 Chromium 上,支持 HTML、CSS、ES Module 和所有标准 Web API,你的前端经验可以直接复用。
它的核心限制是默认拿不到 Node.js。这不是缺陷,而是安全设计。需要用系统能力时,请通过 preload 的 contextBridge 暴露最小必要接口,渲染进程只调用这些接口。前端框架(React、Vue 等)只是产出网页,与这套机制互不冲突。