Maîtriser les Applications Desktop Multiplateformes avec Electron et Tauri
Maîtriser les Applications Desktop Multiplateformes avec Electron et Tauri

Développement d'Applications avec Electron : Premiers Pas et Interface Utilisateur

Bienvenue dans cette leçon dédiée aux fondamentaux d'Electron. Dans le cadre de notre cours sur la Maîtrise des Applications Desktop Multiplateformes avec Electron et Tauri, nous allons explorer comment Electron vous permet de bâtir des applications de bureau robustes en utilisant les technologies web que vous connaissez déjà.

Introduction à Electron

Qu'est-ce qu'Electron ?

Electron est un framework open-source développé par GitHub. Son objectif principal est de permettre aux développeurs de créer des applications de bureau multiplateformes (Windows, macOS, Linux) en utilisant des technologies web : HTML, CSS et JavaScript.

Plusieurs applications populaires que vous utilisez peut-être quotidiennement sont construites avec Electron, notamment :

  • VS Code (l'éditeur de code de Microsoft)
  • Slack
  • Discord
  • Notion
  • Figma Desktop App

Cela démontre la puissance et la flexibilité d'Electron pour des applications allant des éditeurs de texte aux outils de communication et de productivité.

Pourquoi Electron dans un cours sur les applications multiplateformes ?

Electron est un choix privilégié pour de nombreux projets pour plusieurs raisons :

  • Familiarité pour les développeurs web : Si vous maîtrisez HTML, CSS et JavaScript, vous êtes déjà bien équipé pour commencer avec Electron.
  • Écosystème Node.js et npm : Accès à des millions de modules et librairies via npm, facilitant le développement et l'intégration de fonctionnalités.
  • Accès aux API système : Electron ne se contente pas de "simplement afficher une page web". Il expose des API Node.js complètes, permettant d'interagir avec le système d'exploitation (système de fichiers, notifications, menus natifs, etc.).

Bien qu'il existe des alternatives plus récentes comme Tauri (que nous explorerons plus tard), Electron reste une pierre angulaire dans le développement d'applications de bureau. Il est plus mature, offre une grande flexibilité et une vaste communauté. Comprendre Electron est essentiel pour toute personne souhaitant naviguer dans le paysage des applications de bureau multiplateformes.

Les Fondamentaux d'Electron

Pour comprendre comment Electron fonctionne, il est crucial de saisir son architecture unique, basée sur deux composants majeurs et la notion de processus.

Architecture : Chromium et Node.js

Electron combine deux puissantes technologies en une seule application :

  1. Chromium : C'est le projet open-source derrière le navigateur Google Chrome. Dans Electron, Chromium est utilisé comme moteur de rendu web. Il est responsable de l'affichage de votre interface utilisateur (HTML, CSS, images, etc.) et de l'exécution du JavaScript côté client.
  2. Node.js : C'est un environnement d'exécution JavaScript côté serveur. Dans Electron, Node.js fournit l'accès aux API système natives. Il permet à votre application de lire et écrire des fichiers, d'accéder au réseau, de gérer les processus, et d'interagir avec le système d'exploitation de manière approfondie.

C'est cette synergie qui rend Electron si puissant : la capacité d'avoir une interface utilisateur riche et interactive (Chromium) tout en ayant un accès complet aux capacités du système (Node.js).

Processus Principal (Main Process)

Le processus principal est le cœur de votre application Electron.

  • Rôle : Il gère le cycle de vie de l'application, crée et gère les fenêtres de l'interface utilisateur.
  • Environnement : Il s'exécute dans un environnement Node.js.
  • Accès aux API système : Le processus principal a un accès direct et complet à toutes les API Node.js et Electron natives pour interagir avec le système d'exploitation.
  • Point d'entrée : Chaque application Electron démarre avec un seul processus principal, défini par le script main dans votre fichier package.json (généralement main.js). Il est le seul processus à pouvoir créer des instances de BrowserWindow.

Processus de Rendu (Renderer Process)

Chaque fenêtre de votre application Electron s'exécute dans son propre processus de rendu.

  • Rôle : Il est responsable de l'affichage de l'interface utilisateur de cette fenêtre. C'est ici que votre HTML, CSS et JavaScript "côté client" sont exécutés.
  • Environnement : Il s'exécute dans un environnement de navigateur web (Chromium), similaire à un onglet de navigateur.
  • Accès limité aux API système : Par défaut, pour des raisons de sécurité, les processus de rendu n'ont pas un accès direct aux API Node.js. Ils sont "isolés" de l'environnement système.

Communication entre Processus (IPC - Inter-Process Communication)

Étant donné que le processus principal et les processus de rendu s'exécutent dans des environnements isolés, ils ont besoin d'un mécanisme pour communiquer entre eux. C'est le rôle de l'Inter-Process Communication (IPC).

  • Les modules ipcMain (dans le processus principal) et ipcRenderer (dans les processus de rendu) d'Electron permettent cette communication asynchrone et bidirectionnelle.
  • Par exemple, un processus de rendu pourrait envoyer un message au processus principal pour lui demander d'accéder au système de fichiers, et le processus principal pourrait renvoyer les données demandées.

Premiers Pas avec Electron

Nous allons maintenant configurer un projet Electron de base et comprendre sa structure.

Prérequis

Avant de commencer, assurez-vous d'avoir installé :

  • Node.js et npm (Node Package Manager) : Ce sont les outils essentiels pour gérer les dépendances de votre projet et exécuter Electron. Vous pouvez les télécharger depuis nodejs.org.
  • Connaissances de base en HTML, CSS, JavaScript : Vous utiliserez ces technologies pour construire votre interface utilisateur.

Initialisation d'un projet Electron

Suivez ces étapes pour démarrer un nouveau projet :

  1. Créez un dossier pour votre projet :

    mkdir mon-premier-compteur
    cd mon-premier-compteur
    
  2. Initialisez un projet Node.js : Cela crée un fichier package.json qui gérera les métadonnées de votre projet et ses dépendances.

    npm init -y
    

    Le flag -y accepte toutes les options par défaut.

  3. Installez Electron : Ajoutez Electron comme dépendance de développement à votre projet.

    npm install electron --save-dev
    

Structure de base d'un projet

Une fois les étapes précédentes terminées, votre projet aura une structure minimale avec les fichiers suivants que nous allons créer :

  • package.json : Le fichier de configuration du projet Node.js.
  • main.js : Le script JavaScript qui s'exécute dans le Processus Principal. C'est le point d'entrée de votre application Electron.
  • index.html : Le fichier HTML qui définit l'interface utilisateur de votre fenêtre principale. Il sera chargé par le processus de rendu.
  • renderer.js : Un script JavaScript exécuté dans le Processus de Rendu, qui interagit avec le DOM de index.html.
  • style.css : Un fichier CSS pour la mise en forme de votre interface utilisateur.

Développement de l'Interface Utilisateur (UI)

L'un des plus grands avantages d'Electron est qu'il vous permet d'utiliser toutes les technologies web que vous maîtrisez pour construire votre UI.

Utilisation des technologies web standards

  • HTML : Pour structurer le contenu de votre interface (boutons, texte, images, formulaires, etc.).
  • CSS : Pour styliser votre interface, contrôler la mise en page, les couleurs, les polices, etc.
  • JavaScript : Pour ajouter de l'interactivité, gérer les événements, manipuler le DOM, et même faire des requêtes réseau si nécessaire (bien que les requêtes système soient généralement déléguées au processus principal).

Chargement d'une fenêtre et de son contenu

Le processus principal est responsable de la création de fenêtres d'application. Il utilise la classe BrowserWindow d'Electron.

Chaque instance de BrowserWindow est une fenêtre native du système d'exploitation et contient son propre processus de rendu. Vous pouvez charger du contenu HTML dans ces fenêtres via des méthodes comme loadFile() ou loadURL().

Projet Pratique : Mon Premier Compteur Electron

Nous allons maintenant mettre en pratique ces concepts en créant une application Electron simple : un compteur qui peut être incrémenté via un bouton.

1. Structure du projet

Assurez-vous d'avoir suivi les étapes d'initialisation :

  • Créez un dossier mon-premier-compteur.
  • À l'intérieur, exécutez npm init -y puis npm install electron --save-dev.

2. Le fichier package.json

Ouvrez le fichier package.json et modifiez la section scripts pour y ajouter une commande de démarrage :

{
  "name": "mon-premier-compteur",
  "version": "1.0.0",
  "description": "Un simple compteur avec Electron",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^28.0.0"
  }
}

