Allez directement au contenu principal.

Créer une application bureau avec Capacitor et Electron (2026)

Transformez votre application Capacitor en application bureau avec Electron : configuration de shell sécurisée, stratégie de plugin, packaging pour macOS, Windows, Linux et mises à jour en temps réel.

Crédits de l'article

M. Donadieu

Auteur

Valeria

Relecteur

Jordan

Éditeur

Construirez une application bureau avec Capacitor et Electron (2026)

Pour créer une application bureau à partir d'une application Capacitor, enveloppez la même build web.webDir) dans une coquille Electron : un processus principal qui ouvre un BrowserWindow, un script de préchargement qui expose une petite application bureau API, et electron-builder pour produire des installateurs pour macOS, Windows et Linux. Votre interface utilisateur et votre logique métier restent partagées avec iOS et Android, et les fonctionnalités uniquement bureau vivent dans le processus principal Electron.

Cette guide couvre l'état actuel de Capacitor sur Electron en 2026, un setup sécurisé qui fonctionne avec Capacitor 8, le comportement des plugins, la mise en boîte et la signature, et comment envoyer des mises à jour web sans nouveaux installateurs.

L'état de Capacitor sur Electron en 2026

Pendant des années, la réponse par défaut était @capacitor-community/electron, qui a branché Electron sur le Capacitor CLI en tant que plateforme. Ce projet est maintenant marqué comme non maintenu dans son fichier README. Son dernier npm de version 5.0.1, a été livré en septembre 2023, nécessite Capacitor 5.4 ou ultérieur, et a été construit contre Electron 26. Electron a livré de nombreuses versions majeures depuis, et seuls les trois derniers majors reçoivent des correctifs de sécurité.

Vous pouvez toujours l'utiliser sur des projets anciens, mais pour un Capacitor 8, la comparaison ressemble à ceci :

Approche Avantages Cons
Votre propre coquille Electron (ce guide) Contrôl’Electron complet, sans abstraction supplémentaire Vous écrivez environ 60 lignes de main et de préchargement code
@capacitor-community/electron Connu cap commandes Non maintenu, bloqué sur une ancienne Capacitor et Electron

L'approche de shell est moins fastidieuse qu'elle ne le semble, car Capacitor produit déjà une mise en page web statique. Electron n'a besoin que de la charger.

Le comportement des plugins dans Electron

Le rendu de Electron est Chromium, donc votre application Capacitor s'exécute là comme elle le ferait dans un navigateur. Le noyau de Capacitor détecte pas de pont natif et recule sur chaque implémentation web du plugin.

Type de plugin Fonctionne-t-il dans Electron? Qu'est-ce à faire
Plugin avec une implémentation web (Préférences, Partage, Presse-papier, nombreux plugins Capgo) Oui, en utilisant la version web Tester le comportement web
Plugin natif uniquement (pas d'implémentation web) No, rejette comme non implémenté Écrivez un équivalent Electron derrière un préchargement API
Bibliothèques JS pures Oui Rien

Capacitor.getPlatform() retourne 'web' dans ce setup et Capacitor.isNativePlatform() retourne false. Nous exposons un drapeau de bureau explicite depuis le script de préchargement afin que votre code puisse brancher proprement.

Prerequisites

  • Une application Capacitor dont bun run build produit un dossier statique (le webDir in capacitor.config.ts, souvent dist ou www).
  • Bun et une version LTS Node.js actuelle, car les outils Electron fonctionnent toujours sur Node.
  • Pour la distribution macOS, un certificat Apple Developer ID. Pour Windows, un certificat de signature code.

Étape 1 : Installez Electron et le packager

bun add -d electron electron-builder

Ajoutez un electron/ dossier au niveau du projet :

my-app/
  capacitor.config.ts
  dist/              # web build, shared with iOS and Android
  electron/
    main.ts
    preload.ts
  electron-builder.yml

Étape 2 : Faites charger la construction web depuis le disque

Electron charge les fichiers avec le file:// protocole en production. Deux paramètres sont importants :

  1. Chemins d'asset relatifs. With Vite, configurez base: './' pour que les fichiers index.html soient référencés ./assets/... au lieu de /assets/....
  2. la navigation. Les liens profonds comme /settings Utilisez la navigation client côté pour le build bureau, ou assurez-vous que votre routeur ne navigue que côté client après chargement. index.html.
// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  base: './',
});

Les chemins relatifs fonctionnent également sur iOS et Android, vous n'avez donc pas besoin d'une build séparée.

Étape 3 : Écrivez le processus principal

// 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();
});

Keep contextIsolation: true, nodeIntegration: falseConservez sandbox: trueVotre application web peut charger des scripts tiers, et aucun d'entre eux ne doit accéder à Node.js.

Étape 4 : Exposez un petit bureau API depuis la préchargement

// 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>,
});

Typez-le dans votre code web et utilisez-le de la même manière que vous utiliseriez un plugin :

// src/desktop.ts
declare global {
  interface Window {
    desktop?: {
      isElectron: boolean;
      platform: string;
      getVersion: () => Promise<string>;
    };
  }
}

