Introduction à Electron.js

Electron permet de créer des applications de bureau multiplateformes avec JavaScript, HTML et CSS.

Configuration

# Créer un projet
mkdir mon-app
cd mon-app
npm init -y

# Installer Electron
npm install electron --save-dev

# Structure du projet
mon-app/
├── src/
│   ├── main.js
│   ├── preload.js
│   └── renderer/
│       ├── index.html
│       ├── styles.css
│       └── app.js
├── package.json
└── forge.config.js

# package.json
{
  "name": "mon-app",
  "version": "1.0.0",
  "main": "src/main.js",
  "scripts": {
    "start": "electron .",
    "build": "electron-forge make"
  }
}

Application de base

// src/main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js')
    }
  });

  win.loadFile('src/renderer/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();
  }
});

Communication IPC

Preload Script

// src/preload.js
const { contextBridge, ipcRenderer } =
  require('electron');

contextBridge.exposeInMainWorld('api', {
  // Envoyer au processus principal
  send: (channel, data) => {
    ipcRenderer.send(channel, data);
  },
  // Recevoir du processus principal
  receive: (channel, func) => {
    ipcRenderer.on(channel, (event, ...args) =>
      func(...args));
  },
  // Appel avec réponse
  invoke: (channel, data) => {
    return ipcRenderer.invoke(channel, data);
  }
});

Processus principal

// src/main.js
const { ipcMain } = require('electron');

// Écouter les événements
ipcMain.on('save-file', async (event, data) => {
  // Sauvegarder le fichier
  await saveFile(data);
  event.reply('file-saved', { success: true });
});

// Gérer les appels invoke
ipcMain.handle('get-data', async (event, id) => {
  const data = await fetchData(id);
  return data;
});

// src/renderer/app.js
// Utilisation dans le renderer
window.api.send('save-file', { content: 'test' });

window.api.receive('file-saved', (result) => {
  console.log('Fichier sauvegardé:', result);
});

const data = await window.api.invoke('get-data', 123);

Fonctionnalités natives

// Menus
const { Menu } = require('electron');

const template = [
  {
    label: 'Fichier',
    submenu: [
      {
        label: 'Nouveau',
        accelerator: 'CmdOrCtrl+N',
        click: () => createNew()
      },
      { type: 'separator' },
      {
        label: 'Quitter',
        accelerator: 'CmdOrCtrl+Q',
        click: () => app.quit()
      }
    ]
  }
];

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

// Notifications
const { Notification } = require('electron');

new Notification({
  title: 'Notification',
  body: 'Message'
}).show();

// Dialogues de fichiers
const { dialog } = require('electron');

const result = await dialog.showOpenDialog({
  properties: ['openFile', 'multiSelections']
});

Packaging & Distribution

# Installation de Electron Forge
npm install --save-dev @electron-forge/cli

# Initialiser Forge
npx electron-forge import

# Configuration
// forge.config.js
module.exports = {
  packagerConfig: {
    icon: './assets/icon'
  },
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {
        name: 'MonApp'
      }
    },
    {
      name: '@electron-forge/maker-zip',
      platforms: ['darwin']
    },
    {
      name: '@electron-forge/maker-deb',
      config: {}
    }
  ],
  publishers: [
    {
      name: '@electron-forge/publisher-github',
      config: {
        repository: {
          owner: 'username',
          name: 'mon-app'
        }
      }
    }
  ]
};

# Build et publication
npm run make
npm run publish