为什么GrapesJS适合Electron
Electron 在桌面窗口中渲染网页,GrapesJS 是一个浏览器编辑器, 所以它在渲染器里运行,没有任何修改。桌面的创新是存储:而是 通过Electron的IPC将项目保存到磁盘。本指南安装 编辑器,安全保存到磁盘,并导出HTML/CSS——完全离线。
1. 从预加载中暴露一个安全的保存/加载API
继续 contextIsolation ,只接你需要的部分
preload.js:
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('store', {
load: () => ipcRenderer.invoke('page:load'),
save: (data) => ipcRenderer.invoke('page:save', data),
});
2. 在主进程中处理磁盘I/O
const { app, ipcMain } = require('electron');
const fs = require('fs/promises');
const path = require('path');
const file = path.join(app.getPath('userData'), 'page.json');
ipcMain.handle('page:load', async () => {
try { return JSON.parse(await fs.readFile(file, 'utf8')); }
catch { return {}; }
});
ipcMain.handle('page:save', async (_e, data) => {
await fs.writeFile(file, JSON.stringify(data));
return { status: 'ok' };
});
3. 渲染器中的葡萄山JS
import grapesjs from 'grapesjs';
import 'grapesjs/dist/css/grapes.min.css';
const editor = grapesjs.init({
container: '#gjs',
height: '100vh',
fromElement: true,
storageManager: false,
});
// Load saved project on start, save on demand.
window.store.load().then((p) => p.project && editor.loadProjectData(p.project));
document.getElementById('save').onclick = () =>
window.store.save({
project: editor.getProjectData(),
html: editor.getHtml(),
css: editor.getCss(),
});
安全提示
桌面编辑器仍然应当保持严格的安全防护。保持contextIsolation: true和,且绝不在渲染器中启用nodeIntegration——只通过预加载脚本暴露最小的 loadsave API 或 API contextBridge sandbox: true。在写入磁盘前,先在主进程验证有效载荷(大小、形状),因为渲染器会加载远程的GrapesJS代码。写入app.getPath('userData')时,文件会落在操作系统合适的位置,考虑原子写入(临时文件 + 重命名),这样存档中途崩溃时项目不会损坏。
前提条件
你需要Node.js 18+和Electron。编辑器像任何网页一样运行在渲染器中 佩奇;桌面的特点是存储——你通过Electron的IPC保存到磁盘 属于一个HTTP服务器。熟悉主渲染/渲染器分割、预加载脚本和IPC 就够了。
向编辑器添加自定义方块
在渲染器中用块管理器注册可拖拽的块:grapesjs.init
editor.BlockManager.add('hero', {
label: 'Hero section',
category: 'Sections',
content: '<section class="hero"><h1>Headline</h1><p>Copy</p></section>',
});
从GJS拉取现成的块库和预设。市场要买更丰富的套装。
磁盘上的原子写入
把项目写成临时文件,然后重新命名,这样保存过程中就不会崩溃 文件会损坏:
ipcMain.handle('page:save', async (_e, data) => {
const tmp = file + '.tmp';
await fs.writeFile(tmp, JSON.stringify(data));
await fs.rename(tmp, file); // atomic on most filesystems
return { status: 'ok' };
});
表演技巧
把GrapesJS捆绑在你的渲染器上(通过Vite或Webpack),这样它就能从本地文件加载出来 而且这个应用完全离线运行。只有当插件功能 打开了。当视角卸载时销毁编辑器,这样在窗口之间切换时 路由不会泄露实例。
安全考量
保持 contextIsolation: true 和 sandbox: true,永不
在渲染器中启用 nodeIntegration — 只暴露最小值
load/save 通过 contextBridgeAPI验证
在写入前的主进程中,由于渲染器,有效载荷(形状和大小)就已完成
加载远程编辑器代码。写在 app.getPath('userData')。
排查常见问题
渲染器中“要求未定义”表示你尝试使用 Node API 直接通过预加载桥接。未样式或空白 Canvas 意味着样式表没有加载,或者容器不存在。 “无声保存失败”通常指IPC信道名称或处理程序 不匹配。
何时在电子中使用GrapesJS
GrapesJS 适合需要离线可视化编辑器的桌面应用——本地页面或 邮件设计器、文档构建器、自助终端内容工具。因为 获得麻省理工学院授权且自成一体,你可以将整个编辑体验交付在你的内部 没有服务器,也没有按座位付费的应用。
下一步
请参见相关的 GrapesJS + Vite 设置 (方便捆绑渲染器)以及 GrapesJS + React 指南,浏览 GrapesJS市场,或者从这里开始 GJS。市场主页。
常见问题
GrapesJS 能在 Electron 中离线运行吗?
是的——把GrapesJS捆绑在渲染器里,通过主硬盘把项目存到磁盘上 过程。不需要网络。
我该如何将项目保存到磁盘?
从渲染器发送该项目,带 ipcRenderer.invoke (exposed
通过预加载),并在主进程中写入 fs ,在
app.getPath('userData')。
我应该启用 contextIsolation(上下文隔离)吗?
是的——保持开启,并用一个小型 API contextBridge 暴露
使得 nodeIntegration。
