Mille et une manières d'intégrer la librairie JavaScript

Mille et une manières d'intégrer la librairie JavaScript

JavaScript est un langage qui ne cesse d'évoluer sous la pression des auteurs d'applications Web. De plus, la volonté de réutiliser des composants d'un projet à l'autre et de faciliter la création d'interfaces Web a conduit à l'émergence de multiples systèmes de modules et de packaging. Cela conduit à de multiples manières d'intégrer notre librairie, selon le framework utilisé. Voici un petit résumé de la situation actuelle et des dernières nouveautés.

Nous ne pouvons pas publier une librairie séparée par framework ou système de packaging JavaScript existant, il y en aurait plusieurs dizaines, et elles augmenteraient continuellement. Nous avons donc choisi de ne faire qu'une librairie pour JavaScript/ECMAScript, mais qui soit utilisable avec tous les principaux frameworks, via des mécanismes d'intégration standards.

Les standards retenus


Les deux critères définissant de facto ce qui peut être utilisé en JavaScript sont:

  • Le support généralisé dans les navigateur Web
  • Le support dans Node.js

Après des débuts douloureux dans les années 2000 où chaque éditeur de navigateur ajoutait des extensions de son côté, le langage JavaScript s'est standardisé sous la houlette de l'organisation ECMA, qui publie chaque année une nouvelle version ECMAScript officialisant les nouvelles fonctionnalités approuvées par les comités de standardisation, après un processus de débat et de sélection rigoureux. Ces fonctionnalités sont généralement rapidement intégrées dans les navigateurs et dans Node.js. La standardisation ECMAScript est donc un troisième critère définissant ce que nous nous autorisons d'utiliser dans notre librairie.

Méthodes d'inclusions de notre librairie supportées


Voici les différentes manières d'inclusions supportées, de la plus ancienne à la plus récente, avec quelques mots sur les implications de chaque méthode.

Méthode traditionnelle en HTML


Pour charger notre librairie dans une simple page HTML, il suffit d'utiliser un tag <script src="...">:

...
<script src="yoctolib-es2017/yocto_api.js"></script>
<script src="yoctolib-es2017/yocto_temperature.js"></script>
...


Le navigateur chargera tous les fichiers .js dans un environnement global, et les classes définies peuvent donc être ensuite utilisées dans tous les scripts de la page.

La librairie détecte automatiquement qu'elle est utilisée dans un navigateur, et effectue les accès réseau à l'aide des classes système fournies par le navigateur.

Pour un exemple complet d'inclusion traditionnelle en HTML, vous pouvez lire ce tutorial.

Méthode traditionnelle en Node.js


La méthode traditionnelle pour définit et charger des modules en Node.js s'appelle CommonJS. Elle s'emploie à l'aide de la fonction require(), qui provoque le chargement du module désiré. L'exemple précédent s'écrit donc en Node.js comme ceci:

require('yoctolib-es2017/yocto_api.js');
require('yoctolib-es2017/yocto_temperature.js');


Si l'on préfère charger la totalité de la librairie sans lister explicitement les classes à inclure, on peut aussi utiliser:

require('yoctolib-es2017');


Notez que pour permettre la portabilité directe du code d'une version à l'autre, notre inclusion CommonJS exporte directement toutes les classes choisies dans l'environnement global, sans qu'il soit nécessaire de les préfixer par le nom d'un symbole de package. Cela peut être évité si nécessaire.

La librairie détecte automatiquement qu'elle est utilisée dans un environnement Node.js, et effectue les accès réseau à l'aide des librairies Node.js.

Pour faciliter l'utilisation dans Node.js, notre librairie est disponible dans le repository npm, et peut donc être ajoutée à un projet Node.js avec la commande

npm install yoctolib-es2017


Il est aussi possible de l'utiliser avec d'autres package managers dynamiques plus évolués que npm, par exemple ceux qui effectuent un chargement à la demande des modules. Il faut toutefois s'assurer que les prérequis de notre librairie (notemment la librairie ws qui fournit l'accès WebSocket) soient disponibles.

Pour un exemple complet d'inclusion traditionnelle en Node.js, vous pouvez lire ce tutorial.

Environnements hybrides (aka Electron)


Certains environnements de développement combinent Node.js et un navigateur dans la même application pour allier la portabilité d'un affichage Web avec la liberté d'un accès complet aux ressources offert par Node.js. Dans ce cas, le node JavaScript est lancé dans un environnement Node.js, et c'est donc la méthode d'inclusion pour Node.js qui s'applique.

La librairie détecte automatiquement qu'elle est utilisée dans un environnement Node.js, et effectue les accès réseau à l'aide des librairies Node.js, indépendamment du fait qu'il y ait aussi un navigateur dans l'application. Attention toutefois si vous voulez utiliser la librairie depuis le process d'interface plutôt que depuis le process principal: la librairie risque de ne pas pouvoir accéder aux librairies Node.js auxquelles elle s'attend (erreur sur les WebSocket). Vous pouvez contourner ce problème en forçant alors la librairie à utiliser les navigateur pour communiquer en ajoutant juste après l'import de la librairie:

YAPI._isNodeJS = false;



Pour un exemple complet d'utilisation avec Electron, vous pouvez lire cet article.

La nouvelle méthode ECMAscript (modules EM)


ECMAScript a introduit en 2016 un nouveau système de modules harmonisé, qui ressemble un peu aux systèmes de modules d'autres langages comme Python et C#. Il commence maintenant à se généraliser, y compris dans Node.js, ce qui justifie que nous nous y intéressions.

Ce système de module est déclaratif et statique, ce qui a l'avantage de permettre une résolution des dépendances sans devoir exécuter le code, contrairement aux systèmes traditionnels en JavaScript, et permet aussi de détecter l'utilisation de symboles non définis.

Par contre ce système déclaratif ne permet plus de faire une seule version de la librairie qui fonctionne dans un navigateur et dans Node.js, car les modules Node.js à importer n'existent pas dans le navigateur, et déclancheraient donc une erreur. Nous avons donc du extraire tout le code spécifique à Node.js dans un fichier séparé, et produire deux version séparées de la librairie au format de module ECMAScript: une pour l'utilisation dans les pages HTML, et l'autre pour l'utilisation dans Node.js

Voici la syntaxe pour l'utilisation dans une page HTML:

<script type="module">
import { YAPI, YErrorMsg, YModule } from './yoctolib_esm_html/yocto_api.mjs';
import { YTemperature } from './yoctolib_esm_html/yocto_temperature.mjs';
...
</script>


La syntaxe est identique pour l'utilisation en Node.js, à l'exception de la référence à la librairie yoctolib-esm. La librairie doit être naturellement référencée dans les dépendances du projet:

import { YAPI, YErrorMsg, YModule } from 'yoctolib-esm/yocto_api.mjs';
import { YTemperature } from 'yoctolib-esm/yocto_temperature.mjs';


Pour des exemples complet d'utilisation de cette librairie sous forme de module ECMAScript, consultez les nouveaux exemples intitulés Prog-ESModule dans notre librairie pour JavaScript/ECMAScript. Vous les trouverez dans les répertoires example_html et example_nodejs.

A priori, on pourrait penser que ce nouveau type de module est un simple changement d'écriture. En réalité c'est plus que cela. En effet, les modules ECMAScript sont chargés dans un contexte très différent par le navigateur et Node.js. La possibilité de charger notre librairie de cette manière vous facilitera donc l'inclusion de notre librairie pour tous les environnements qui utilisent les modules ECMAScript comme méthode native, comme TypeScript. D'ailleurs, nous en reparlerons prochainement...

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.