Warum GrapesJS zu Electron passt
Electron rendert Webseiten in einem Desktop-Fenster, und GrapesJS ist ein Browser-Editor. Sie läuft also im Renderer ohne Änderungen. Der Desktop-Twist ist stattdessen der Speicher: eines Servers speichert man Projekte über Electrons IPC auf der Festplatte. Dieser Leitfaden montiert sich der Editor speichert sicher auf der Festplatte und exportiert HTML/CSS – vollständig offline.
1. Eine sichere Speicher-/Lade-API aus dem Preload bereitstellen
Bleib contextIsolation dran und überbrücke nur das, was du brauchst
preload.js:
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('store', {
load: () => ipcRenderer.invoke('page:load'),
save: (data) => ipcRenderer.invoke('page:save', data),
});
2. Disk-I/O im Hauptprozess zu handhaben
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. Mount GrapesJS im Renderer
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(),
});
Sicherheitstipps
Ein Desktop-Editor verdient dennoch eine strenge Sicherheitsstrategie. Behalten contextIsolation: true Sie und sandbox: true, und aktivieren nodeIntegration Sie niemals im Renderer – stellen Sie nur ein Minimum load/save API in contextBridge einem Preload-Skript bereit. Validiere die Nutzlast im Hauptprozess, bevor du sie auf die Festplatte schreibst (Größe, Form), da der Renderer entfernten GrapesJS-Code lädt. Schreibe darunter app.getPath('userData') , damit Dateien an der für das Betriebssystem geeigneten Ort landen, und berücksichtige atomare Schreibvorgänge (temporäre Datei + Umbenennung), damit ein Absturz mitten im Speicherstand das Projekt nie beschädigt.
Voraussetzungen
Du brauchst Node.js 18+ und Electron. Der Editor läuft im Renderer wie in jedem beliebigen Web Seite; der Desktop-Twist ist der Speicher – du speicherst stattdessen über Electrons IPC auf der Festplatte eines HTTP-Servers. Vertrautheit mit der Haupt-/Renderer-Trennung, Preload-Skripten und IPC ist genug.
Fügen Sie benutzerdefinierte Blöcke zum Editor hinzu
Registrieren Sie ziehbare Blöcke anschließend im Blockmanager grapesjs.init im Renderer:
editor.BlockManager.add('hero', {
label: 'Hero section',
category: 'Sections',
content: '<section class="hero"><h1>Headline</h1><p>Copy</p></section>',
});
Ziehe fertige Blockbibliotheken und Presets aus GJS.Market für ein reichhaltigeres Set.
Atomare Schreibvorgänge auf Festplatte
Schreibe das Projekt in eine temporäre Datei und benenne sie so um, dass es während des Speicherstands nie abstürzt beschädigt die Datei:
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' };
});
Aufführungstipps
Bündeln Sie GrapesJS mit Ihrem Renderer (über Vite oder Webpack), damit es aus lokalen Dateien lädt. Und die App funktioniert komplett offline. Lazy-load-lastige Plugins nur, wenn ihre Funktion geöffnet. Zerstöre den Editor, wenn die Ansicht entkoppelt, also navigiere zwischen Fenstern oder Routen leaken keine Instanzen.
Sicherheitsaspekte
Behalten contextIsolation: true und sandbox: true, und niemals
Im Renderer aktivieren nodeIntegration – nur ein Minimum freilegen
load/save API über contextBridge. Validieren
Die Nutzlast (Form und Größe) im Hauptprozess vor dem Schreiben, da der Renderer
Lädt Remote Editor-Code. Schreibe unter app.getPath('userData').
Fehlerbehebung häufiger Fehler
"require ist nicht definiert" im Renderer bedeutet, dass du versucht hast, Node zu verwenden APIs direkt – gehen Sie stattdessen über die Preload-Bridge. Ein unstyled oder leerer Leinwand bedeutet, dass das Stylesheet nicht geladen wurde oder der Container nicht vorhanden war. Speicherstände scheitern lautlos in der Regel den IPC-Kanalnamen oder Handler passt nicht zusammen.
Wann sollte man GrapesJS in Electron verwenden.
GrapesJS eignet sich für eine Desktop-App, die einen Offline-visuellen Editor benötigt – eine lokale Seite oder E-Mail-Designer, ein Dokumentations-Builder, ein Kiosk-Inhaltstool. Weil es so ist MIT-lizenziert und in sich geschlossen, du lieferst das gesamte Schnitterlebnis in deinem eigenen App ohne Server und ohne Sitzgebühren.
Nächste Schritte
Siehe das zugehörige GrapesJS + Vite-Setup (praktisch zum Bündeln des Renderers) und GrapesJS + React Leitfäden, durchstöbern Sie den GrapesJS-Marktplatz oder starten Sie bei die GJS.Market-Startseite.
FAQ
Kann GrapesJS offline in Electron laufen?
Ja – bündel GrapesJS mit dem Renderer und speichere Projekte auf der Festplatte über das Hauptprogramm Prozess. Kein Netzwerk erforderlich.
Wie speichere ich Projekte auf der Festplatte?
Sende das Projekt vom Renderer mit ipcRenderer.invoke (exposed
über Preload) und schreibe es mit fs im Hauptprozess, unter
app.getPath('userData').
Sollte ich contextIsolation aktivieren?
Ja – lass es an und stelle stattdessen eine kleine API contextBridge bereit
der Ermöglichung nodeIntegrationvon .