export const isDesktop = () => Boolean(window.desktop?.isElectron);

Chaque fonctionnalité native uniquement nécessaire sur le bureau devient une ipcMain.handle une dans le processus principal et une fonction dans la préchargement. Validez les arguments dans le processus principal, car le rendu est non fiable.

Étape 5 : Construire et exécuter

Compilez les fichiers Electron avec Bun. La préchargement s'exécute en sandbox, il faut donc la bundler en un seul fichier 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"
  }
}

Durant le développement, démarrez votre serveur de développement dans un terminal (bun run dev) et bun run electron:dev en un autre. Vous obtenez un redémarrage chaud dans la fenêtre du bureau.

Étape 6 : Installer des packages avec 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

Exécutez bun run electron:packelectron-builder construit pour le système d'exploitation sur lequel vous l'exécutez. Utilisez une matrice de lanceurs macOS, Windows et Linux dans CI pour produire les trois.

OS Cibles courantes Signature
macOS .dmg, .zip Certificat de développeur ID plus notarisation, ou Gatekeeper bloque l'application
Windows NSIS .exe, MSI Code certificat de signature pour éviter les avertissements de SmartScreen
Linux AppImage, .deb, .rpm Facultatif

Les applications Electron sont plus grandes que les builds mobiles car elles incluent Chromium et Node.js. Attendez-vous à des installateurs d'environ 80 à 150 MB en fonction des cibles.

Étape 7 : Envoyez des mises à jour web sans nouveaux installateurs

La plupart des modifications dans une application Capacitor sont des changements web. Vous pouvez les déployer sur mobile. les mises à jour Capgo en direct. Sur le bureau, @capgo/electron-updater Faites la même chose avec le même modèle : les canaux, un bundle intégré, les bundles téléchargés, et le retrait automatique si le nouveau bundle ne fonctionne pas. notifyAppReady().

bun add @capgo/electron-updater

Mettez à jour le processus principal pour permettre à l'actualiseur de choisir le bundle à charger :

// 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());

Ajoutez le pont de l'actualiseur au même fichier de préchargement :

// electron/preload.ts (next to the desktop API)
import { exposeUpdaterAPI } from '@capgo/electron-updater/preload';

exposeUpdaterAPI();

Et confirmez un lancement sain depuis l'application web, uniquement sur le bureau :

import { isDesktop } from './desktop';

if (isDesktop()) {
  const { requireUpdater } = await import('@capgo/electron-updater/renderer');
  await requireUpdater().notifyAppReady();
}

Téléchargez un nouveau bundle avec le même CLI que vous utilisez pour mobile :

bun run build
bunx @capgo/cli@latest bundle upload --channel=production

Les mises à jour web ne peuvent pas modifier Electron lui-même, le processus principal ou le préchargement. Pour ceux-ci, envoyez un nouveau installateur avec un actualiseur auto-actualiseur. Notre guide sur les mises à jour Electron couvre cette trajectoire, et le page du plugin electron-updater et docs couvre toutes les options.

Troubleshooting

fenêtre blanche dans l'application embarquée. Les assets utilisent des chemins absolus. Définissez base: './' and rebuild. Open DevTools in the packaged app to confirm 404s on file:///assets/....

Les routes affichent une page blanche après rechargement. Le routeur a essayé de charger /route À partir du disque. Passer à la navigation par hash pour le bureau.

require is not defined ou les erreurs de chargement préalable. Le préchargement sandboxé ne peut pas charger des packages arbitraires en temps de exécution. Emballez-le dans un seul fichier, comme dans le script de compilation ci-dessus.

Une appelle de plugin rejette avec "non implémenté sur le web". Cette plugin n'a pas d'implémentation web. Ajoutez un gestionnaire d'IPC dans le processus principal et appelez-l’à travers window.desktop.

macOS dit que l'application est endommagée ou provient d'un développeur non identifié. L'application n'est pas signée et notarisée. Configurez un certificat de développeur ID et la notarisation dans electron-builder.

Updates roll back right after install. notifyAppReady() n'a pas été appelé dans le délai (10 secondes par défaut). Appelez-le tôt dans le démarrage de votre application.

Rappel

Vous n'avez pas besoin d'un package de plateforme dédié Capacitor pour atteindre le bureau. Un processus principal Electron court, un chargement préalable qui expose un API typé, des chemins d'asset relatifs et electron-builder vous donnent des installateurs pour les trois systèmes d'exploitation à partir d'une même build web. Ajoutez @capgo/electron-updater et l'application bureau obtient le même workflow live update que vos builds iOS et Android. Si vous choisissez toujours un runtime bureau, lisez notre Comparaison Electron vs Tauri.

Mises à jour en direct pour les applications Capacitor

Quand un bug de layer web est en direct, envoyer la correction par le biais de Capgo au lieu d'attendre des jours pour l'approbation de l'app store. Les utilisateurs reçoivent la mise à jour en arrière-plan tandis que les changements natifs restent dans la voie de revue normale.

Dernières actualités de notre Blog

Capgo vous donne les meilleures informations dont vous avez besoin pour créer une application mobile vraiment professionnelle.