Explication : Le script "start": "electron ." est crucial. Il indique à npm d'exécuter l'exécutable electron dans le répertoire courant (.). Electron cherchera alors le fichier défini par la propriété "main" (ici main.js) pour démarrer l'application.

3. Le fichier main.js (Processus Principal)

Créez un fichier nommé main.js à la racine de votre projet :

const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
  // Crée une nouvelle fenêtre de navigateur Electron.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      // Configuration importante pour la sécurité et l'accès aux API Node.js :
      // Note: Pour des applications de production, il est fortement recommandé
      // d'utiliser 'contextIsolation: true' et un 'preload' script
      // pour un accès sécurisé et contrôlé aux API Node.js depuis le renderer.
      // Pour cet exemple introductif, nous simplifions l'accès au DOM.
      nodeIntegration: true, // Permet l'accès aux API Node.js dans le processus de rendu
      contextIsolation: false // Désactive l'isolation du contexte pour simplifier l'exemple
    }
  });

  // Charge le fichier index.html dans la fenêtre principale.
  mainWindow.loadFile('index.html');

  // Optionnel : Ouvre les outils de développement (DevTools) de Chromium pour le débogage.
  // Décommentez la ligne suivante pour les activer au démarrage.
  // mainWindow.webContents.openDevTools();
}

