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 Tauri : Premiers Pas et Interface Utilisateur

Contexte du cours : Maîtriser les Applications Desktop Multiplateformes avec Electron et Tauri.


Introduction à Tauri

Bienvenue dans cette leçon dédiée à Tauri, un framework innovant pour la création d'applications desktop multiplateformes. Après avoir exploré Electron, qui s'appuie sur Chromium, nous allons maintenant plonger dans un concurrent de taille qui mise sur la performance, la légèreté et la sécurité : Tauri.

Tauri permet de construire des applications de bureau en utilisant des technologies web (HTML, CSS, JavaScript) pour l'interface utilisateur, tout en intégrant un backend écrit en Rust. Contrairement à Electron qui embarque une instance complète de Chromium (ce qui le rend lourd), Tauri utilise les webviews natives du système d'exploitation. Cela se traduit par :

  • Taille de bundle réduite : Les applications Tauri sont significativement plus petites que leurs équivalents Electron, car elles n'embarquent pas un navigateur complet.
  • Performance améliorée : Utilisation des capacités natives du système pour le rendu de l'interface et l'exécution du backend Rust, offrant une meilleure réactivité et une consommation de ressources moindre.
  • Sécurité renforcée : Le backend en Rust, combiné à un modèle de sécurité granulaire, offre un contrôle plus fin sur l'accès aux ressources du système.

Dans cette leçon, nous allons apprendre les bases du développement avec Tauri : comment initialiser un projet, comprendre son architecture, construire une interface utilisateur simple avec les technologies web de votre choix, et établir une communication entre le frontend et le puissant backend Rust.

Prérequis

Avant de démarrer, assurez-vous d'avoir les éléments suivants installés sur votre machine :

  • Node.js et npm/yarn/pnpm : Pour la gestion des dépendances frontend et l'exécution des scripts de build.
  • Rust : Tauri s'appuie sur Rust pour son backend. L'installation via rustup est recommandée.
    • Téléchargez et installez rustup depuis rustup.rs.
  • Dépendances spécifiques au système d'exploitation :
    • Windows : Outils de build C++ pour Visual Studio (via le Visual Studio Installer).
    • macOS : Command Line Tools pour Xcode (xcode-select --install).
    • Linux : webkit2gtk-4.0 ou webkit2gtk-4.1 (selon votre distribution), ainsi que d'autres dépendances de build (libappindicator-dev, libudev-dev, etc.). La documentation de Tauri fournit une liste complète.

Premiers Pas avec Tauri

1. Initialisation d'un Projet Tauri

Tauri fournit un outil de scaffolding très pratique, create-tauri-app, pour démarrer rapidement un nouveau projet.

Ouvrez votre terminal et exécutez la commande suivante :

npm create tauri-app@latest
# ou
yarn create tauri-app
# ou
pnpm create tauri-app

L'outil vous posera quelques questions :

  1. project-name : Le nom de votre projet (ex: ma-premiere-app-tauri).
  2. Choose your UI template : Le framework frontend que vous souhaitez utiliser (Vanilla JavaScript, Vue, React, Svelte, Angular, Solid, Qwik). Tauri est agnostique au framework frontend, choisissez celui avec lequel vous êtes le plus à l'aise.
  3. Choose your UI template variant : Pour certains frameworks, vous pourrez choisir TypeScript ou JavaScript pur.
  4. Choose your package manager : npm, yarn, ou pnpm.

Exemple d'initialisation (avec React et TypeScript) :

npm create tauri-app@latest

# ? project-name » ma-premiere-app-tauri
# ? Choose your UI template » react
# ? Choose your UI template variant » typescript
# ? Choose your package manager » npm

# cd ma-premiere-app-tauri
# npm install

Une fois le processus terminé, naviguez dans le répertoire de votre nouveau projet et installez les dépendances npm/yarn/pnpm.

2. Lancement de l'Application en Mode Développement

Pour lancer votre application en mode développement (avec rechargement à chaud), utilisez la commande suivante :

