Aller au contenu principal

Créer votre première application

Objectifs

Dans cette partie du tutoriel, vous apprendrez comment configurer votre projet Electron et écrire une simple application pour débuter. À la fin de cette section, vous devriez être en mesure d'exécuter une application Electron fonctionnelle en mode développement depuis votre terminal.

Configuration de votre projet

Évitez WSL

Si vous êtes sur une machine Windows, veuillez ne pas utiliser le Windows Subsystem pour Linux (WSL) pour suivre ce tutoriel car vous rencontreriez alors des problèmes lors de l'exécution de l'application .

Initialisation de votre projet npm

Les applications Electron sont édifiées à l'aide de npm, avec le fichier package.json comme point d'entrée. Commencez par créer un dossier et exécutez npm init qui va créer et configurer le fichier package. json.

mkdir my-electron-app && cd my-electron-app
npm init

Cette commande vous demande alors certaines informations afin de configurer certains champs du fichier package.json. Quelques règles devront être suivies pour les besoins de ce tutoriel:

  • entry point doit être renseigné avec main.js (vous créerez ce fichier un peu plus loin).
  • author, license, and description can be any value, but will be necessary for packaging later on.

Ensuite, installez Electron dans le devDependencies de votre application, qui est la liste des dépendances de modules externes nécessaires pour le développement et non requises en production.

Pourquoi mettre Electron dans les devDependencies ?

Cela peut sembler, au prime abord, contre-intuitif puisque votre code de production exécute des API Electron. Cependant, les applications empaquetées sont livrées avec le binaire Electron, ce qui élimine ainsi le besoin de le spécifier comme dépendance de production.

npm install electron --save-dev

Maintenant, après avoir initialisé votre fichier package.json et installé Electron votre fichier package.json devrait ressembler à ce qui suit. Vous devriez également avoir un dossier node_modules contenant l'exécutable d'Electron, ainsi qu'un fichier de verrouillage package-lock.json qui spécifie les versions exactes des dépendances à installer.

package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
Procédure d’installation avancée d'Electron

If installing Electron directly fails, please refer to our Advanced Installation documentation for instructions on download mirrors, proxies, and troubleshooting steps.

Ajout d'un .gitignore

Le fichier .gitignore indique à git quels fichiers et répertoires ne sont pas à tracker. Vous devez placer une copie basée sur le modèle de gitignore pour Node.js dans le dossier racine de votre projet afin d'éviter au moins le tracking du dossier node_modules de votre projet.

Exécution d'une application Electron

Lectures complémentaires

Read Electron's process model documentation to better understand how Electron's multiple processes work together.

Le script main que vous avez défini dans package.json est le point d'entrée de toute application Electron. Ce script contrôle le **processus principal **, qui s’exécute dans un environnement Node.js et est responsable du contrôle du cycle de vie de votre application, de l’affichage des interfaces natives, de l’exécution d’opérations privilégiées et de la gestion des processus de rendu (nous y reviendrons plus tard).

Avant de créer votre première application Electron, vous allez tout d’abord utiliser un script trivial afin de vous assurer que le point d’entrée du processus principal est correctement configuré. Vous allez donc pour cela créer un fichier main.js dans le dossier racine de votre projet avec une seule ligne de code :

main.js
console.log('Hello from Electron 👋')

Because Electron's main process is a Node.js runtime, you can execute arbitrary Node.js code with the electron command (you can even use it as a REPL). Pour exécuter ce script, il vous suffit d'ajouter electron . à la commande start dans le champ scripts de votre package.json. Cette commande indique à l'exécutable Electron de rechercher le script principal dans le répertoire courant et de l'exécuter en mode dev.

package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
npm run start

Votre terminal devrait alors afficher Hello from Electron 👋. Félicitations, vous venez d'exécuter votre première ligne de code avec Electron! Maintenant , vous allez apprendre comment créer des interfaces utilisateur avec HTML et les charger dans une fenêtre native.

Chargement d’une page Web dans une BrowserWindow

