Fermer

janvier 24, 2025

Construire des applications / packages agnostiques d’exécution avec JavaScript

Construire des applications / packages agnostiques d’exécution avec JavaScript


Apprenez à créer des applications et des packages JavaScript Angnoscript d’exécution en utilisant des temps d’exécution modernes comme Node.js, Bun et Deno avec des méthodes de détection fiables.

Node.js a popularisé le concept d’exécution JavaScript sur le serveur. Aujourd’hui, il y a plus de temps d’exécution JavaScript destinés à créer des applications basées sur un serveur, avec Chignon et LLRT Parmi les plus récents, je suis au courant. Deno existe depuis quelques années, et leur version de la version 2 semble atteindre un accord car il a une meilleure compatibilité avec l’API Node.js.

Certains de ces temps d’exécution ont adopté des API de plate-forme Web pour permettre à la même API d’être utilisée à la fois dans le navigateur et le serveur (par exemple, Web Crypto API) – mais ils ont également des API spécifiques à l’exécution.

Par exemple, Deno a des API spécifiques comme Deno.env qui se comporte comme process.env Dans Node.js mais avec plus de méthodes pour obtenir, définir ou supprimer les variables d’environnement. Chaque plate-forme a des API spécifiques à l’exécution qui facilitent la réalisation de certaines tâches. Mais comment pouvez-vous utiliser une API spécifique à l’exécution et permettre toujours à votre application / programme de fonctionner sur toutes les plates-formes (c’est-à-dire, d’exécution-agnostique)?

Je vais vous montrer la meilleure façon de détecter l’exécution / la plate-forme et ce que vous pouvez en faire. Je vais commencer par la meilleure option, puis me conclure avec des suggestions courantes qui échoueront probablement.

La sauce secrète 🤫

La bonne façon de savoir sur quel runtime votre code fonctionne est d’utiliser navigator.userAgent. Il renvoie une chaîne contenant l’exécution et éventuellement la version de l’exécution.

Vous connaissez peut-être cette API de la spécifications du navigateur Pour déterminer le navigateur sur lequel votre code fonctionne. Bien que la détection du navigateur à l’aide de cette approche ne soit pas recommandée, le Wintercg Le groupe a convenu sur cela dans le cadre de leur API de plate-forme Web commune minimum pour les temps d’exécution non basés sur ECMAScript.

Voici un exemple du résultat que vous obtenez lorsque vous appelez cette API dans certains des temps JavaScript aujourd’hui:

Temps d’exécutionSortir
Node.jsNode.js/22
ChignonBun/1.0.28
Cloudflare WorkersCloudflare-Workers
NezDeno/1.40.0

Cela devient utile lorsque vous créez des applications ou des packages multiplateformes. J’utilise BUN pour certains projets, et BUN met en œuvre un ensemble de fonctions de commodité pour consommer de manière asynchrone le corps d’un ReadableStream et le convertir en différents formats binaires. Lorsque vous construisez un package qui utilise l’une de ces API, vous pouvez utiliser navigator.userAgent pour passer à la bonne implémentation pour l’exécution spécifique. Faire quelque chose de similaire dans un temps d’exécution comme Node.js ou les travailleurs nécessiterait plus de code. Au lieu de montrer cela ici, j’utiliserai un exemple beaucoup plus simple.

Voyons comment implémenter une fonction qui enregistre la représentation de chaîne d’un objet.

function logObject(obj) {
  const runtime = navigator.userAgent;

  if (runtime.startsWith("Deno")) {
    console.log(Deno.inspect(obj));
  } else if (runtime.startsWith("Bun")) {
    console.log(Bun.inspect(obj));
  } else {
    
    const util = require("node:util");
    console.log(util.inspect(obj));
  }
}

class Foo {
  get [Symbol.toStringTag]() {
    return "bar";
  }
  [Symbol.for("Deno.customInspect")]() {
    return "I'm running in Deno";
  }
}

class Bar {}

const obj = {
  a: 10,
  b: "hello",
  test: function () {},
};

console.log("Running in " + navigator.userAgent);
logObject(obj);
logObject(new Bar());
logObject(new Foo());

Le logObject() La fonction vérifie le temps d’exécution, puis utilise l’API spécifique à l’exécution pour récupérer une représentation de chaîne de l’objet. Le GIF ci-dessous montre ce que vous obtiendrez lorsque vous exécutez le code.

Ce GIF montre la sortie de l'exécution du code JS à l'aide de Deno, Bun et Node.js

Si vous regardez attentivement, vous remarquerez que chaque runtime renvoie la valeur dans un format légèrement différent, et avec Deno, nous obtenons une sortie personnalisée lorsque nous spécifions une fonction d’inspection personnalisée.

Dans le mauvais sens ❌

Nous avons vu comment utiliser navigator.userAgent comme la bonne façon, mais vous trouverez différentes suggestions lorsque vous Google pour les réponses. Par exemple, ce code a été suggéré sur Débordement de pile Pour vérifier s’il fonctionne sur Deno:

if ("Deno" in window) {
  console.log("window.Deno=", window.Deno);
} else {
  console.log("no Deno here");
}

Cela fonctionnera, mais vous risquez le risque d’un faux résultat si vous ou vos dépendances joignez un objet avec le même nom au window objet.

Il y a des hacks spécifiques à l’API qui ressemblent à l’un d’entre eux:

function isNode() {
  try {
    const fs = await import('fs');
    return true;
  } catch () {
    return false;
  }
}
function isNode() {
  try {
    const env = process.env;
    return true;
  } catch () {
    return false;
  }
}

Le problème avec cette approche est que maintenant que CloudFlare prend en charge process.envle code qui travaillait de manière fiable ne fonctionnerait plus. La version récente des travailleurs de CloudFlare prend également en charge l’importation de modules Node.js avec le node: Préfixe, qui ferait probablement toute application qui s’appuie sur cet échec.

Conclusion

Dans cet article, nous explorons comment déterminer l’environnement d’exécution pour le code JavaScript, en particulier avec l’avènement des temps d’exécution modernes comme Bun et Deno. La meilleure approche consiste à utiliser navigator.userAgent qui fournit une chaîne identifiant l’exécution et éventuellement sa version. Le groupe WinterCG approuve cette méthode dans le cadre de leur API de plate-forme Web commune minimale.

Nous avons également discuté des méthodes moins fiables, telles que la vérification des objets globaux ou des API spécifiques, ce qui peut entraîner des inexactitudes en raison de capacités de chevauchement entre les différents temps d’exécution.




Source link