105 votes

Style de nœud requis pour le javascript côté client ?

Y a-t-il des bibliothèques pour JavaScript dans le navigateur qui offrent la même flexibilité/modularité/facilité d'utilisation que le require de Node?

Pour donner plus de détails : la raison pour laquelle require est si bon, c'est qu'il :

  1. Permet de charger dynamiquement du code depuis d'autres emplacements (ce qui est stylistiquement mieux, à mon avis, que de lier tout votre code dans le HTML)
  2. Fournit une interface cohérente pour construire des modules
  3. Il est facile pour les modules de dépendre d'autres modules (je pourrais écrire, par exemple, une API qui nécessite jQuery afin de pouvoir utiliser jQuery.ajax())
  4. Le javascript chargé est isolé, ce qui signifie que je pourrais charger avec var dsp = require("dsp.js"); et je pourrais accéder à dsp.FFT, ce qui n'interférerait pas avec ma variable locale var FFT

Je n'ai pas encore trouvé de bibliothèque qui le fait efficacement. Les contournements que j'ai tendance à utiliser sont les suivants :

  • coffeescript-concat -- il est assez facile de requérir d'autres js, mais vous devez le compiler, ce qui signifie qu'il est moins adapté pour un développement rapide (par exemple, la construction d'API en mode test)

  • RequireJS -- C'est populaire, simple et résout 1-3, mais le manque de portée est un vrai casse-tête (je pense que head.js est similaire en ce sens qu'il manque de portée, bien que je n'ai jamais eu l'occasion de l'utiliser. De même, LABjs peut charger et .wait() atténue les problèmes de dépendance, mais il ne gère toujours pas la portée)

De ce que je peux dire, il semble qu'il y ait de nombreuses solutions pour le chargement dynamique et/ou asynchrone de javascript, mais elles tendent à avoir les mêmes problèmes de portée que le simple chargement de js à partir du HTML. Plus que tout, j'aimerais trouver un moyen de charger du javascript qui ne pollue pas du tout l'espace de noms global, mais qui me permet quand même de charger et utiliser des bibliothèques (comme le fait le require de Node).

MISE À JOUR 2020: Les modules sont désormais standard en ES6, et à partir de mi-2020, ils sont nativement pris en charge par la plupart des navigateurs. Les modules prennent en charge le chargement synchrone et asynchrone (en utilisant les promesses). Ma recommandation actuelle est que la plupart des nouveaux projets devraient utiliser des modules ES6 et utiliser un transpileur pour revenir à un seul fichier JS pour les navigateurs obsolètes.

En tant que principe général, la bande passante est aujourd'hui généralement beaucoup plus large que lorsque j'ai posé cette question à l'origine. Ainsi, en pratique, vous pouvez raisonnablement choisir d'utiliser toujours un transpileur avec des modules ES6 et de vous concentrer sur l'efficacité du code plutôt que sur le réseau.

ÉDITION PRÉCÉDENTE (ou si vous n'aimez pas les modules ES6): Depuis que j'ai écrit ceci, j'ai largement utilisé RequireJS (qui a maintenant une documentation beaucoup plus claire). RequireJS était vraiment le bon choix à mon avis. J'aimerais clarifier comment fonctionne le système pour les personnes aussi perdues que je l'étais:

Vous pouvez utiliser require dans le développement quotidien. Un module peut être n'importe quoi retourné par une fonction (typiquement un objet ou une fonction) et est isolé en tant que paramètre. Vous pouvez également compiler votre projet dans un seul fichier pour le déploiement en utilisant r.js (en pratique, c'est presque toujours plus rapide, même si require peut charger des scripts en parallèle).

La principale différence entre RequireJS et le require de style node comme browserify (un projet cool suggéré par tjameson) est la manière dont les modules sont conçus et requis:

  • RequireJS utilise AMD (Async Module Definition). En AMD, require prend une liste de modules (fichiers javascript) à charger et une fonction de rappel. Lorsqu'il a chargé chacun des modules, il appelle le rappel avec chaque module en tant que paramètre du rappel. Ainsi, c'est vraiment asynchrone et donc bien adapté au web.
  • Node utilise CommonJS. En CommonJS, require est un appel bloquant qui charge un module et le renvoie comme un objet. Cela fonctionne bien pour Node car les fichiers sont lus à partir du système de fichiers, ce qui est assez rapide, mais cela fonctionne mal sur le web car le chargement synchrone de fichiers peut prendre beaucoup plus de temps.

En pratique, de nombreux développeurs ont utilisé Node (et donc CommonJS) avant même de voir AMD. De plus, de nombreuses bibliothèques/modules sont écrites pour CommonJS (en ajoutant des choses à un objet exports) plutôt que pour AMD (en retournant le module de la fonction define). Par conséquent, de nombreux développeurs issus de Node veulent utiliser des bibliothèques CommonJS sur le web. C'est possible, car le chargement à partir d'une balise </code> est bloquant. Des solutions comme browserify prennent des modules CommonJS (Node) et les enveloppent pour que vous puissiez les inclure avec des balises de script.</p> <p>Par conséquent, si vous développez votre propre projet multi-fichiers pour le web, je recommande fortement RequireJS, car c'est vraiment un système de module pour le web (bien que, pour être honnête, je trouve AMD beaucoup plus naturel que CommonJS). Récemment, la distinction est devenue moins importante, car RequireJS permet désormais essentiellement d'utiliser la syntaxe CommonJS. De plus, RequireJS peut être utilisé pour charger des modules AMD dans Node (bien que je préfère <a href="https://github.com/ajaxorg/node-amd-loader" rel="noreferrer">node-amd-loader</a>).</p></x-turndown>

31voto

Ilyas Assainov Points 474

Je réalise qu'il peut y avoir des débutants cherchant à organiser leur code. Nous sommes en 2022, et si vous envisagez une application JS modulaire, vous devriez commencer dès maintenant avec npm et Webpack.

Voici quelques étapes simples pour démarrer :

  1. Dans la racine de votre projet, exécutez npm init -y pour initialiser un projet npm
  2. Téléchargez le module bundler Webpack : npm install webpack webpack-cli
  3. Créez un fichier index.html :

    App

Accordez une attention particulière au fichier _bundle.js - ce sera un fichier JS final généré par webpack, que vous ne modifierez pas directement (continuez de lire).

  1. Créez un fichier /app.js dans lequel vous importerez d'autres modules :

    const printHello = require('./print-hello');

    printHello();

  2. Créez un module print-hello.js exemple :

    module.exports = function() { console.log('Bonjour le monde !'); }

  3. Créez un fichier /webpack.config.js et copiez-collez ce qui suit :

    var path = require('path');

    module.exports = { entry: './app.js', output: { path: path.resolve(__dirname), filename: '_bundle.js' } };

Dans le code ci-dessus, il y a 2 points :

  • l'entrée app.js est l'endroit où vous écrirez votre code JS. Il importera d'autres modules comme montré ci-dessus.
  • la sortie _bundle.js est votre bundle final généré par webpack. C'est ce que votre html verra à la fin.
  1. Ouvrez votre fichier package.json, et remplacez scripts par la commande suivante :

    "scripts": { "start": "webpack --mode production -w" },

  2. Et enfin exécutez le script watch app.js et générer le fichier _bundle.js en exécutant : npm start.

  3. Profitez de coder !

22voto

tjameson Points 8098

Découvrez ender. Cela fait beaucoup de choses.

Aussi, browserify est assez bon. J'ai utilisé require-kiss¹ et ça marche. Il y en a probablement d'autres.

Je ne suis pas sûr de RequireJS. Ce n'est tout simplement pas pareil que celui de node. Vous pourriez rencontrer des problèmes lors du chargement à partir d'autres endroits, mais ça pourrait fonctionner. Tant qu'il y a une méthode de fourniture ou quelque chose qui peut être appelé.

En résumé - Je recommanderais browserify ou require-kiss.


Mise à jour :

1 : require-kiss est maintenant obsolète, et l'auteur l'a supprimé. Depuis, j'utilise RequireJS sans problèmes. L'auteur de require-kiss a écrit pakmanager et pakman. En toute transparence, je travaille avec le développeur.

Personnellement, je préfère RequireJS. C'est beaucoup plus facile à déboguer (vous pouvez avoir des fichiers séparés en développement, et un seul fichier déployé en production) et repose sur une "norme" solide.

18voto

Torben Points 1481

J'ai écrit un petit script qui permet le chargement asynchrone et synchrone de fichiers Javascript, ce qui pourrait être utile ici. Il n'a pas de dépendances et est compatible avec Node.js & CommonJS. L'installation est assez simple :

$ npm install --save @tarp/require

Ensuite, ajoutez simplement les lignes suivantes à votre HTML pour charger le module principal :

Tarp.require({main: "./scripts/main"});

A l'intérieur de votre module principal (et de tout sous-module, bien sûr) vous pouvez utiliser require() comme vous le connaissez de CommonJS/NodeJS. La documentation complète et le code peuvent être trouvés sur GitHub.

16voto

Lucio M. Tato Points 827

Une variation de la superbe réponse d'Ilya Kharlamov, avec un peu de code pour le rendre compatible avec les outils de développement de Chrome.

//
///- NÉCESSITE FN
// équivalent à require de node.js
function require(url){
    if (url.toLowerCase().substr(-3)!=='.js') url+='.js'; // permet de charger sans le suffixe js;
    if (!require.cache) require.cache=[]; //initialise le cache
    var exports=require.cache[url]; //obtient depuis le cache
    if (!exports) { //non mis en cache
            try {
                exports={};
                var X=new XMLHttpRequest();
                X.open("GET", url, 0); // synchrone
                X.send();
                if (X.status && X.status !== 200)  throw new Error(X.statusText);
                var source = X.responseText;
                // correction (si sauvegardé depuis les Chrome Dev Tools)
                if (source.substr(0,10)==="(function("){ 
                    var moduleStart = source.indexOf('{');
                    var moduleEnd = source.lastIndexOf('})');
                    var CDTcomment = source.indexOf('//@ ');
                    if (CDTcomment>-1 && CDTcomment

6voto

Ilya Kharlamov Points 631
(function () {
    // c est le cache, le reste sont les constantes
    var c = {},s="status",t="Text",e="exports",E="Error",r="require",m="module",S=" ",w=window;
    w[r]=function R(url) {
        url+=/.js$/i.test(url) ? "" : ".js";// pour permettre le chargement sans suffixe js;
        var X=new XMLHttpRequest(),module = { id: url, uri: url }; //selon la norme des modules 1.1
        if (!c[url])
            try {
                X.open("GET", url, 0); // sync
                X.send();
                if (X[s] && X[s] != 200) 
                    throw X[s+t];
                Function(r, e, m, X['response'+t])(R, c[url]={}, module); // Exécute le module
                module[e] && (c[url]=module[e]);
            } catch (x) {
                throw w[E](E+" in "+r+": Can't load "+m+S+url+":"+S+x);
            }
        return c[url];
    }
})();

Mieux vaut ne pas l'utiliser en production en raison du blocage. (Dans node.js, require() est un appel bloquant aussi).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X