Deno accueille `deno desktop` : sous-commande pour applications de bureau auto-contenues, basée sur WEF, avec Deno.BrowserWindow, DevTools unifiés et compilation croisée macOS, Windows et Linux

Deno accueille `deno desktop` : sous-commande pour applications de bureau auto-contenues, basée sur WEF, avec Deno.BrowserWindow, DevTools unifiés et compilation croisée macOS, Windows et Linux

lschvn

Deno a fusionné deno desktop le 16 juin 2026 (PR #33441, ouvert à l'origine en avril 2026 comme ticket #3234), ajoutant une nouvelle sous-commande qui compile un projet Deno en application de bureau auto-contenue. Le même matin ont aussi atterri trois PR plus petites : deno link / deno unlink pour le tableau links dans deno.json, deno test --shard pour découper une exécution de tests entre machines, et un fetch request_builder_hook pour les déploiements cloud. Le gros morceau est la sous-commande desktop : elle donne à Deno un chemin de première classe pour livrer des applications de bureau multiplateformes avec une seule invocation deno desktop <entry>, et c'est le plus gros ajout à la CLI Deno depuis que Deno 2.7 a stabilisé l'API Temporal et les builds Windows-on-Arm.

Ce que deno desktop fait réellement

deno desktop <entry> compile un projet Deno en application de bureau auto-contenue, construite sur WEF (WebView Engine Foundation). La CLI télécharge les backends WEF précompilés depuis github.com/denoland/wef/releases, épingle la version via le Cargo.lock du projet, les vérifie en SHA-256, et les met en cache sous <deno_dir>/wef/<version>/. Pour le développement contre un checkout WEF local, WEF_DEV_DIR pointe la CLI vers un répertoire local au lieu de télécharger.

Il existe trois backends, sélectionnables par projet :

  • cef, le défaut, un Chromium embarqué (CEF est la même famille de moteurs que celle sur laquelle le renderer d'Electron est construit).
  • webview, le webview de l'OS hôte (Edge WebView2 sur Windows, WKWebView sur macOS, WebKitGTK sur Linux).
  • raw, une fenêtre winit sans moteur embarqué, pour les projets qui veulent dessiner dans la fenêtre eux-mêmes.

Deno.serve() dans l'entry s'auto-lie au port vers lequel le webview navigue, via une nouvelle variable d'environnement DENO_SERVE_ADDRESS que le runtime desktop injecte. Un projet framework peut garder sa config port normale et laisser le runtime desktop faire le binding.

Détection automatique des frameworks et HMR

La CLI détecte automatiquement les projets framework dans cli/tools/framework.rs, avec un support de première classe pour Next.js, Astro, Fresh, Remix, Nuxt, SvelteKit, SolidStart, TanStack Start et Vite SSR. Un projet framework détecté obtient le serveur de production du framework par défaut ; sous --hmr, c'est le serveur de dev du framework qui s'exécute (serveur de dev Next pour Next, serveur de dev Nuxt pour Nuxt, serveur de dev Vite pour Vite SSR, etc.).

Les projets non-framework ont quand même du hot-reload sous --hmr, mais via un mécanisme différent. La CLI utilise un file-watcher plus un hot-swap CDP Debugger.setScriptSource pour pousser les modifications dans l'isolat V8 en cours d'exécution pendant que le runtime Deno et le processus CEF restent en vie. L'effet pratique est le même : on édite un fichier, on voit le changement, la fenêtre ne se recharge pas. L'asymétrie est que les projets framework obtiennent le pipeline HMR du framework, qui est généralement plus granulaire (mises à jour scope composant, frontières fast-refresh, préservation d'état au niveau framework), tandis que les projets non-framework obtiennent un hot-swap au niveau script V8. Le compromis est documenté dans la PR : les jeux d'icônes ne sont pas encore supportés en mode --hmr, seul un chemin d'icône unique fonctionne dans ce mode.

Deno.BrowserWindow et la surface API native

La nouvelle API Deno.BrowserWindow (déclarée dans cli/tsc/dts/lib.deno.desktop.d.ts) est ce que le code utilisateur appelle pour piloter une fenêtre. La surface couvre le cycle de vie de la fenêtre (show / hide / focus / close / reload), la taille et la position, alwaysOnTop, la navigation, les menus d'app et contextuels, les handles de fenêtre natifs, et les événements clavier, souris, molette, resize et focus. Deux modules natifs-only s'insèrent à côté : Deno.dock (macOS-only) pour l'intégration du dock, et Deno.Tray (multiplateforme) pour les icônes de status-area avec tooltips, variantes dark-mode, et menus contextuels.

Un canal RPC bind / unbind expose le JS du webview côté Deno en tant que bindings.<name>(), et la direction inverse est executeJs depuis Deno vers le webview. L'intégration runtime est la partie qui a le plus de levier sur le code JS existant : prompt(), alert(), et confirm() dans le webview deviennent des popups natifs, et les erreurs non catchées affichent une alerte native avec un POST optionnel vers desktop.errorReporting.url pour le crash reporting. L'auto-updater expose Deno.desktopVersion et un Deno.autoUpdate({ url, interval, onUpdateReady, onRollback }) qui poll <url>/latest.json, applique des patches bsdiff au dylib (via qbsdiff), stage le résultat pour le prochain lancement, et fait un rollback en cas d'échec de lancement.

Une session DevTools, deux isolats V8

Les flags --inspect, --inspect-brk et --inspect-wait passent par un nouveau multiplexeur CDP dans cli/tools/desktop_devtools.rs qui expose le V8 du runtime Deno et le V8 du renderer CEF comme deux cibles attachées dans une seule session DevTools. L'effet côté utilisateur est un menu déroulant Console unique (Renderer / Deno) et un panneau Sources unique avec les deux threads. Le multiplexeur parle Chrome DevTools Protocol au client inspector et le multiplexe sur deux backends, une connexion CDP au V8 du runtime et une au V8 du renderer.

--inspect-brk met en pause les deux isolats au démarrage (Deno via son propre mécanisme, CEF via un Debugger.enable + Debugger.pause injecté avant la navigation). Pour la plupart des sessions de debug desktop, c'est le workflow : on pause les deux, on met un breakpoint dans le renderer, on met un breakpoint dans le runtime, on unpause, on conduit l'app, et on step entre threads dans le même panneau Sources. La cible CEF est la même cible DevTools qu'utilise Chromium, avec les mêmes panneaux Performance, Memory et Network ; la cible Deno est la cible V8 Deno standard avec l'introspection deno_core.

Compilation croisée et distribution

Les flags --target et --all-targets téléchargent les binaires denort précompilés et les backends WEF pour le triple cible. Les sorties sont :

  • macOS : un bundle .app (framework sous Contents/Frameworks/), avec .dmg produit via hdiutil.
  • Windows : un .exe plus un répertoire de DLLs.
  • Linux : un répertoire applicatif et un .AppImage produit via appimagetool.

La signature de code est implémentée sur macOS via la clé macos.codesignIdentity dans deno.json (avec un fallback ad-hoc pour les builds non signés), mais la notarisation et le stapling via notarytool ne sont pas encore câblés. Les installeurs Windows MSI, Linux .deb / .rpm, le clipboard, et secureStorage sont tous encore en TODO dans la description de la PR.

Limites OS-spécifiques à connaître en amont

La description de la PR est inhabituellement explicite sur les manques. Six limitations sont signalées comme « se dégradant gracieusement » mais à connaître :

  • L'auto-update est unix-only. apply_pending_update, get_dylib_path, et AutoUpdateState sont #[cfg(unix)], donc sur Windows le chemin staged-update, bsdiff et rollback est un no-op.
  • Le support des addons natifs NAPI est unix-only. promote_dylib_symbols_to_global (le re-dlopen avec RTLD_GLOBAL qui rend les symboles NAPI visibles aux addons comme next-swc) est #[cfg(unix)] ; sur Windows, les frameworks qui chargent des addons natifs peuvent échouer à les charger.
  • Les permissions de notification sont macOS-spécifiques. Le backend LAUFEY est lancé via disclaim_spawn (posix_spawn avec responsabilité TCC disclaimée) pour qu'il devienne son propre principal de permission ; sans cela, UNUserNotificationCenter.requestAuthorization échoue.
  • Linux est X11-only. Le lanceur généré force --ozone-platform=x11 et GDK_BACKEND=x11 parce que le moniteur d'événements LAUFEY (mouse, focus, resize) utilise XI2 sur X11. Sur les sessions Wayland, ça passe par XWayland ; le Wayland natif n'est pas supporté.
  • Deno.dock est macOS-only.
  • Les jeux d'icônes ne sont pas supportés en mode --hmr (toute plateforme).

La motivation pour livrer avec ces manques est la même que pour chaque release « on livre la première coupe, on consigne les limites » : la sous-commande desktop est la première fois que Deno livre un runtime non-serveur, et obtenir l'intégration WEF, l'API Deno.BrowserWindow, l'auto-détection de frameworks, les DevTools unifiés, l'auto-updater, et la compilation croisée qui fonctionnent sur au moins une plateforme (macOS) est le prérequis pour tout le reste. Les manques cross-plateforme sont réels, mais ce sont des manques de la première coupe, pas des manques d'architecture.

Les trois autres PR du même matin

La même branche main de Deno a vu trois autres fonctionnalités atterrir entre 06h59 et 07h15 UTC, avant deno desktop à 10h41 UTC. Elles sont plus petites en scope mais elles sont toutes vérifiées à la source primaire sur la même release et elles complètent l'histoire « Deno ajoute pas mal de plomberie » du matin.

deno link et deno unlink donnent un accès CLI de première classe au tableau links dans deno.json, qui était la façon user-facing d'utiliser un paquet JSR local à la place d'une version du registre, mais qui jusqu'ici n'avait pas de CLI pour la manipuler. deno link <path> valide le path, ajoute le path relatif à links (en créant le tableau s'il manque, en préservant le formatage via la machinerie CST existante), et lance install. deno unlink <path-or-name> retire une entrée par path littéral, par path résolu, ou par le nom JSR du paquet lié lu depuis le deno.json de la cible. Quand aucun argument ne correspond, unlink sort en code non-zéro, donc une typo est détectable depuis les scripts. Comme fix de découvrabilité, deno add ./local-dir et deno install ./local-dir sortent maintenant avec un hint « Did you mean deno link ./local-dir ? » quand le spec résout vers un répertoire linkable.

deno test --shard=<i>/<n> apporte le sharding CI style Vitest / Jest / Playwright à deno test. Les fichiers de test découverts sont triés pour un ordre stable, puis découpés en <n> groupes consécutifs et équilibrés, et seuls les fichiers du groupe <i> s'exécutent. Chaque fichier atterrit dans exactement un shard, les tailles de groupe diffèrent d'au plus un, et la sélection se passe avant tout --shuffle, donc un shard donné exécute les mêmes fichiers sur chaque machine quelle que soit la seed de shuffle. La PR est explicite sur le compromis : le shard est sélectionné au runtime, après que le module graph du suite complète a été construit et type-checked, donc chaque machine paie encore le coût de build du graph et de type-check pour toute la suite. Déplacer le pré-filtre de shard avant le type-checking, pour que chaque machine ne charge et ne check que son propre sous-ensemble, est un follow-up naturel.

Le fetch request_builder_hook lit les variables d'environnement X_DENO_FETCH_TOKEN et CDN_LOOP une fois et, quand elles sont présentes, les injecte en tant qu'en-têtes x-deno-fetch-token et cdn-loop sur chaque fetch() sortant (à la fois le main worker et les web workers). L'en-tête cdn-loop permet à l'infrastructure upstream de détecter les boucles de requêtes. Pour garder le fetch token trustworthy, toute copie de x-deno-fetch-token fournie par l'utilisateur est assainie avant que la valeur du runtime soit appliquée, donc le code utilisateur ne peut pas l'usurper. Quand aucune des deux env vars n'est set, aucun en-tête supplémentaire n'est ajouté. C'est le côté runtime de la même plomberie de déploiement cloud que le produit Deno Deploy utilise pour identifier quel déploiement a fait un appel sortant.

Ce qui suit

Le cluster de quatre PR est un signal fort de la direction prise par Deno : un main qui traite le desktop comme une cible de première classe, ajoute la parité de sharding CI avec Vitest / Jest / Playwright, finalise le workflow local-package style npm-link, et expose les en-têtes fetch de niveau runtime dont les déploiements cloud ont besoin. La prochaine release Deno (probablement 2.8.4, vu que les release notes Deno 2.8 sont sorties le 1er juin) est la première chance que ces fonctionnalités arrivent dans un build tagué. La PR deno desktop est la dernière des quatre à avoir atterri, et c'est celle avec le plus de surface area à valider, donc le premier build tagué qui livre les quatre est aussi celui contre lequel déposer du feedback.

Questions fréquentes

Articles connexes

Plus de couverture avec des sujets et tags en commun.

Astro 7.0.0-beta.4 fait de Sätteri le processeur Markdown par défaut et promeut le routage avancé, le logger personnalisé et le rendu en flux en stable
frameworks

Astro 7.0.0-beta.4 fait de Sätteri le processeur Markdown par défaut et promeut le routage avancé, le logger personnalisé et le rendu en flux en stable

Astro 7.0.0-beta.4 (15 juin 2026) active par défaut le pipeline Markdown Rust Sätteri, retire le drapeau expérimental du routage avancé, du logger personnalisé et du nouveau moteur de rendu, supprime les commandes CLI obsolètes astro db/login/logout/link/init, et intègre en standard le mode serveur de développement en arrière-plan ajouté en alpha.2.
GLM-5.2 de Z.ai : un modèle 1M de contexte en open weights conçu pour les agents de code long-horizon, analyse approfondie
tooling

GLM-5.2 de Z.ai : un modèle 1M de contexte en open weights conçu pour les agents de code long-horizon, analyse approfondie

Le 16 juin 2026, Z.ai a publié GLM-5.2 sous licence MIT, avec un contexte solide d'un million de tokens, une optimisation d'attention sparse appelée IndexShare qui réduit les FLOPs par token de 2,9×, un module anti-hack pour le RL de code, et des scores de benchmark qui le placent à quelques points de Claude Opus 4.8 sur Terminal-Bench 2.1, devant GPT-5.5 sur trois suites long-horizon, et en tête du classement open weights sur tous les benchmarks de code que l'entreprise a choisi de publier. Cette longue lecture parcourt l'architecture, IndexShare + MTP, l'infrastructure slime pour le RL agentique, le module anti-hack, la table complète des benchmarks avec toutes les notes de bas de page, et ce que cela implique pour le reste de la course au long contexte en open weights.
Fresh 2.3 : Zero JS par Défaut, View Transitions et Support WebSocket
runtimes

Fresh 2.3 : Zero JS par Défaut, View Transitions et Support WebSocket

Fresh 2.3 tient enfin sa promesse de 'zéro JavaScript par défaut', ajoute le support natif des View Transitions, des handlers WebSocket intégrés, l'injection de nonce CSP et le support de l'API Temporal dans les islands.

Commentaires

Connexion Connectez-vous pour participer à la conversation.

Pas encore de commentaires. Soyez le premier à partager vos pensées.