Avec Electron, chaque fenêtre affiche une page Web qui peut être chargée à partir d'un fichier HTML local ou d'une adresse Web distante. Pour cet exemple, vous allez charger un fichier local. Commencez par créer un squelette de page web dans un fichier index.html à la racine de votre projet :

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Bonjour depuis le rendu d'Electron !</title>
</head>
<body>
<h1>Bonjour depuis le rendu d'Electron !</h1>
<p>👋</p>
</body>
</html>

Now that you have a web page, you can load it into an Electron BrowserWindow. Remplacez le contenu de votre fichier main.js par le code suivant. Nous expliquerons séparement chaque bloc de code.

main.js
const { app, BrowserWindow } = require('electron')

const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})

win.loadFile('index.html')
}

app.whenReady().then(() => {
createWindow()
})

Importation de modules

main.js (Line 1)
const { app, BrowserWindow } = require('electron')

Dans cette première ligne, nous importons deux modules Electron avec la syntaxe des module CommonJS :

  • app, which controls your application's event lifecycle.
  • BrowserWindow, which creates and manages app windows.
Conventions d'usage des majuscules d'un module

Vous avez peut-être remarqué la différence de majuscule entre les modules de app et BrowserWindow. Electron suit ici les conventions JavaScript typiques, où les modules nommés en Pascal case sont des constructeurs de classes instanciables (par ex. BrowserWindow, Tray, Notification) alors que les modules nommés en Camel case ne sont pas instanciables (par exemple, app, ipcRenderer, webContents).

Alias pour les importations typées

For better type checking when writing TypeScript code, you can choose to import main process modules from electron/main.

const { app, BrowserWindow } = require('electron/main')

For more information, see the Process Model docs.

ES Modules in Electron

ECMAScript modules (i.e. using import to load a module) are supported in Electron as of Electron 28. You can find more information about the state of ESM in Electron and how to use them in our app in our ESM guide.

Écriture d’une fonction réutilisable pour instancier des fenêtres

La fonction createWindow() charge votre page web dans une nouvelle instance de BrowserWindow :

main.js (Lines 3-10)
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})

win.loadFile('index.html')
}

Appel de votre fonction lorsque l’application est prête

main.js (Lines 12-14)
app.whenReady().then(() => {
createWindow()
})

De nombreux modules de base d’Electron sont des émetteurs d’événements Node.js qui adhèrent à l’architecture événementielle asynchrone de Node. Le module app est l’un de ces émetteurs.

In Electron, BrowserWindows can only be created after the app module's ready event is fired. You can wait for this event by using the app.whenReady() API and calling createWindow() once its promise is fulfilled.

info

Typiquement, vous écoutez les événements Node.js à l’aide de la fonction .on d’un émetteur.

+ app.on('ready', () => {
- app.whenReady().then(() => {
createWindow()
})

Toutefois, Electron expose la fonction helper app.whenReady() pour l’événement ready afin d’éviter les pièges subtils pouvant survenir lors de l'écoute directe de cet événement. Voir electron/electron#21972 sur github pour plus de détails.

Arrivé à ce stade, l’exécution du script start de votre application Electron devrait ouvrir avec succès une fenêtre qui affiche votre page Web!

Chaque page Web affichée par votre application dans une fenêtre s’exécutera dans un processus distinct appelé **processus de rendu ** (ou simplement renderer ). Les processus de rendu ont accès aux mêmes API et outils JavaScript que ceux utilisés pour le développement front-end classique, tels que Webpack pour regrouper et minimiser votre code ou React pour créer vos interfaces utilisateur.

Gestion du cycle de vie des fenêtres de votre application

Les fenêtres d'une application se comportent différemment selon le système d’exploitation. Plutôt que d’appliquer ces conventions par défaut, Electron vous permet de choisir de les implémenter dans votre code si vous souhaitez les suivre . Vous pouvez implémenter ces conventions de base en écoutant les événements émis par les modules app et BrowserWindow.

Flux de contrôle spécifique au processus

La vérification de la propriété process.platform de Node peut vous aider à exécuter conditionnellement du code sur certaines plates-formes. Notez qu'Electron ne peut fonctionner que sur trois plates-formes : win32 (Windows), linux (Linux), et darwin (macOS).

Quitter l'application lorsque toutes les fenêtres sont fermées (Windows & Linux)

Sur Windows et Linux, le fait de fermer toutes les fenêtres ferme généralement entièrement l'application. To implement this pattern in your Electron app, listen for the app module's window-all-closed event, and call app.quit() to exit your app if the user is not on macOS.

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})