npm run tauri dev
# ou
yarn tauri dev
# ou
pnpm tauri dev

Ceci compilera le backend Rust et ouvrira une fenêtre d'application affichant votre interface utilisateur.

3. Structure d'un Projet Tauri

Un projet Tauri typique, initialisé avec create-tauri-app, présente la structure suivante :

ma-premiere-app-tauri/
├── src/                # Le code source de votre interface utilisateur (frontend web)
│   ├── index.html
│   ├── main.tsx        # ou main.js, main.vue, etc.
│   └── ...             # Vos composants, styles, etc.
├── src-tauri/          # Le code source du backend Rust
│   ├── Cargo.toml      # Manifeste du projet Rust (dépendances, métadonnées)
│   ├── src/
│   │   └── main.rs     # Point d'entrée du backend Rust
│   └── tauri.conf.json # Fichier de configuration principal de Tauri
├── package.json        # Dépendances et scripts npm
└── ...                 # Autres fichiers de configuration (tsconfig.json, vite.config.ts, etc.)
  • src/ : Ce dossier contient tout le code de votre application web (frontend). Tauri se contente de charger ce contenu dans une webview. Vous développez ici comme pour n'importe quelle application web.
  • src-tauri/ : Ce dossier est le cœur de l'application desktop. Il contient le code Rust qui interagit avec le système d'exploitation et fournit des fonctionnalités au frontend via une API sécurisée.
  • src-tauri/tauri.conf.json : Ce fichier JSON est crucial. Il configure la manière dont Tauri construit, exécute et interagit avec votre application. Nous y reviendrons plus tard.

L'Architecture de Tauri

Comprendre l'architecture de Tauri est essentiel pour exploiter pleinement son potentiel.

Tauri repose sur une architecture client-serveur simplifiée, où :

  1. Le Frontend (la Webview) :

    • C'est votre application web standard (HTML, CSS, JavaScript) qui fournit l'interface utilisateur.
    • Tauri ne distribue pas Chromium. À la place, il utilise les webviews natives du système d'exploitation :
      • Windows : WebView2 (basé sur Edge Chromium)
      • macOS : WKWebView (basé sur Safari WebKit)
      • Linux : WebKitGTK
    • Cela signifie que l'application est plus légère et intègre mieux les spécificités du système d'exploitation en termes de rendu et de performances.
  2. Le Backend (Rust) :

    • C'est un programme Rust qui s'exécute en arrière-plan et fournit les fonctionnalités "desktop" à votre application.
    • Il gère l'accès au système de fichiers, les requêtes réseau sécurisées, la gestion des fenêtres, l'affichage de dialogues natifs, et toute autre logique métier nécessitant des performances ou un accès bas niveau au système.
    • Rust est choisi pour sa sécurité mémoire, ses performances et sa concurrence sans risque, ce qui en fait un choix idéal pour un backend d'application desktop.
  3. La Communication (IPC - Inter-Process Communication) :

    • Le frontend (JavaScript) et le backend (Rust) communiquent via un mécanisme sécurisé appelé IPC (Inter-Process Communication).
    • Le JavaScript du frontend peut invoquer des commandes définies dans le backend Rust.
    • Le backend Rust peut émettre des événements que le frontend JavaScript peut écouter.
    • Cette séparation claire des responsabilités et le canal de communication contrôlé améliorent la sécurité et la maintenabilité de l'application.

L'Interface Utilisateur (Frontend)

