Créer des applications de bureau avec deno desktop
Deno desktop compile des apps TypeScript en binaires natifs, avec webview ou CEF, prise en charge des frameworks, cross-compilation et limites.
deno desktop compile un projet Deno en une application de bureau autonome : votre code, le runtime Deno et un moteur de rendu réunis dans un seul binaire par plateforme. La commande est arrivée avec Deno 2.9. Ce qui la distingue d’Electron et de Tauri, c’est que le moteur de rendu est un choix effectué au moment du build. Vous optez pour la WebView du système d’exploitation ou pour un Chromium embarqué, et aucun d’Electron, Electrobun, Tauri ou Dioxus ne propose ce basculement.
Quiconque a déjà livré une application Electron connaît la discussion autour de l’installeur de 100 Mo, et quiconque a livré une application Tauri connaît le bug qui ne se reproduit que sur WebKitGTK. Ces deux frameworks se situent aux extrémités opposées d’un même axe, et jusqu’ici, choisir un framework revenait à choisir définitivement un moteur de rendu.
Voici un premier aperçu de cette troisième option, destiné aux lecteurs qui connaissent déjà le compromis Electron/Tauri. Cet article couvre ce que produit la commande, le plus petit programme qui illustre le modèle, ce que coûte chaque backend en mégaoctets, quels projets de framework elle accepte sans modification, comment fonctionne la compilation croisée et ce qui manque encore. Le débat Electron contre Tauri est traité à part dans une comparaison entre Electron et Tauri.
Points clés
deno desktopest arrivé dans la version stable Deno 2.9.0 le 25 juin 2026, et l’article de publication le qualifie encore d’expérimental, certaines fonctionnalités spécifiques aux plateformes n’étant pas encore intégrées.- Le backend
webviewpar défaut effectue le rendu via WebView2 sous Windows, WKWebView sous macOS et WebKitGTK sous Linux ; le backend optionnelcefembarque Chromium pour un rendu identique sur toutes les plateformes. - La page de comparaison de Deno situe une application basée sur WebView à environ 40 Mo et une application basée sur CEF à environ 150 Mo, contre plus de 100 Mo pour Electron et 2 à 10 Mo pour Tauri.
- Un handler
Deno.serve()placé dans un point d’entrée desktop ne prend ni port ni nom d’hôte ; le runtime le lie à l’adresse que la fenêtre charge. --targetet--all-targetspermettent la compilation croisée vers cinq triplets de plateformes depuis n’importe quel hôte, sans chaîne d’outils Rust, à la seule exception du.dmgmacOS, qui reste lié à son hôte.
Qu’est-ce que deno desktop ?
Pointez deno desktop vers un point d’entrée Deno ou vers un projet de framework web, et vous obtenez en retour une application de bureau qui dessine son interface dans une webview et exécute sa logique dans Deno. L’article de publication de la 2.9 la présente comme la fonctionnalité phare et, dans la même section, la marque comme expérimentale, sa surface d’API n’étant pas encore stabilisée. Elle est arrivée dans la version stable 2.9.0, et non dans une canary, comme le consignent les notes de version v2.9.0 sous feat: deno desktop subcommand.
Trois éléments entrent dans le binaire de chaque plateforme : votre code, le runtime Deno et un backend de rendu. La communication entre le côté Deno et la webview passe par des canaux in-process plutôt que par une IPC basée sur des sockets, ce qui diffère du modèle de passage de messages main/renderer d’Electron. Les surfaces natives telles que Deno.BrowserWindow et Deno.Tray sont intégrées au runtime : le contrôle des fenêtres et les icônes de barre d’état système ne requièrent donc aucun paquet tiers.
Le plus petit programme deno desktop
L’application de bureau minimale tient en un seul handler Deno.serve() qui renvoie du HTML, plus une commande.
// main.ts
Deno.serve(() =>
new Response("<!DOCTYPE html><h1>Window one</h1>", {
headers: { "content-type": "text/html" },
})
);
deno desktop main.ts
Notez l’argument absent. Dans un serveur Deno classique, vous passeriez un port ; ici, vous l’omettez, car dans un point d’entrée desktop le runtime transmet au handler l’adresse vers laquelle la fenêtre pointe déjà. L’application compilée ouvre une fenêtre native sur ce serveur local. C’est la seule partie non évidente du modèle de programmation : le serveur HTTP sert de transport pour l’interface, et le runtime relie les deux extrémités pour vous.
Faut-il choisir le backend webview ou cef ?
Le moteur de rendu se décide au moment du build, et c’est la raison pour laquelle deno desktop occupe une position qu’aucun de ses concurrents ne remplit. Electron n’embarque que Chromium et Tauri n’utilise que la WebView du système. deno desktop fait l’un ou l’autre, au choix via --backend ou le champ desktop.backend dans deno.json.
deno desktop main.ts # webview (default)
deno desktop --backend cef main.ts # bundled Chromium
La page consacrée aux backends nomme les moteurs derrière l’option par défaut : WKWebView sous macOS, WebView2 sous Windows, WebKitGTK sous Linux. Elle documente également deux limites de ce backend qui comptent pour quiconque l’évalue : les DevTools sont réservés à CEF, et WebGPU sous Linux exige CEF. Le backend cef place une copie du Chromium Embedded Framework dans le bundle de l’application, que la même page évalue à environ 150 Mo pour le framework seul.
La page de comparaison de Deno donne les tailles d’application résultantes à titre d’approximations :
| Outil | Moteur | Taille de l’application (chiffre Deno) |
|---|---|---|
deno desktop, webview | WebView de l’OS | ~40 Mo |
deno desktop, cef | Chromium embarqué | ~150 Mo |
| Electron | Chromium embarqué | 100 Mo et plus |
| Tauri | WebView de l’OS | 2 à 10 Mo |
La page sur la distribution fournit un autre point de repère : un hello-world sur le backend WebView pèse environ 66 Mo, et --compress ramène ce chiffre à 19 Mo. Considérez toutes ces valeurs comme les chiffres propres à Deno plutôt que comme des mesures de votre application.
La règle en une ligne de l’article de publication consiste à rester sur webview sauf si vous avez besoin d’un moteur identique partout. En y ajoutant les limites documentées, on obtient une décision exploitable : webview par défaut ; passez à cef lorsque votre interface dépend d’un rendu propre à Chromium, lorsque vous ne pouvez pas tester sur les trois moteurs des différents OS, lorsque vous avez besoin des DevTools en développement, ou lorsqu’il vous faut WebGPU sous Linux. Le prix du basculement correspond à l’écart entre les deux lignes du tableau ci-dessus.
Quels frameworks deno desktop détecte-t-il ?
Pointé vers un projet de framework existant, deno desktop . identifie le framework à partir du fichier de configuration ou du package.json, embarque la sortie du build et exécute le serveur de production du framework comme handler Deno.serve(). Pour Next.js, Astro, Fresh et Nuxt, les notes par framework ne montrent rien de plus que la commande de build propre au framework suivie de deno desktop ., sans adaptateur ni configuration supplémentaire. SvelteKit est détecté lui aussi, mais uniquement via la sortie de l’adaptateur Deno Deploy ou de l’adaptateur Node ; React Router nécessite un app/entry.server.tsx compatible Deno.
Lancez d’abord le build du framework. La commande empaquette ce que ce build a produit ; elle ne déclenchera pas next build ou astro build à votre place.
npx next build # produce .next/
deno desktop . # package the built server
deno desktop . --hmr # development: framework dev server with hot reload
Avec --hmr, la fenêtre de l’application pointe directement vers le serveur de développement du framework : le développement ressemble donc beaucoup au travail dans un onglet de navigateur, l’état survit à une modification, le fast refresh fonctionne et les erreurs arrivent via l’overlay habituel.
Comment compiler des applications deno desktop en croisé ?
--target <triple> construit pour une autre plateforme et --all-targets construit pour toutes les plateformes prises en charge, depuis n’importe quel hôte, sans chaîne d’outils Rust. La page sur la distribution liste cinq cibles : aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc, aarch64-unknown-linux-gnu et x86_64-unknown-linux-gnu.
deno desktop --target x86_64-pc-windows-msvc main.ts
deno desktop --all-targets main.ts
Le mécanisme repose sur le téléchargement, non sur la compilation. Pour la cible demandée, la CLI récupère un denort prêt à l’emploi et une archive de backend prête à l’emploi, en vérifiant les deux contre leurs empreintes SHA-256 avant utilisation. C’est pourquoi cela fonctionne là où Tauri et Dioxus échouent. Leurs chaînes d’outils Rust doivent compiler sur la plateforme cible, chaque OS nécessite donc sa propre machine de build. Electron peut effectuer des builds croisés via electron-builder : le contraste porte donc spécifiquement sur les outils basés sur Rust. La seule exception du côté de Deno est le .dmg macOS, qui délègue à hdiutil et doit être produit sur un Mac.
La maturité, honnêtement
Electron fait tourner Slack, Visual Studio Code et Notion ; Tauri 2 a derrière lui des années de versions et des cibles mobiles ; deno desktop est arrivé avec la 2.9.0, et chaque version corrective 2.9 depuis a apporté des correctifs desktop, la 2.9.6 comprise. La documentation est franche sur ce qui manque encore.
Les formats de sortie sont plus avancés que ne le laisse penser la liste des manques de la page de comparaison. La page sur la distribution documente .app et .dmg sous macOS, un répertoire d’application ou un .msi sous Windows, et un répertoire d’application, .AppImage, .deb ou .rpm sous Linux, le choix étant déterminé par l’extension passée à --output. Les installeurs .msi, .deb et .rpm sont arrivés dans la 2.9.0 elle-même, d’après les notes de version.
Les manques confirmés :
- Mise à jour automatique sous Windows. Seuls macOS et Linux mènent réellement la mise à jour à son terme : ils appliquent le correctif préparé et, si la nouvelle version ne démarre pas, reviennent à l’ancienne. Windows télécharge et prépare un correctif mais ne l’applique jamais, si bien que rien ne change au lancement suivant. La page sur la mise à jour automatique indique de considérer la mise à jour automatique sous Windows comme non prise en charge pour l’instant.
- Notarisation. La signature s’exécute automatiquement sur un hôte macOS, mais la section sur la signature de code souligne que vous devez encore notariser à la main,
xcrun notarytool submitconstituant une étape distincte. - Mobile. Aucune cible iOS ou Android, là où Tauri 2 propose les deux.
- Stockage sécurisé, invites de permission à l’exécution, runtime CEF partagé. La page de comparaison présente ces trois éléments comme absents ou inscrits à la feuille de route ; le runtime partagé est l’élément qui réduirait la taille des applications CEF, et il relève de la promesse, pas d’une version publiée.
Qui devrait essayer deno desktop dès maintenant ?
Essayez-le dès maintenant si vous utilisez déjà Deno, si votre équipe écrit du TypeScript et non du Rust, et si l’application est un outil interne ou une enveloppe de bureau autour d’une base de code Next.js, Astro, Fresh ou Nuxt existante, dans un contexte où un build WebView de 40 Mo est acceptable et où un public macOS ou Linux couvre la mise à jour automatique. Attendez si vous livrez à des utilisateurs Windows qui ont besoin de mises à jour en place, si vous avez besoin du mobile depuis la même base de code, ou s’il vous faut un pipeline de distribution appuyé sur des années d’outillage de signature et d’installation. L’étiquette « expérimental » de l’article de publication est exacte : le modèle est solide et les commandes fonctionnent comme documenté, mais la surface d’API peut encore évoluer d’une version corrective à l’autre.
Conclusion
deno desktop constitue une véritable troisième option car il dissocie la décision sur le moteur de rendu de celle sur le framework, et il facture un prix documenté pour chaque terme de ce choix. La façon la moins coûteuse de l’évaluer consiste à lancer deno desktop . dans un projet de framework que vous avez déjà, une fois sur le backend par défaut et une fois avec --backend cef, puis à comparer les deux artefacts au regard des manques listés ci-dessus.
FAQ
Comment la webview appelle-t-elle du code Deno dans une application deno desktop ?
Via les bindings. Côté Deno, vous attachez un handler à une fenêtre avec win.bind(name, handler) ; le JavaScript de la page appelle ensuite bindings.name(args) et récupère une promesse portant ce que le handler a renvoyé. Chaque fenêtre conserve son propre ensemble de bindings, si bien qu'un handler enregistré sur une Deno.BrowserWindow est invisible pour une autre. L'appel transite par des canaux in-process plutôt que par une IPC sur socket, et lorsqu'un handler lève une exception, ce qui parvient à la webview est un simple objet portant name, message et stack, et non une véritable Error.
Qu'est-ce que le backend raw dans deno desktop et quand faut-il l'utiliser ?
Il exécute une application de bureau sans aucun moteur web. Vous conservez les fenêtres, les événements d'entrée et la surface d'API native, mais il n'y a nulle part où rendre du HTML : pas de webview, pas de liaison automatique de Deno.serve() et pas de proxy de bindings. Il convient aux applications qui dessinent elles-mêmes leur interface avec WebGPU, Skia ou du code de dessin personnalisé. Le seul moyen de le sélectionner est le champ desktop.backend dans deno.json, puisque le drapeau --backend n'accepte que cef et webview.
Puis-je faire passer une application deno desktop du backend webview au backend cef sans modifier le code ?
Oui. La page de Deno consacrée aux backends traite CEF et WebView comme interchangeables : fenêtres, bindings, événements, navigation et exécution de JS se comportent de la même façon sur l'un comme sur l'autre, et seul le backend raw rompt cette portabilité. Construire pour un backend ou une cible que vous n'avez pas encore utilisés déclenche d'abord le téléchargement d'une archive prête à l'emploi, de quelques centaines de mégaoctets dans le cas de CEF, vérifiée par somme de contrôle et conservée dans le répertoire de cache de Deno, si bien que les builds suivants évitent le téléchargement.
Les permissions Deno s'appliquent-elles à l'intérieur d'une application deno desktop ?
Oui, mais elles proviennent des permissions compilées dans le binaire plutôt que d'invites. Un binding s'exécute au sein du runtime Deno avec ce qui a été accordé au processus : un handler qui lit un fichier a donc besoin d'un accès en lecture accordé au démarrage, et rien de ce que fait la webview ne peut élargir ce périmètre. La documentation est claire : aucune invite de permission distincte n'est déclenchée à l'exécution. Traitez donc comme une entrée non fiable tout ce qu'un binding accepte de la page, et validez-le.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k