Créer votre première application
Ceci est la partie 2 du tutoriel Electron.
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
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.
- npm
- Yarn
mkdir my-electron-app && cd my-electron-app
npm init
mkdir my-electron-app && cd my-electron-app
yarn 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, et description peuvent prendre n'importe quelle valeur, mais seront nécessaires plus tard pour l' empaquetage.
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.
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
- Yarn
npm install electron --save-dev
yarn add electron --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.
{
"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"
}
}
Si l’installation d’Electron échoue directement, reportez-vous à notre documentation sur l'Installation avancée pour en savoir un peu plus sur les miroirs de téléchargement, proxy et étapes de dépannage.
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
La lecture de la documentation du modèle de processus d'Electron vous permettra de mieux comprendre comment les processus multiples d'Electron fonctionnent ensemble.
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 :
console.log('Hello from Electron 👋')
Étant donné que le processus principal d’Electron est un exécutable Node.js, vous pouvez exécuter tout code Node.js avec la commande electron
(vous pouvez même l’utiliser comme 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.
{
"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
- Yarn
npm run start
yarn 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 :
<!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>
Maintenant que vous avez une page web, vous pouvez la charger dans une BrowserWindow d'Electron. Remplacez le contenu de votre fichier main.js
par le code suivant. Nous expliquerons séparement chaque bloc de code.
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
const { app, BrowserWindow } = require('electron')
Dans cette première ligne, nous importons deux modules Electron avec la syntaxe des module CommonJS :
- app, qui contrôle le cycle de vie des événements de votre application.
- BrowserWindow, qui crée et gère les fenêtres d’application.
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')
Pour plus d'informations, voir la doc Process Model.
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 :
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
Appel de votre fonction lorsque l’application est prête
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.
Dans Electron, une BrowserWindows ne peut être créé qu’après l’émission de l'événement ready
de l’application. Vous pouvez attendre cet événement en utilisant l'API app.whenReady()
et en appelant createWindow()
une fois sa promesse résolue.
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.
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. Pour implémenter ce modèle dans votre application Electron et si l’utilisateur n’est pas sur macOS, écoutez les modules window-all-closed
de l’application et appelez app.quit()
pour quitter votre application.
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.
Pour implémenter cette fonctionnalité, écoutez l'événement activate
du module app et appelez votre méthode createWindow()
existante si aucune BrowserWindows n'est ouverte.
É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
- main.js
- index.html
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()
}
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<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>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>
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 :
{
"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 auRenderer
. 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 estchrome
.Main + renderer
est une tâche composée qui exécute les deux précédentes et ceci simultanément.
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.
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.