Memperluas CatatanKu secara arsitektural: pola multi-window, model proses di Electron, Tauri, dan Flutter, isolasi proses antar window, serta komunikasi lintas window tanpa berbagi memori

Di episode 23 CatatanKu resmi menjadi platform dengan plugin. Namun aplikasi desktop yang dipakai serius jarang bertahan dengan satu jendela saja: editor utama, panel preview, jendela pengaturan, dan komposer catatan baru sering kali berdampingan. Masalahnya bukan sekadar "membuka jendela" — tapi bagaimana proses di baliknya bekerja.
Episode ini membedah multi-window & multi-process: pola desain window, model proses di Tauri, Electron, dan Flutter, mengapa isolasi proses membuat aplikasi lebih stabil sekaligus aman, dan bagaimana window-window berkomunikasi tanpa berbagi memori secara membabi buta.
Multi-window bukan hiasan. Beberapa alasan nyata:
Keputusan arsitektur kedua adalah SDI vs MDI (multiple-document interface). Aplikasi modern mayoritas memilih SDI dengan beberapa window — satu catatan per window — karena lebih sederhana, lebih mudah diisolasi, dan sinkron dengan model mental OS.
Pertanyaan pentingnya: apakah satu window = satu proses? Jawabannya tergantung framework — dan ini menentukan stabilitas serta strategi komunikasi kalian.
Di Electron setiap BrowserWindow mendapat renderer process Chromium sendiri. Main process adalah pengatur: membuat window, meneruskan IPC, dan mengelola lifecycle. Satu renderer crash → window itu bisa di-reload tanpa menjatuhkan aplikasi — ini isolasi proses yang nyata.
Tauri memakai satu core Rust untuk semua window, lalu setiap window adalah webview (WebKitGTK di Linux, WKWebView di macOS, WebView2 di Windows). Komunikasi window ↔ core lewat IPC; core yang memegang state penting, webview hanya "wajah".
Flutter desktop berjalan dalam satu Dart isolate dan membuka window native (Window.toWindow()). Karena satu isolate, window berbagi heap — pemisahannya bukan isolasi proses, melainkan disiplin state di sisi kalian. Ini trade-off: lebih ringan, tapi satu kesalahan global bisa memengaruhi semua window.
Isolasi proses memberi dua hal sekaligus:
Konsekuensinya: jangan berbagi memori antar window. Renderer tidak boleh saling memegang referensi state. Cara berbagi yang benar:
Semua komunikasi antar window melewati satu otoritas pusat: main process (Electron) atau core (Tauri).
// main process
function broadcast(event: string, payload: unknown) {
for (const window of BrowserWindow.getAllWindows()) {
window.webContents.send(event, payload);
}
}
// renderer A menerima
ipcRenderer.on("note:updated", (_e, note) => refreshView(note));use tauri::{Manager, Emitter};
#[tauri::command]
fn note_updated(app: AppHandle, note: Note) {
// broadcast ke semua window yang mendengarkan "note:updated"
let _ = app.emit("note:updated", note);
}Pola ini sama dengan streaming AI di episode 21: event dengan payload, diterima siapa saja yang butuh. Tidak ada window yang memanggil state window lain secara langsung.
Tip
Buat satu WindowManager terpusat yang mencatat window aktif, mem-broadcast event, dan me-restore state window (posisi, ukuran, window yang terbuka) saat aplikasi dijalankan ulang. Tanpa itu, state window tersebar di kode dan sulit dipulihkan — persis masalah persistensi yang kita bahas di episode 8.
Multi-window tidak lepas dari kebiasaan tiap OS:
Terapkan dengan logika kondisional platform dari episode 25 — karena menulis multi-window yang "benar di satu OS" dan rusak di OS lain adalah pitfall klasik.
WindowManager bisa di-garbage collect; simpan semua referensi.Inti yang harus dibawa pulang:
WindowManager terpusat.Di episode 25 berikutnya kita memakai semua yang sudah dibangun untuk menuntaskan janji utama desktop development: cross-platform mastery — satu codebase yang benar-benar berjalan di Windows, macOS, dan Linux dengan adaptasi platform yang tepat. Sampai jumpa di episode 25!