[ Web Proxy ]
URL:
Viewing: https://fr.javascript.info/modules-intro [Back]  [Original]

Modules, introduction
FR

Nous souhaitons rendre ce projet open source disponible pour les gens du monde entier.

Aidez-nous traduire le contenu de ce tutoriel dans votre langue!

    Rechercher sur Javascript.info:
    Rechercher dans le tutoriel:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    Modules, introduction

    Au fur et mesure que notre application grandit, nous souhaitons la scinder en plusieurs fichiers, appels modules. Un module contient gnralement une classe ou une bibliothque de fonctions pour une tche prcise.

    Pendant longtemps, JavaScript navait pas de module. Ce ntait pas un problme, car au dpart les scripts taient petits et simples, il ntait donc pas ncessaire.

    Mais les scripts sont devenus de plus en plus complexes et la communaut a donc invent diverses mthodes pour organiser le code en modules, des bibliothques spciales pour charger des modules la demande.

    Pour en nommer quelques-uns (pour des raisons historiques) :

    • AMD un des systmes de modules les plus anciens, initialement mis en uvre par la bibliothque require.js.
    • CommonJS le systme de module cr pour Node.js
    • UMD un systme de module supplmentaire, propos comme universel, compatible avec AMD et CommonJS

    Maintenant, tous ces lments deviennent lentement du pass, mais nous pouvons toujours les trouver dans danciens scripts.

    Le systme de modules au niveau du langage est apparu dans la norme en 2015, a progressivement volu depuis, et est dsormais pris en charge par tous les principaux navigateurs et dans Node.js. Nous allons donc tudier les modules JavaScript modernes partir de maintenant.

    Quest-ce quun module?

    Un module nest quun fichier. Un script est un module. Aussi simple que cela.

    Les modules peuvent se charger mutuellement et utiliser des directives spciales, export et import, pour changer des fonctionnalits, appeler les fonctions dun module dans un autre:

    • Le mot-cl export labelise les variables et les fonctions qui doivent tre accessibles depuis lextrieur du module actuel.
    • import permet limportation de fonctionnalits partir dautres modules.

    Par exemple, si nous avons un fichier sayHi.js exportant une fonction

    //  sayHi.js
    export function sayHi(user) {
      alert(`Hello, ${user}!`);
    }

    Un autre fichier peut limporter et lutiliser:

    //  main.js
    import {sayHi} from './sayHi.js';
    
    alert(sayHi); // function...
    sayHi('John'); // Hello, John!

    La directive import charge le module qui a pour chemin ./sayHi.js par rapport au fichier actuel et affecte la fonction exporte sayHi la variable correspondante.

    Lanons lexemple dans le navigateur.

    Comme les modules prennent en charge des mots-cls et des fonctionnalits spciales, nous devons indiquer au navigateur quun script doit tre trait comme un module, en utilisant lattribut <script type="module">.

    Comme a:

    Rsultat
    say.js
    index.html
    export function sayHi(user) {
      return `Hello, ${user}!`;
    }
    <!doctype html>
    <script type="module">
      import {sayHi} from './say.js';
    
      document.body.innerHTML = sayHi('John');
    </script>

    Le navigateur extrait et value automatiquement le module import (et, le cas chant, ses importations), puis excute le script.

    Les modules fonctionnent uniquement via HTTP(s), pas localement

    Si vous essayez douvrir une page Web localement, via le protocole file://, vous verrez que les directives import/export ne fonctionnent pas. Utilisez un serveur Web local, tel que static-server ou utilisez la fonctionnalit live server de votre diteur, tel que VS Code Live Server Extension pour tester les modules.

    Caractristiques du module de base

    Quest-ce qui est diffrent dans les modules par rapport aux scripts normaux?

    Il existe des fonctionnalits de base, valables la fois pour le navigateur et le JavaScript ct serveur.

    Toujours en mode use strict

    Les modules fonctionnent toujours en mode strict. Par exemple. laffectation une variable non dclare donnera une erreur.

    <script type="module">
      a = 5; // error
    </script>

    Porte au niveau du module

    Chaque module a sa propre porte globale. En dautres termes, les variables et les fonctions globales dun module ne sont pas visibles dans les autres scripts.

    Dans lexemple ci-dessous, deux scripts sont imports et hello.js essaie dutiliser la variable user dclare dans user.js. Il choue, car il sagit dun module distinct (vous verrez lerreur dans la console):

    Rsultat
    hello.js
    user.js
    index.html
    alert(user); // pas de variable user (chaque module a des variables indpendantes)
    let user = "John";
    <!doctype html>
    <script type="module" src="user.js"></script>
    <script type="module" src="hello.js"></script>

    Les modules doivent export ce quils veulent tre accessible de lextrieur et import ce dont ils ont besoin.

    • user.js devrait exporter la variable user.
    • hello.js devrait limporter depuis le module user.js.

    En dautres termes, avec les modules, nous utilisons limport/export au lieu de nous appuyer sur des variables globales.

    Ceci est la bonne variante :

    Rsultat
    hello.js
    user.js
    index.html
    import {user} from './user.js';
    
    document.body.innerHTML = user; // John
    export let user = "John";
    <!doctype html>
    <script type="module" src="hello.js"></script>

    Dans le navigateur, si nous parlons de pages HTML, une porte de niveau suprieur indpendante existe galement pour chaque <script type="module">.

    Voici deux scripts sur la mme page, tous deux type="module". Ils ne voient pas les variables de niveau suprieur de lautre:

    <script type="module">
      // La variable est uniquement visible dans ce module
      let user = "John";
    </script>
    
    <script type="module">
      alert(user); // Error: user is not defined
    </script>
    Veuillez noter :

    Dans le navigateur, nous pouvons rendre une variable globale au niveau de la fentre en laffectant explicitement une proprit window, par exemple window.user = "John".

    Ensuite, tous les scripts la verront, la fois avec type="module" et sans.

    Cela dit, faire de telles variables globales est mal vu. Veuillez essayer de les viter.

    Un code de module est charg la premire fois lorsquil est import

    Si le mme module est import dans plusieurs autres modules, son code nest excut quune seule fois, lors de la premire importation. Ensuite, ses exportations sont donnes tous les autres importateurs.

    Lvaluation ponctuelle a des consquences importantes, dont nous devons tre conscients.

    Voyons quelques exemples.

    Premirement, si excuter un code de module entrane des effets secondaires, comme afficher un message, limporter plusieurs fois ne le dclenchera quune seule fois la premire fois:

    //  alert.js
    alert("Module is evaluated!");
    // Importer le mme module  partir de fichiers diffrents
    
    //  1.js
    import `./alert.js`; // le module est charg
    
    //  2.js
    import `./alert.js`; // (n'affiche rien)

    La deuxime importation ne montre rien, car le module a dj t valu.

    Il y a une rgle : le code du module de niveau suprieur doit tre utilis pour linitialisation, la cration de structures de donnes internes spcifiques au module. Si nous devons rendre quelque chose appelable plusieurs fois, nous devons lexporter en tant que fonction, comme nous lavons fait avec sayHi ci-dessus.

    Maintenant, considrons un exemple plus profond.

    Disons quun module exporte un objet:

    //  admin.js
    export let admin = {
      name: "John"
    };

    Si ce module est import partir de plusieurs fichiers, il nest charg que la premire fois, un objet admin est cr, puis transmis tous les autres importateurs.

    Tous les importateurs obtiennent exactement le seul et unique objet admin:

    //  1.js
    import {admin} from './admin.js';
    admin.name = "Pete";
    
    //  2.js
    import {admin} from './admin.js';
    alert(admin.name); // Pete
    
    // 1.js et 2.js font rfrence au mme objet admin
    // Les modifications apportes dans 1.js sont visibles dans 2.js

    Comme vous pouvez le voir, lorsque 1.js modifie la proprit name dans le admin import, alors 2.js peut voir le nouveau admin.name.

    Cest prcisment parce que le module nest excut quune seule fois. Les exportations sont gnres, puis partages entre les importateurs, donc si quelque chose change lobjet admin, les autres modules le verront.

    Un tel comportement est en fait trs pratique, car il nous permet de configurer des modules.

    En dautres termes, un module peut fournir une fonctionnalit gnrique qui ncessite une configuration. Par exemple. lauthentification a besoin dinformations didentification. Ensuite, il peut exporter un objet de configuration en attendant que le code externe lui soit affect.

    Voici le modle classique :

    1. Un module exporte certains moyens de configuration, par exemple un objet de configuration.
    2. Lors de la premire importation, nous linitialisons, crivons dans ses proprits. Le script dapplication de niveau suprieur peut le faire.
    3. Dautres importations utilisent le module.

    Par exemple, le module admin.js peut fournir certaines fonctionnalits (par exemple, lauthentification), mais sattend ce que les informations didentification entrent dans lobjet config de lextrieur:

    //  admin.js
    export let config = { };
    
    export function sayHi() {
      alert(`Ready to serve, ${config.user}!`);
    }

    Ici, admin.js exporte lobjet config (initialement vide, mais peut galement avoir des proprits par dfaut).

    Ensuite, dans init.js, le premier script de notre application, nous en importons config et dfinissons config.user:

    //  init.js
    import {config} from './admin.js';
    config.user = "Pete";

    Maintenant, le module admin.js est configur.

    Further importers can call it, and it correctly shows the current user:

    //  another.js
    import {sayHi} from './admin.js';
    
    sayHi(); // Prt  tre utilis, Pete!

    import.meta

    Lobjet import.meta contient les informations sur le module actuel.

    Son contenu dpend de lenvironnement. Dans le navigateur, il contient lURL du script ou une URL de page Web actuelle si elle est en HTML:

    <script type="module">
      alert(import.meta.url); // URL du script
      // pour un script en ligne - l'URL de la page HTML actuelle
    </script>

    Dans un module, this nest pas dfini

    Cest un peu une caractristique mineure, mais pour tre complet, nous devrions le mentionner.

    Dans un module, lobjet global this est indfini.

    Comparez-le des scripts sans module, l o il est un object global:

    <script>
      alert(this); // window
    </script>
    
    <script type="module">
      alert(this); // undefined
    </script>

    Fonctionnalits spcifiques au navigateur

    Il existe galement plusieurs diffrences de scripts spcifiques au navigateur avec type="module" par rapport aux scripts classiques.

    Vous devriez peut-tre ignorer cette section pour linstant si vous lisez pour la premire fois ou si vous nutilisez pas JavaScript dans un navigateur.

    Les modules sont diffrs

    Les modules sont toujours diffrs, avec le mme effet que lattribut defer (dcrit dans le chapitre Les scripts: async, defer), pour les scripts externes et intgrs.

    En dautres termes:

    • tlcharger des modules externe <script type="module" src="..."> ne bloque pas le traitement HTML, ils se chargent en parallle avec dautres ressources.
    • Les modules attendent que le document HTML soit compltement prt (mme sils sont minuscules et se chargent plus rapidement que le HTML), puis sexcutent.
    • lordre relatif des scripts est maintenu : les scripts qui entrent en premier dans le document sont excuts en premier.

    Comme effet secondaire, les modules voient toujours la page HTML entirement charge, y compris les lments HTML situs en dessous.

    Par exemple:

    <script type="module">
      alert(typeof button); // object: le script peut 'voir' le bouton ci-dessous
      //  mesure que les modules sont diffrs, le script s'excute aprs le chargement de la page entire
    </script>
    
    Comparez au script habituel ci-dessous:
    
    <script>
      alert(typeof button); // button est undefined, le script ne peut pas voir les lments ci-dessous
      // les scripts normaux sont excuts immdiatement, avant que le reste de la page ne soit trait
    </script>
    
    <button id="button">Button</button>

    Remarque : le deuxime script fonctionne avant le premier ! Nous verrons donc dabord undefined, puis object.

    Cest parce que les modules sont diffrs, nous attendons donc que le document soit trait. Les scripts rguliers sexcutent immdiatement, nous avons donc vu son resultat en premier.

    Lorsque nous utilisons des modules, nous devons savoir que la page HTML apparat lors de son chargement et que les modules JavaScript sexcutent par la suite, afin que lutilisateur puisse voir la page avant que lapplication JavaScript soit prte. Certaines fonctionnalits peuvent ne pas encore fonctionner. Nous devons dfinir des indicateurs de chargement ou veiller ce que le visiteur ne soit pas confus par cela.

    Async fonctionne sur les scripts en ligne

    Pour les scripts non modulaires, lattribut async ne fonctionne que sur les scripts externes. Les scripts asynchrones sexcutent immdiatement lorsquils sont prts, indpendamment des autres scripts ou du document HTML.

    Pour les modules, cela fonctionne sur tous les scripts.

    Par exemple, le script ci-dessous est async et nattend donc personne.

    Il effectue limportation (rcupre ./analytics.js) et sexcute lorsquil est prt, mme si le document HTML nest pas encore termin ou si dautres scripts sont toujours en attente.

    Cest bon pour une fonctionnalit qui ne dpend de rien, comme des compteurs, des annonces, des couteurs dvnements au niveau du document.

    <!-- toutes les dpendances sont rcupres (analytics.js) et le script s'excute -->
    <!-- il n'attend pas le document ou d'autres balises <script> -->
    <script async type="module">
      import {counter} from './analytics.js';
    
      counter.count();
    </script>

    Scripts externes

    Les scripts externes de type="module" se distinguent sous deux aspects:

    1. Les scripts externes avec le mme src ne sexcutent quune fois:

      <!-- le script my.js est rcupr et excut une seule fois -->
      <script type="module" src="my.js"></script>
      <script type="module" src="my.js"></script>
    2. Les scripts externes extraits dune autre origine (par exemple, un autre site) ncessitent CORS en-ttes, comme dcrit dans le chapitre Fetch: Requtes Cross-Origin. En dautres termes, si un module est extrait dune autre origine, le serveur distant doit fournir un en-tte Access-Control-Allow-Origin permettant lextraction.

      <!-- another-site.com doit fournir Access-Control-Allow-Origin -->
      <!-- sino, le script ne sera pas excut -->
      <script type="module" src="http://another-site.com/their.js"></script>

      Cela garantit une meilleure scurit par dfaut.

    Aucun module nu autoris

    Dans le navigateur, import doit avoir une URL relative ou absolue. Les modules sans chemin sont appels modules nus. De tels modules ne sont pas autoriss lors de limportation.

    Par exemple, cette import nest pas valide:

    import {sayHi} from 'sayHi'; // Error, "bare" module
    // le module doit avoir un chemin, par exemple './sayHi.js'

    Certains environnements, tels que Node.js ou les outils de bundle autorisent les modules nus, sans chemin daccs, car ils disposent de moyens propres de recherche de modules trouver des modules et des hooks pour les ajuster. Mais les navigateurs ne supportent pas encore les modules nus.

    Compatibilit, nomodule

    Les anciens navigateurs ne comprennent pas type="module". Les scripts de type inconnu sont simplement ignors. Pour eux, il est possible de fournir une solution de secours en utilisant lattribut nomodule :

    <script type="module">
      alert("Runs in modern browsers");
    </script>
    
    <script nomodule>
      alert("Modern browsers know both type=module and nomodule, so skip this")
      alert("Old browsers ignore script with unknown type=module, but execute this.");
    </script>

    Construire des outils

    Dans la vie relle, les modules de navigateur sont rarement utiliss sous leur forme brute. Gnralement, nous les regroupons avec un bundle tel que Webpack et les dployons sur le serveur de production.

    Lun des avantages de lutilisation des bundles est quils permettent de mieux contrler la faon dont les modules sont rsolus, permettant ainsi des modules nus et bien plus encore, comme les modules CSS / HTML.

    Les outils de construction font ce qui suit:

    1. Prenons un module principal, celui qui est destin tre plac dans <script type="module"> dans le HTML.
    2. Analyser ses dpendances : importations puis importations dimportations etc.
    3. Construire un seul fichier avec tous les modules (ou plusieurs fichiers configurables), en remplaant les appels import natifs par des fonctions dassemblage, pour que cela fonctionne. Les types de modules spciaux tels que les modules HTML/CSS sont galement pris en charge.
    4. Dans le processus, dautres transformations et optimisations peuvent tre appliques:
      • Le code inaccessible est supprim.
      • Les exportations non utilises sont supprimes (tree-shaking).
      • Les instructions spcifiques au dveloppement telles que console et le debugger sont supprimes.
      • La syntaxe JavaScript moderne et ultramoderne peut tre transforme en une ancienne version dote de fonctionnalits similaires avec Babel.
      • Le fichier rsultant est minifi (espaces supprims, variables remplaces par des noms plus courts, etc.).

    Si nous utilisons des outils densemble, alors que les scripts sont regroups dans un seul fichier (ou quelques fichiers), les instructions import/export contenues dans ces scripts sont remplaces par des fonctions spciales de regroupeur. Ainsi, le script fourni rsultant ne contient aucune import/export, il ne ncessite pas type="module", et nous pouvons le mettre dans un script standard:

    <!-- En supposant que nous ayons bundle.js d'un outil tel que Webpack -->
    <script src="bundle.js"></script>

    Cela dit, les modules natifs sont galement utilisables. Nous nutilisons donc pas Webpack ici: vous pourrez le configurer plus tard.

    Rsum

    Pour rsumer, les concepts de base sont les suivants:

    1. Un module est un fichier. Pour que import/export fonctionne, les navigateurs ont besoin de <script type="module">. Les modules ont plusieurs diffrences:
      • Diffr par dfaut.
      • Async fonctionne sur les scripts en ligne.
      • Pour charger des scripts externes dune autre origine (domain/protocol/port), des en-ttes CORS sont ncessaires.
      • Les scripts externes en double sont ignors.
    2. Les modules ont leur propre porte globale et leurs fonctionnalits dchange via import/export.
    3. Les modules utilisent toujours use strict.
    4. Le code des modules est excut une seule fois. Les exportations sont cres une fois et partages entre les importateurs

    Lorsque nous utilisons des modules, chaque module implmente la fonctionnalit et lexporte. Nous utilisons ensuite import pour limporter directement l o il le faut. Le navigateur charge et excute les scripts automatiquement.

    En production, les gens utilisent souvent des bundlers tels que Webpack qui regroupe des modules pour des raisons de performances ou pour dautres raisons.

    Dans le chapitre suivant, nous verrons plus dexemples de modules et comment des choses peuvent tre import / export.

    Carte du tutoriel

    Commentaires

    lire ceci avant de commenter
    • Si vous avez des amliorations suggrer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
    • Si vous ne comprenez pas quelque chose dans l'article, merci de prciser.
    • Pour insrer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page