Comme mentionné, l'interface utilisateur de votre application Tauri est une application web standard. Vous pouvez utiliser n'importe quel framework ou bibliothèque JavaScript avec lequel vous êtes à l'aise.

  • HTML : Le fichier index.html (ou l'équivalent dans votre setup de build) est le point d'entrée de votre application web.
  • CSS : Tous les outils CSS modernes (Sass, Less, PostCSS, Tailwind CSS, styled-components, etc.) peuvent être utilisés.
  • JavaScript/TypeScript : Vous pouvez écrire votre logique frontend avec la syntaxe de votre choix.

Exemple de index.html (simplifié) :

<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Ma Première App Tauri</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Votre travail de développeur frontend se concentre dans le dossier src/. Les bundlers comme Vite (souvent inclus par défaut dans les templates Tauri) gèrent la compilation et le rechargement à chaud pour une expérience de développement fluide.

Interagir avec le Backend Rust : L'API Tauri

Le véritable pouvoir de Tauri réside dans la capacité de votre frontend web à interagir avec le backend Rust pour accéder aux fonctionnalités du système. Ceci est rendu possible grâce à l'API Tauri, principalement via le concept de commandes.

1. Définir une Commande Rust

Une commande Rust est une fonction Rust annotée avec #[tauri::command]. Cette annotation rend la fonction accessible depuis le frontend JavaScript.

Ouvrez le fichier src-tauri/src/main.rs. C'est le point d'entrée de votre application Rust.

Exemple : Créons une commande simple qui salue un utilisateur.

// src-tauri/src/main.rs

// Importez l'attribut `tauri::command`
use tauri::Manager; // Utile pour accéder à l'application et ses fenêtres

// 1. Définir une commande Rust
// L'annotation `#[tauri::command]` rend cette fonction invocable depuis le frontend.
#[tauri::command]
fn greet(name: &str) -> String {
    // La fonction prend un argument `name` de type chaîne de caractères
    // et retourne une nouvelle chaîne de caractères.
    format!("Bonjour, {} ! Vous avez été salué depuis Rust !", name)
}

fn main() {
    tauri::Builder::default()
        // 2. Enregistrer la commande pour qu'elle soit accessible au frontend
        // `generate_handler!` est une macro qui génère le code nécessaire pour gérer les appels de commandes.
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("erreur lors de l'exécution de l'application tauri");
}

Explication du code Rust :

  • #[tauri::command] : Cette macro est essentielle. Elle transforme la fonction greet en une commande qui peut être appelée depuis le JavaScript.
  • fn greet(name: &str) -> String : Définit une fonction greet qui prend un argument name de type &str (référence de chaîne de caractères) et retourne une String. Tauri gère automatiquement la sérialisation/désérialisation des données entre JavaScript (JSON) et Rust.
  • .invoke_handler(tauri::generate_handler![greet]) : Dans la fonction main, cette ligne enregistre la commande greet auprès du système Tauri, la rendant ainsi disponible pour les appels du frontend. Vous pouvez enregistrer plusieurs commandes en les listant : tauri::generate_handler![greet, autre_commande, etc.].

2. Invoquer une Commande depuis le Frontend JavaScript

Pour appeler une commande Rust depuis le frontend, vous utilisez la fonction invoke de l'API Tauri.

Ouvrez un fichier JavaScript/TypeScript dans votre dossier src/ (par exemple, src/main.tsx ou un fichier de composant).

Exemple : Frontend HTML/JavaScript simple pour appeler la commande greet.

<!-- src/index.html (ou dans votre composant React/Vue) -->
<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tauri Greeter</title>
    <style>
      body {
        font-family: sans-serif;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100vh;
        margin: 0;
        background-color: #f0f0f0;
      }
      .container {
        padding: 20px;
        background-color: white;
        border-radius: 8px;
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        text-align: center;
      }
      input {
        padding: 8px;
        margin-bottom: 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        width: 200px;
      }
      button {
        padding: 10px 15px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        font-size: 16px;
      }
      button:hover {
        background-color: #0056b3;
      }
      #greeting-message {
        margin-top: 20px;
        font-weight: bold;
        color: #333;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>Salutations Tauri</h1>
      <input id="name-input" type="text" placeholder="Entrez votre nom" />
      <button onclick="greetUser()">Saluer !</button>
      <p id="greeting-message"></p>
    </div>

    <script type="module">
      // Importez la fonction `invoke` de l'API Tauri
      import { invoke } from '@tauri-apps/api/tauri';

      // Définissez la fonction `greetUser` dans la portée globale pour qu'elle soit accessible depuis onclick
      window.greetUser = async () => {
        // 1. Récupérer la valeur de l'input
        const nameInput = document.getElementById('name-input');
        const name = nameInput.value;

        // 2. Appeler la commande Rust 'greet' avec l'argument 'name'
        // La fonction `invoke` retourne une Promise qui se résout avec le résultat de la commande Rust.
        try {
          const greeting = await invoke('greet', { name });

          // 3. Afficher le résultat
          document.getElementById('greeting-message').textContent = greeting;
        } catch (error) {
          console.error('Erreur lors de l\'invocation de la commande:', error);
          document.getElementById('greeting-message').textContent = 'Une erreur est survenue.';
        }
      };
    </script>
  </body>
</html>

Explication du code JavaScript/HTML :

  • import { invoke } from '@tauri-apps/api/tauri'; : Cette ligne importe la fonction invoke de la bibliothèque JavaScript @tauri-apps/api/tauri. Cette bibliothèque fournit toutes les interfaces pour interagir avec le backend Tauri.
  • await invoke('greet', { name }); : C'est l'appel clé.
    • Le premier argument est le nom de la commande Rust que vous souhaitez appeler ('greet').
    • Le second argument est un objet contenant les arguments à passer à la commande Rust. Les clés de cet objet doivent correspondre aux noms des arguments de la fonction Rust (ici, name).
    • Puisque l'invocation d'une commande est une opération asynchrone, invoke retourne une Promise. Nous utilisons await pour attendre le résultat.
  • La valeur retournée par la fonction Rust (String dans notre cas) est automatiquement désérialisée et disponible dans la variable greeting.

Redémarrez votre application Tauri (npm run tauri dev) pour voir ces changements en action. Entrez un nom, cliquez sur "Saluer !", et observez la réponse venir du backend Rust !

Accéder aux Fonctionnalités du Système

L'API @tauri-apps/api contient de nombreux modules pour interagir avec les fonctionnalités du système :

  • @tauri-apps/api/fs : Pour le système de fichiers (lecture/écriture).
  • @tauri-apps/api/dialog : Pour afficher des boîtes de dialogue natives (ouvrir/enregistrer un fichier, alertes).
  • @tauri-apps/api/window : Pour contrôler la fenêtre de l'application (taille, position, titre).
  • @tauri-apps/api/shell : Pour exécuter des commandes shell ou ouvrir des URL.
  • Et bien plus encore !

Chaque interaction est encapsulée dans une commande Rust sous-jacente qui a été sécurisée par Tauri.

Configuration de l'Application (tauri.conf.json)

Le fichier src-tauri/tauri.conf.json est le cœur de la configuration de votre application Tauri. Il contient des informations sur la construction, le bundle et le comportement de votre application.

Voici les sections les plus importantes pour les premiers pas :

// src-tauri/tauri.conf.json
{
  "$schema": "../node_modules/@tauri-apps/cli/schemas/config.json",
  "build": {
    "beforeBuildCommand": "npm run build", // Commande à exécuter avant le build Rust (ex: build frontend)
    "beforeDevCommand": "npm run dev",     // Commande à exécuter avant le dev Rust (ex: dev frontend)
    "devPath": "../src",                  // Chemin vers le dossier de dev frontend (pour le rechargement à chaud)
    "distDir": "../src"                   // Chemin vers le dossier de build frontend (pour le bundle final)
  },
  "package": {
    "productName": "Ma Premiere App",  // Nom du produit (utilisé pour les installeurs)
    "version": "0.1.0"                 // Version de l'application
  },
  "tauri": {
    "bundle": {
      "active": true,
      "targets": "all",               // Cible les plateformes (macOS, Windows, Linux)
      "identifier": "com.monentreprise.mapp", // Identifiant unique de l'application (format DNS inversé)
      "icon": [                         // Icônes de l'application pour différentes tailles
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/128x128@2x.png",
        "icons/icon.icns",
        "icons/icon.ico"
      ]
    },
    "security": {
      "csp": null                       // Politique de sécurité du contenu (Content Security Policy)
    },
    "allowlist": {                      // Liste blanche des API Tauri accessibles au frontend
      "all": true                       // Permet l'accès à toutes les API (pour commencer, mais à restreindre !)
      // "fs": { "all": true },           // Exemple: autoriser toutes les opérations du système de fichiers
      // "shell": { "all": true }
    },
    "windows": [                        // Configuration des fenêtres de l'application
      {
        "title": "Ma Première App Tauri", // Titre de la fenêtre
        "width": 800,                    // Largeur initiale
        "height": 600,                   // Hauteur initiale
        "resizable": true,               // La fenêtre peut-elle être redimensionnée ?
        "fullscreen": false              // La fenêtre démarre-t-elle en plein écran ?
      }
    ]
  }
}

Points clés de la configuration :

  • build : Définit comment Tauri doit construire et exécuter le frontend.
    • beforeDevCommand et beforeBuildCommand sont très utiles pour déclencher les scripts de build de votre framework frontend (npm run dev ou npm run build).
    • devPath et distDir pointent vers les dossiers où votre frontend est servi en développement et où le build final est généré.
  • package : Informations générales sur votre application.
  • tauri.bundle : Configure la manière dont votre application est packagée pour la distribution (installateurs). identifier est très important et doit être unique.
  • tauri.security.csp : La Content Security Policy (CSP) est une couche de sécurité cruciale pour les applications web. Il est fortement recommandé de la définir pour restreindre les ressources que votre webview peut charger. Pour des raisons de simplicité, null désactive le CSP par défaut, mais ce n'est pas une bonne pratique pour la production.
  • tauri.allowlist : C'est un aspect de sécurité fondamental de Tauri. Vous devez explicitement autoriser les API du système que votre frontend peut utiliser. all: true est pratique pour le développement, mais pour une application en production, vous devriez spécifier uniquement les APIs dont vous avez besoin (ex: "fs": { "read": true, "write": true }).
  • tauri.windows : Permet de configurer les propriétés de chaque fenêtre de votre application (titre, taille, redimensionnement, etc.). Vous pouvez définir plusieurs fenêtres ici.

Conclusion et Prochaines Étapes

Félicitations ! Vous avez fait vos premiers pas dans le monde de Tauri. Vous avez appris à :

  • Initialiser un projet Tauri et comprendre sa structure de base.
  • Saisir l'architecture de Tauri, basée sur les webviews natives et Rust, et ses avantages par rapport à Electron.
  • Comprendre que l'interface utilisateur est une application web standard, vous donnant la liberté d'utiliser vos outils frontend préférés.
  • Établir une communication bidirectionnelle sécurisée entre le frontend JavaScript et le backend Rust via les commandes (invoke).
  • Naviguer et comprendre les options de configuration clés dans tauri.conf.json.

Tauri offre une alternative robuste, performante et sécurisée pour le développement d'applications desktop. Sa flexibilité en termes de choix de framework frontend et sa puissance côté backend avec Rust en font un outil de choix pour de nombreux scénarios.

Pour aller plus loin :

  • Gestion de l'État : Explorez comment gérer l'état de votre application, soit entièrement côté frontend (Redux, Vuex, Zustand), soit en utilisant le backend Rust pour un état persistant ou partagé entre plusieurs fenêtres.
  • Plus d'API Tauri : Familiarisez-vous avec d'autres modules de l'API Tauri (système de fichiers, dialogues, notifications, etc.) pour étendre les fonctionnalités de votre application.
  • Gestion des Événements : Découvrez comment le backend Rust peut émettre des événements que le frontend peut écouter, utile pour les mises à jour en temps réel.
  • Bundling et Distribution : Apprenez à créer des exécutables et des installeurs pour Windows, macOS et Linux avec Tauri.
  • Plugins : Explorez la création ou l'utilisation de plugins Tauri pour des fonctionnalités spécifiques ou l'intégration avec des bibliothèques Rust tierces.

Le développement avec Tauri est une compétence précieuse qui allie la rapidité du développement web à la puissance et la performance des applications natives. Continuez à explorer !