Ouverture d'une fenêtre si aucune n'est ouverte (macOS)

Par contre, les applications macOS continuent généralement à fonctionner même si aucune fenêtre n'est ouverte. L’activation de l’application lorsqu’aucune fenêtre n’est disponible va en ouvrir une nouvelle.

To implement this feature, listen for the app module's activate event, and call your existing createWindow() method if no BrowserWindows are open.

Étant donné que les fenêtres ne peuvent pas être créées avant l'événement ready , vous ne devrez écouter l'événement activate qu'après l'initialisation de votre application. Pour ce faire, écoutez uniquement les événements d’activation dans la callback de votre whenReady() existant.

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

Code final

const { app, BrowserWindow } = require('electron/main')

const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})

win.loadFile('index.html')
}

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

Facultatif : Débogage avec VS Code

Si vous souhaitez déboguer votre application à l’aide de VS Code, vous devez attacher VS Code aux processus principal et de rendu. Nous allons voir maintenant une configuration prête à être utilisée. Vous devez pour cela créer une configuration launch.json dans le dossier .vscode de votre projet si celui-ci n'existe pas encore :

.vscode/launch.json
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}

Suite à cela la nouvelle option "Main + renderer" apparaîtra lorsque vous sélectionnez "Run and Debug" dans la barre latérale, en l'utilisant vous pourrez entre autres définir des points d'arrêt et inspecter toutes les variables dans les processus principal et de rendu.

Nous avonc dans ce fichier launch.json créé les 3 configurations suivantes:

  • Main qui est utilisée pour démarrer le processus principal et expose également le port 9222 pour le débogage distant (--remote-debugging-port=9222). C'est le port que nous utiliserons pour attacher le débogueur au Renderer. Puisque le processus principal est un processus Node.js, le type est défini à node.
  • Renderer, elle est utilisée pour déboguer le processus de rendu. Le processus principal étant celui qui crée ce processus, nous devons « nous y attacher » ("request": "attach") au lieu d'en créer un nouveau. Le processus de rendu est un processus web, donc le débogueur que nous devons utiliser est chrome.
  • Main + renderer est une tâche composée qui exécute les deux précédentes et ceci simultanément.
attention

Comme nous nous attachons à un processus dans Renderer, il est possible que les premières lignes de votre code soient ignorées si le débogueur n’a pas eu assez de temps pour se connecter avant qu’elles ne soient exécutées. Vous pouvez contourner ce problème en actualisant la page ou en définissant un délai avant l'exécution du code en mode développement.

Lectures complémentaires

Si vous souhaitez approfondir le sujet du débogage, les guides suivants vous fourniront d'avantage d'informations :

Récapitulatif

Les applications Electron sont configurées à l'aide de paquets npm. L'exécutable Electron doit être installé dans les devDependencies de votre projet et peut être exécuté en mode développement en utilisant un script de votre fichier package.json.

L’exécutable exécute le point d’entrée JavaScript indiqué par la propriété main de votre fichier package.json. Ce fichier contrôle le **processus principal ** d'Electron, qui exécute une instance de Node.js et est responsable du cycle de vie de votre application, de l’affichage des interfaces natives, de l’exécution des opérations privilégiées, et de la gestion des processus de rendu.

Les processus de rendu (ou renderer pour faire court) sont responsables de l'affichage de contenu graphique. Vous pouvez charger une page web dans un moteur de rendu en le faisant pointer sur une adresse web ou un fichier HTML local. Les renderers se comportent de manière très similaire aux pages Web normales et ont accès aux mêmes API Web.

Dans la section suivante du tutoriel, nous allons apprendre comment enrichir le processus de rendu avec des API à privilèges et comment communiquer entre les processus.