// Cette méthode est appelée quand Electron a fini de s'initialiser
// et est prêt à créer des fenêtres de navigateur.
// Certaines API ne peuvent être utilisées qu'après cet événement.
app.whenReady().then(() => {
  createWindow();

  // Sur macOS, les applications restent généralement actives même sans fenêtres ouvertes.
  // Si l'application est activée (par exemple, clic sur l'icône du dock)
  // et qu'il n'y a pas de fenêtres ouvertes, on en crée une nouvelle.
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

// Quitte l'application quand toutes les fenêtres sont fermées, sauf sur macOS.
// Sur macOS, il est courant pour les applications de rester actives tant que
// l'utilisateur ne les quitte pas explicitement (Cmd + Q ou menu).
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

Explication :

  • const { app, BrowserWindow } = require('electron'); : Importe les modules nécessaires d'Electron. app contrôle le cycle de vie de l'application, et BrowserWindow permet de créer des fenêtres.
  • createWindow() : Cette fonction crée une nouvelle instance de BrowserWindow. Les options width et height définissent les dimensions initiales.
  • webPreferences : Configure l'environnement web de la fenêtre.
    • nodeIntegration: true : Permet au JavaScript dans le processus de rendu (votre renderer.js) d'accéder directement aux API Node.js (comme require ou process). Attention : Pour des applications de production, désactiver ceci (false) et utiliser un script preload est une pratique de sécurité essentielle. Nous le laissons à true ici pour simplifier ce premier exemple.
    • contextIsolation: false : Désactive l'isolation des contextes JavaScript. Pour la production, il est crucial de le laisser à true et d'utiliser un script preload sécurisé.
  • mainWindow.loadFile('index.html'); : Charge le fichier index.html que nous allons créer, qui deviendra l'interface utilisateur de cette fenêtre.
  • app.whenReady().then(...) : Assure que la fonction createWindow() est appelée une fois qu'Electron est complètement initialisé.
  • Les écouteurs d'événements app.on('activate', ...) et app.on('window-all-closed', ...) gèrent le comportement de l'application lors de la fermeture des fenêtres, en tenant compte des spécificités de macOS.

4. Le fichier index.html (Interface Utilisateur)

Créez un fichier nommé index.html à la racine de votre projet :

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Mon Compteur Electron</title>
    <!-- Inclut notre feuille de style CSS -->
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Compteur Electron</h1>
    <p>Le compteur actuel est : <span id="counter">0</span></p>
    <button id="increment-btn">Incrémenter</button>

    <!-- Inclut notre script JavaScript pour le processus de rendu -->
    <script src="renderer.js"></script>
</body>
</html>

Explication :

  • C'est un fichier HTML standard.
  • Il contient un titre (<h1>), un paragraphe (<p>) avec un <span> (ID counter) pour afficher la valeur du compteur, et un bouton (<button>, ID increment-btn) pour l'incrémenter.
  • link rel="stylesheet" href="style.css" : Lie notre fichier CSS pour la mise en forme.
  • script src="renderer.js" : Inclut notre script JavaScript qui gérera la logique de l'interface utilisateur. Il est placé à la fin du <body> pour s'assurer que tous les éléments HTML sont chargés avant que le script ne tente de les manipuler.

5. Le fichier style.css (Mise en forme)

Créez un fichier nommé style.css à la racine de votre projet :

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh; /* Prend toute la hauteur de la fenêtre */
    margin: 0;
    background-color: #282c34; /* Arrière-plan sombre */
    color: #abb2bf; /* Texte clair */
}

h1 {
    color: #61afef; /* Couleur de titre */
    margin-bottom: 20px;
}

p {
    font-size: 1.2em;
    margin-bottom: 30px;
}

#counter {
    font-weight: bold;
    color: #98c379; /* Couleur du compteur */
    font-size: 2em; /* Taille du texte du compteur */
    display: block; /* Pour s'assurer qu'il prend sa propre ligne si nécessaire */
    margin-top: 10px;
}

