Untuk membangun aplikasi desktop dari aplikasi Capacitor, bungkus build web yang sama (webDir) dalam shell Electron: proses utama yang membuka BrowserWindow, sebuah preload script yang mengekspos API desktop kecil, dan electron-builder untuk membuat installer bagi macOS, Windows, dan Linux. UI dan business logic Anda tetap sama dengan iOS dan Android, sementara fitur khusus desktop berjalan di Electron main process.
Panduan ini membahas kondisi terkini Capacitor di Electron pada 2026, setup aman yang kompatibel dengan Capacitor 8, perilaku plugin, packaging dan signing, serta cara mengirim update web tanpa installer baru.
Kondisi Capacitor di Electron pada 2026
Selama bertahun-tahun, jawaban standarnya adalah @capacitor-community/electron, yang menghubungkan Electron ke Capacitor CLI sebagai platform. Proyek itu kini berstatus unmaintained di README-nya sendiri. Rilis npm terakhirnya, 5.0.1, dirilis September 2023, membutuhkan Capacitor 5.4 atau lebih baru, dan dibangun dengan Electron 26. Sejak itu Electron sudah merilis banyak versi mayor, dan hanya tiga versi mayor terbaru yang mendapat perbaikan keamanan.
Anda masih bisa menggunakannya di proyek lama, tetapi untuk aplikasi Capacitor 8, perbandingannya adalah sebagai berikut:
| Pendekatan | Kelebihan | Kekurangan |
|---|---|---|
| Electron shell buatan sendiri (panduan ini) | Electron terbaru, kontrol penuh, tanpa abstraksi tambahan | Anda menulis sekitar 60 baris code main dan preload |
@capacitor-community/electron |
Familiar cap commands |
Tidak terawat, terkunci pada versi lama Capacitor dan Electron |
Pendekatan shell ini lebih sedikit pekerjaannya daripada yang terdengar, karena Capacitor sudah menghasilkan static web build. Electron hanya perlu memuatnya.
Bagaimana perilaku plugin di Electron
Renderer Electron adalah Chromium, jadi aplikasi Capacitor Anda berjalan di sana seperti di browser. Core Capacitor mendeteksi tidak ada native bridge dan fallback ke implementasi web masing-masing plugin.
| Jenis plugin | Berjalan di Electron? | Cara mengatasi |
|---|---|---|
| Plugin dengan implementasi web (Preferences, Share, Clipboard, banyak plugin Capgo) | Ya, menggunakan versi web | Uji perilaku web |
| Plugin khusus native (tanpa implementasi web) | Tidak, ditolak sebagai tidak diimplementasikan | Tulis ekuivalen Electron di balik API preload |
| Library JS murni | Ya | Tidak ada |
Capacitor.getPlatform() mengembalikan 'web' dalam setup ini dan Capacitor.isNativePlatform() mengembalikan false. Kami akan mengekspos flag desktop eksplisit dari preload script agar code Anda bisa bercabang dengan bersih.
Prerequisites
- Aplikasi Capacitor yang
bun run buildmenghasilkan folder statis (yaituwebDirdicapacitor.config.ts, sering kalidistatauwww). - Bun dan Node.js LTS terbaru, karena tooling Electron masih berjalan di Node.
- Untuk distribusi macOS, sertifikat Apple Developer ID. Untuk Windows, sertifikat penandatanganan code.
Langkah 1: Instal Electron dan packager
bun add -d electron electron-builder
Tambahkan electron/ folder di root proyek:
my-app/
capacitor.config.ts
dist/ # web build, shared with iOS and Android
electron/
main.ts
preload.ts
electron-builder.yml
Langkah 2: Muat build web dari disk
Electron memuat file dengan file:// protokol di produksi. Dua pengaturan penting:
- Path aset relatif. Dengan Vite, setel
base: './'agar buildindex.htmlmerujuk ke./assets/...alih-alih/assets/.... - Routing. Deep link seperti
/settingstidak ada dalam bentuk file. Gunakan hash routing untuk build desktop, atau pastikan router Anda hanya melakukan navigasi di sisi klien setelah dimuatindex.html.
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
base: './',
});
Path relatif juga berfungsi di iOS dan Android, jadi Anda tidak perlu build terpisah.
Langkah 3: Tulis main process
// electron/main.ts
import { app, BrowserWindow, ipcMain, shell } from 'electron';
import path from 'node:path';
const isDev = !app.isPackaged;
async function createWindow() {
const win = new BrowserWindow({
width: 1280,
height: 800,
minWidth: 800,
minHeight: 600,
show: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
});
win.once('ready-to-show', () => win.show());
// Open external links in the default browser, never inside the app.
// Only allow https: so a script cannot launch file: or other protocol handlers.
win.webContents.setWindowOpenHandler(({ url }) => {
try {
if (new URL(url).protocol === 'https:') void shell.openExternal(url).catch(() => {});
} catch {
// invalid URL: ignore
}
return { action: 'deny' };
});
if (isDev) {
await win.loadURL('http://localhost:5173');
win.webContents.openDevTools({ mode: 'detach' });
} else {
await win.loadFile(path.join(__dirname, '..', '..', 'dist', 'index.html'));
}
}
ipcMain.handle('desktop:get-version', () => app.getVersion());
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
Pertahankan contextIsolation: true, nodeIntegration: false, dan sandbox: true. Aplikasi web Anda mungkin memuat skrip pihak ketiga, dan tidak ada satu pun yang boleh mendapatkan akses Node.js.
Langkah 4: Ekspos API desktop kecil dari preload
// electron/preload.ts
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('desktop', {
isElectron: true,
platform: process.platform,
getVersion: () => ipcRenderer.invoke('desktop:get-version') as Promise<string>,
});
Ketik di code web Anda dan gunakan dengan cara yang sama seperti menggunakan plugin:
// src/desktop.ts
declare global {
interface Window {
desktop?: {
isElectron: boolean;
platform: string;
getVersion: () => Promise<string>;
};
}
}
export const isDesktop = () => Boolean(window.desktop?.isElectron);
Setiap fitur native-only yang Anda butuhkan di desktop menjadi satu ipcMain.handle di main process dan satu fungsi di preload. Validasi argumen di main process, karena renderer tidak dapat dipercaya.
Langkah 5: Build dan jalankan
Kompilasi file Electron dengan Bun. Preload berjalan dalam sandbox, jadi bundle menjadi satu file CommonJS:
{
"main": "electron/dist/main.js",
"scripts": {
"build": "vite build",
"electron:compile": "bun build electron/main.ts --outdir electron/dist --target node --format cjs --external electron && bun build electron/preload.ts --outdir electron/dist --target node --format cjs --external electron",
"electron:dev": "bun run electron:compile && electron .",
"electron:pack": "bun run build && bun run electron:compile && electron-builder"
}
}
Saat development, jalankan dev server di satu terminal (bun run dev) dan bun run electron:dev di terminal lain. Anda akan mendapatkan hot reload di jendela desktop.
Langkah 6: Kemas installer dengan electron-builder
# electron-builder.yml
appId: com.example.myapp
productName: My App
directories:
output: release
files:
- dist/**/*
- electron/dist/**/*
- package.json
mac:
target: [dmg, zip]
category: public.app-category.productivity
hardenedRuntime: true
win:
target: [nsis]
linux:
target: [AppImage, deb]
category: Utility
Jalankan bun run electron:pack. electron-builder membangun untuk OS tempat Anda menjalankannya. Gunakan matriks runner macOS, Windows, dan Linux di CI untuk menghasilkan ketiga versi tersebut.
| OS | Target umum | Signing |
|---|---|---|
| macOS | .dmg, .zip |
Sertifikat Developer ID plus notarization, atau Gatekeeper akan memblokir aplikasi |
| Windows | NSIS .exe, MSI |
sertifikat penandatanganan Code untuk menghindari peringatan SmartScreen |
| Linux | AppImage, .deb, .rpm |
Opsional |
Aplikasi Electron lebih besar daripada build mobile karena menyertakan Chromium dan Node.js. Harapkan installer berukuran sekitar 80 hingga 150 MB tergantung pada target.
Langkah 7: Kirim pembaruan web tanpa installer baru
Sebagian besar perubahan dalam aplikasi Capacitor adalah perubahan web. Di mobile, Anda dapat mengirimkannya dengan Live updates Capgo. Di desktop, @capgo/electron-updater melakukan pekerjaan yang sama dengan model yang sama: channel, bundle bawaan, bundle yang diunduh, dan rollback otomatis jika bundle baru tidak memanggil notifyAppReady().
bun add @capgo/electron-updater
Perbarui main process agar updater dapat memilih bundle yang akan dimuat:
// electron/main.ts (production branch)
import { ElectronUpdater, setupIPCHandlers, setupEventForwarding } from '@capgo/electron-updater';
const updater = new ElectronUpdater({
appId: 'com.example.myapp',
autoUpdate: true,
});
// inside createWindow(), instead of loading dist/index.html directly
const builtinPath = path.join(__dirname, '..', '..', 'dist', 'index.html');
await updater.initialize(win, builtinPath);
setupIPCHandlers(updater);
setupEventForwarding(updater, win);
await win.loadFile(updater.getCurrentBundlePath());
Tambahkan updater bridge ke file preload yang sama:
// electron/preload.ts (next to the desktop API)
import { exposeUpdaterAPI } from '@capgo/electron-updater/preload';
exposeUpdaterAPI();
Dan pastikan peluncuran dari web app berjalan normal, hanya di desktop:
import { isDesktop } from './desktop';
if (isDesktop()) {
const { requireUpdater } = await import('@capgo/electron-updater/renderer');
await requireUpdater().notifyAppReady();
}
Upload bundle baru dengan CLI yang sama seperti yang Anda gunakan untuk mobile:
bun run build
bunx @capgo/cli@latest bundle upload --channel=production
Pembaruan web tidak dapat mengubah Electron itu sendiri, main process, atau preload. Untuk itu, rilis installer baru dengan binary auto-updater. Panduan kami tentang Auto-update Electron membahas jalur itu, dan halaman plugin electron-updater dan dokumentasi membahas semua opsi.
Pemecahan Masalah
Jendela kosong di aplikasi yang sudah di-package. Assets menggunakan path absolut. Set base: './' dan rebuild. Buka DevTools di aplikasi yang sudah di-package untuk memastikan 404 pada file:///assets/....
Routes menampilkan halaman kosong setelah reload. Router mencoba memuat /route dari disk. Ganti ke hash routing untuk desktop.
require is not defined atau error preload. Preload yang di-sandbox tidak bisa memuat package sembarang saat runtime. Bundle menjadi satu file, seperti di script compile di atas.
Panggilan plugin ditolak dengan “not implemented on web”. Plugin tersebut tidak memiliki implementasi web. Tambahkan IPC handler di main process dan panggil melalui window.desktop.
macOS mengatakan aplikasi rusak atau dari developer yang tidak dikenal. Aplikasi belum ditandatangani dan dinotarisasi. Konfigurasikan sertifikat Developer ID dan notarization di electron-builder.
Update di-rollback tepat setelah instalasi. notifyAppReady() tidak dipanggil dalam timeout (default 10 detik). Panggil lebih awal saat startup aplikasi Anda.
Kesimpulan
Anda tidak perlu paket platform Capacitor khusus untuk menjangkau desktop. Main process Electron yang ringkas, preload yang mengekspos API bertipe, path aset relatif, dan electron-builder memberi Anda installer untuk ketiga sistem operasi dari build web yang sama. Tambahkan @capgo/electron-updater dan aplikasi desktop mendapat alur kerja live update yang sama dengan build iOS dan Android Anda. Jika Anda masih memilih runtime desktop, baca perbandingan Electron vs Tauri kami.