button {
    background-color: #c678dd; /* Couleur de bouton vive */
    color: white;
    padding: 12px 25px;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 1.1em;
    transition: background-color 0.3s ease, transform 0.1s ease;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

button:hover {
    background-color: #a453be; /* Couleur au survol */
    transform: translateY(-2px); /* Effet de léger déplacement au survol */
}

button:active {
    transform: translateY(0); /* Effet de pression au clic */
    background-color: #8c42a3;
}

Explication : Ce CSS simple centre le contenu de l'application et applique un thème sombre avec des couleurs contrastées pour une meilleure lisibilité. Il ajoute également des effets de survol et de clic pour le bouton.

6. Le fichier renderer.js (Processus de Rendu)

Créez un fichier nommé renderer.js à la racine de votre projet :

// Attends que le DOM soit entièrement chargé avant d'exécuter le script
document.addEventListener('DOMContentLoaded', () => {
    // Récupère les éléments HTML par leur ID
    const counterElement = document.getElementById('counter');
    const incrementBtn = document.getElementById('increment-btn');

    let count = 0; // Initialise la variable du compteur

    // Fonction pour mettre à jour l'affichage du compteur dans l'interface
    function updateCounter() {
        counterElement.textContent = count;
    }

    // Ajoute un écouteur d'événements au bouton d'incrémentation
    incrementBtn.addEventListener('click', () => {
        count++; // Incrémente le compteur
        updateCounter(); // Met à jour l'affichage
    });

    // Appelle la fonction une première fois pour afficher la valeur initiale (0)
    updateCounter();
});

Explication :

  • document.addEventListener('DOMContentLoaded', ...) : Ce code s'assure que le script ne s'exécute qu'une fois que tous les éléments HTML de la page sont disponibles dans le DOM.
  • document.getElementById() : Utilisé pour obtenir des références aux éléments HTML avec les IDs counter et increment-btn.
  • let count = 0; : Déclare une variable JavaScript count qui stockera la valeur actuelle du compteur.
  • updateCounter() : Une fonction simple qui prend la valeur de count et la met à jour dans le <span> de l'interface.
  • incrementBtn.addEventListener('click', ...) : Attache un écouteur d'événements au bouton. Chaque fois que le bouton est cliqué, la fonction anonyme est exécutée, incrémentant count et appelant updateCounter() pour rafraîchir l'affichage.

7. Exécuter l'application

Maintenant que tous les fichiers sont en place, ouvrez un terminal dans le dossier mon-premier-compteur et exécutez la commande :

npm start

Vous devriez voir une fenêtre Electron s'ouvrir, affichant votre compteur et le bouton "Incrémenter". Chaque clic sur le bouton devrait augmenter la valeur affichée !

Félicitations, vous avez créé votre première application Electron fonctionnelle !

Conclusion et Prochaines Étapes

Résumé des concepts clés

Dans cette leçon, nous avons démystifié les premiers pas dans le développement d'applications avec Electron :

  • Electron permet de créer des applications de bureau multiplateformes en réutilisant vos compétences en HTML, CSS et JavaScript.
  • Son architecture repose sur l'intégration de Chromium pour l'interface utilisateur et Node.js pour l'accès aux fonctionnalités système.
  • Nous avons différencié le Processus Principal (qui gère l'application et les fenêtres, avec accès complet aux API Node.js) et le Processus de Rendu (qui affiche l'interface utilisateur de chaque fenêtre).
  • Nous avons mis en place une structure de projet de base incluant package.json, main.js, index.html, style.css, et renderer.js.
  • Le projet pratique "Mon Premier Compteur Electron" a démontré comment lier ces composants pour créer une interface utilisateur interactive.

Pour aller plus loin

Ce n'était qu'un aperçu des possibilités d'Electron. Pour construire des applications plus complexes et robustes, les prochaines étapes de votre apprentissage devraient inclure :

  • Communication Inter-Processus (IPC) : Apprenez à faire communiquer de manière sécurisée et efficace le processus principal et les processus de rendu. C'est essentiel pour accéder aux fonctionnalités système depuis votre UI.
  • Menus et Context Menus : Comment créer des menus d'application natifs, des menus contextuels, et les gérer via le processus principal.
  • Notifications Natives : Envoyer des notifications système à l'utilisateur.
  • Packaging et Distribution : Comprendre comment transformer votre code source en un fichier installable (.exe, .dmg, .deb) pour distribuer votre application. Des outils comme electron-builder ou electron-packager sont indispensables.
  • Sécurité des Applications Electron : Approfondir les bonnes pratiques de sécurité, notamment l'utilisation correcte de contextIsolation et des scripts preload pour prévenir les vulnérabilités.
  • Intégration de Frameworks UI : Comment utiliser des frameworks JavaScript populaires comme React, Vue.js, ou Angular pour construire des interfaces utilisateur complexes dans Electron.
  • Comparaison Approfondie avec Tauri : Une fois les bases d'Electron maîtrisées, nous pourrons mieux comprendre les avantages et inconvénients de Tauri, et quand choisir l'un ou l'autre en fonction des exigences de votre projet.

Continuez à explorer et à construire ! Le monde des applications de bureau multiplateformes est à portée de main.