Introduction aux modules JavaScript
Les modules JavaScript vous aident à gérer de grands projets en divisant votre code en parties séparées et réutilisables.
Les modules JavaScript vous aident à gérer de grands projets en divisant votre code en parties séparées et réutilisables. Ce guide explore comment utiliser efficacement les modules JavaScript, en améliorant vos compétences en programmation et l'organisation de vos projets.
Cette page couvre ce qu'est un module, la syntaxe import/export, la différence entre les exports nommés et les exports par défaut, le fonctionnement de la portée des modules, les anciens systèmes de modules que vous rencontrerez encore (CommonJS et AMD), ainsi qu'un exemple complet que vous pouvez exécuter.
Comprendre les modules JavaScript
Un module est simplement un fichier. Chaque fichier dispose de sa propre portée privée : les variables et les fonctions que vous déclarez dans un module ne sont pas visibles en dehors de celui-ci, sauf si vous les exportez explicitement. Pour utiliser quelque chose provenant d'un autre module, vous l'importez. C'est le fondement de toutes les autres notions de cette page.
Les modules apportent également deux comportements automatiques à connaître :
- Le mode strict est toujours actif. Chaque module s'exécute comme s'il commençait par
'use strict', de sorte que les variables globales accidentelles lèvent uneReferenceErrorau lieu de créer silencieusement une variable. thisau niveau supérieur estundefined, et non l'objet global. C'est l'un des moyens les plus simples de savoir si du code s'exécute en tant que module.
Ci-dessous, nous couvrons la syntaxe de base et l'utilisation des modules.
Introduction à la syntaxe des modules
Les modules utilisent les instructions import et export pour partager du code entre les fichiers.
Exemple :
// Exporting functions
export const add = (a, b) => a + b;
export function multiply(a, b) {
return a * b;
}
// Importing them in another file
import { add, multiply } from './mathFunctions.js';L'instruction export vous permet de rendre des parties de votre module disponibles pour d'autres fichiers. L'instruction import vous permet d'utiliser ces parties là où vous en avez besoin.
Utilisez des noms clairs et descriptifs pour vos modules et vos fonctions. Cela rend votre code plus facile à lire et à maintenir.
Exports par défaut vs exports nommés
Vous pouvez utiliser des exports par défaut ou des exports nommés pour partager différentes parties de votre code. Les exports nommés partagent plusieurs fonctionnalités par leur nom, tandis que les exports par défaut partagent une seule fonctionnalité sans spécifier de nom.
Exemple :
// mathFunctions.js
export default function subtract(a, b) {
return a - b;
}
// Using the default export
import subtract from './mathFunctions.js';Le mot-clé default sert à exporter une seule fonction ou variable. Lors de l'importation d'un export par défaut, vous pouvez utiliser n'importe quel nom pour y faire référence.
Les exports nommés conviennent bien aux fonctions utilitaires, et les exports par défaut sont utiles pour la fonctionnalité principale unique d'un fichier, comme un composant React ou une classe.
Un fichier peut mélanger un export par défaut avec un nombre quelconque d'exports nommés. Vous les importez ensemble, le défaut en premier et les exports nommés entre accolades :
// mathFunctions.js
export const add = (a, b) => a + b; // named export
export default function subtract(a, b) { // default export
return a - b;
}
// app.js
import subtract, { add } from './mathFunctions.js';Quelques règles à retenir :
- Un module ne peut avoir qu'un seul export par défaut, mais plusieurs exports nommés.
- Les imports nommés doivent utiliser le nom exporté exact (ou le renommer avec
as:import { add as sum } from './mathFunctions.js'). - Un import par défaut peut utiliser n'importe quel nom de votre choix, car l'export par défaut n'a pas de nom fixe.
Renommage et ré-exportation
Vous pouvez renommer à l'entrée ou à la sortie avec as, et ré-exporter depuis un autre module pour créer un point d'entrée unique (un fichier « barrel ») :
// utils.js
export { add as sum } from './mathFunctions.js';
export { default as subtract } from './mathFunctions.js';
// app.js
import { sum, subtract } from './utils.js';Exploiter les modules pour un code propre
L'utilisation des modules peut rendre votre code plus facile à gérer, surtout lorsque les projets grandissent.
Structure des répertoires
Une bonne organisation des dossiers aide à garder votre code structuré.
Exemple :
/src
/components
/helpers
/models
/services
index.jsGestion des dépendances
Gérer les dépendances signifie s'assurer que vos fichiers de code fonctionnent correctement ensemble.
Exemple :
// Webpack configuration for bundling modules
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{ test: /\.js$/, use: 'babel-loader' }
]
}
};Cette configuration indique à Webpack de démarrer avec index.js, de regrouper ce fichier et toutes ses dépendances dans bundle.js, et de placer ce dernier dans le dossier dist.
Remarque : les fichiers de configuration Webpack utilisent traditionnellement la syntaxe CommonJS (module.exports), même dans les projets fortement axés sur ES6.
Techniques avancées avec les modules
L'utilisation des fonctionnalités avancées des modules peut rendre votre code plus efficace et plus facile à gérer.
Imports dynamiques
Les imports dynamiques vous permettent de charger du code uniquement lorsque c'est nécessaire, ce qui peut accélérer votre application.
Exemple :
// Dynamically importing a module
// Assuming a button element exists
button.onclick = () => {
import('./messageModule.js')
.then(module => {
module.showMessage('Dynamic Import Executed!');
});
};Ce code charge un module uniquement lorsqu'un bouton est cliqué, ce qui peut réduire les temps de chargement initiaux.
Utilisez les imports dynamiques pour les parties de votre application qui ne sont pas immédiatement nécessaires, comme des fonctionnalités supplémentaires accessibles ultérieurement.
import() retourne une promesse, vous pouvez donc l'utiliser avec async/await :
async function loadFeature() {
const module = await import('./messageModule.js');
module.showMessage('Loaded on demand');
}Consultez les imports dynamiques pour une analyse plus approfondie.
Communication entre modules
Les modules doivent être autonomes, mais peuvent communiquer via des ressources partagées.
Exemple :
// stateManager.js
export let state = { count: 0 };
// counter.js
import { state } from './stateManager.js';
state.count++;Ce code montre deux modules partageant un objet d'état. Comme les modules JavaScript sont mis en cache en tant que singletons, les deux fichiers référencent exactement le même objet en mémoire. Lorsqu'un module modifie l'état, l'autre voit la modification.
Remarque : cet exemple mute directement l'objet partagé. Pour des applications en production, envisagez d'utiliser une bibliothèque de gestion d'état ou un pattern réactif pour gérer les mises à jour de manière prévisible.
Comprendre les systèmes de modules et leur utilisation aujourd'hui
Dans le développement web moderne, il est essentiel de comprendre les différents systèmes de modules :
- CommonJS : principalement utilisé dans Node.js pour le code côté serveur.
- AMD (Asynchronous Module Definition) : utilisé pour le chargement asynchrone des modules, adapté aux navigateurs.
- Modules ES6 : la norme dans le développement web moderne, prenant en charge le chargement synchrone et asynchrone.
Exemples pour chaque système de modules
Pour illustrer ces concepts en JavaScript, nous inclurons des extraits pour chaque type de module avec l'exemple ES6 existant.
Exemple CommonJS :
// mathFunctions.js
exports.add = function(a, b) {
return a + b;
};
// app.js
const math = require('./mathFunctions.js');
console.log(math.add(5, 3));Explication pour CommonJS : dans cet exemple, nous utilisons exports pour rendre la fonction add disponible en dehors du fichier. Ensuite, dans un autre fichier, nous utilisons require pour importer la fonction add afin de pouvoir l'utiliser. Ce système est couramment utilisé dans Node.js.
Exemple AMD :
// mathFunctions.js
define([], function() {
return {
add: function(a, b) {
return a + b;
}
};
});
// app.js
require(['mathFunctions'], function(math) {
console.log(math.add(5, 3));
});Explication pour AMD : cet exemple utilise define pour déclarer un module sans dépendances et retourne un objet contenant la fonction add. require est ensuite utilisé pour charger le module de manière asynchrone. Cela est utile pour charger des modules dynamiquement dans le navigateur.
Exemple de modules ES6 :
// mathFunctions.js
export const add = (a, b) => a + b;
// app.js
import { add } from './mathFunctions.js';
console.log(add(5, 3));Explication pour les modules ES6 : ici, nous utilisons export pour rendre la fonction add disponible, et import pour l'utiliser dans un autre fichier. C'est la norme moderne pour la gestion des modules en JavaScript, prise en charge par la plupart des navigateurs.
Activer les modules ES6 dans Node.js
Lorsque vous utilisez des modules ES6 dans Node.js, vous pouvez profiter de la même syntaxe import/export généralement utilisée dans le développement JavaScript côté client. Cela permet une syntaxe de modules cohérente entre les environnements client et serveur.
Pour utiliser la syntaxe des modules ES6 dans Node.js, vous devez vous assurer que votre environnement la prend en charge. À partir de la version 14 de Node.js, les modules ES6 sont stables, et depuis la version 16, ils sont activés par défaut lorsque "type": "module" est défini. Voici comment procéder :
Mettre à jour package.json : dans le fichier package.json de votre projet Node.js, ajoutez la ligne suivante :
"type": "module"Cela indique à Node.js de traiter les fichiers .js comme des modules ES6 par défaut.
Extensions de fichiers : utilisez .js pour vos fichiers de modules, ou utilisez explicitement .mjs si vous préférez. Node.js reconnaît les deux, mais si vous utilisez le paramètre "type": "module", .js sera considéré comme un module ES6.
// mathFunctions.js
export function add(a, b) {
return a + b;
}
// app.js
import { add } from './mathFunctions.js';
console.log(add(5, 3)); // 8Dans Node.js ESM, les imports relatifs nécessitent l'extension de fichier (./mathFunctions.js, et non ./mathFunctions). Cela diffère de CommonJS, où l'extension est facultative.
Pièges courants
Quelques comportements des modules surprennent les débutants. Les connaître à l'avance permet d'économiser du temps de débogage :
- Les chemins relatifs nécessitent une extension dans le navigateur.
import { add } from './math'fonctionne dans de nombreux bundlers, mais échoue avec le ESM natif du navigateur, où vous devez écrire'./math.js'. - Les modules s'exécutent une seule fois et sont mis en cache. Quel que soit le nombre de fichiers qui importent le même module, son code de niveau supérieur ne s'exécute qu'une seule fois et chaque importateur partage la même instance. C'est ce qui a rendu l'exemple d'état partagé ci-dessus possible.
- Les imports sont des liaisons en lecture seule, pas des copies. Vous ne pouvez pas réassigner une valeur importée (
add = 5lève une erreur). Vous avez accès à un lien en direct vers l'export, donc si le module exportateur modifie la valeur, les importateurs voient la nouvelle valeur. import/exportdoivent être au niveau supérieur. Les instructionsimportetexportstatiques ne peuvent pas apparaître dans un blocifou une fonction. Lorsque vous avez besoin d'un chargement conditionnel, utilisez plutôt la fonctionimport()dynamique.- Les scripts de modules sont différés. Un
<script type="module">dans le navigateur ne bloque pas l'analyse ; il s'exécute après l'analyse du HTML, de manière similaire à l'ajout dedefer.
Pour en savoir plus sur le mode strict toujours actif, consultez le mode strict. Pour la référence complète export/import, consultez Export et Import.
Bonnes pratiques pour l'utilisation des modules JavaScript
- Restez simple : utilisez des noms clairs et simples pour vos fichiers et vos exports.
- Soyez cohérent : appliquez les mêmes patterns et structures à travers votre projet pour rendre votre code prévisible.
- Documentez tout : commentez votre code et documentez comment utiliser vos modules.
- Optimisez selon les besoins : révisez et optimisez régulièrement votre code à mesure que votre projet grandit.
Exemple complet
Voici un exemple complet qui intègre tout ce que vous avez appris dans cet article.
Structure du projet :
/src
/math
- mathFunctions.js
- app.js
index.htmlmathFunctions.js :
export const add = (a, b) => a + b;
export default function subtract(a, b) {
return a - b;
}app.js :
import subtract, { add } from './math/mathFunctions.js';
document.getElementById('add').addEventListener('click', function() {
const result = add(5, 3);
document.getElementById('result').textContent = `Adding: ${result}`;
});
document.getElementById('subtract').addEventListener('click', function() {
const result = subtract(5, 3);
document.getElementById('result').textContent = `Subtracting: ${result}`;
});index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript Module Example</title>
</head>
<body>
<button id="add">Add 5 + 3</button>
<button id="subtract">Subtract 5 - 3</button>
<div id="result"></div>
<script type="module" src="src/app.js"></script>
</body>
</html>Remarque : les modules ES nécessitent un serveur de développement local (par exemple npx serve ou Vite) pour s'exécuter dans le navigateur en raison des restrictions CORS. Ouvrir index.html directement via file:// échouera.
Cette configuration utilise une page web simple avec des boutons pour démontrer l'addition et la soustraction de nombres à l'aide de fonctions importées. Les résultats sont affichés directement sur la page.
Explication de l'exemple
- mathFunctions.js : ce fichier contient deux fonctions (
addetsubtract) exportées en tant que modules.addest un export nommé, etsubtractest un export par défaut. - app.js : ce fichier importe les fonctions depuis
mathFunctions.jset les associe à des événements de clic sur des boutons pour effectuer des calculs lorsque l'utilisateur interagit avec la page. - index.html : le fichier HTML configure l'interface utilisateur avec des boutons et une zone d'affichage pour les résultats. Il lie
app.jsen tant que module.
Cet exemple complet démontre comment les modules JavaScript peuvent être structurés et utilisés dans une application réelle.
Conclusion
Les modules JavaScript sont un outil puissant pour organiser et maintenir des applications web à grande échelle. En comprenant et en utilisant différents systèmes de modules de manière appropriée, vous pouvez améliorer la scalabilité et la maintenabilité de votre projet. Mettre régulièrement à jour vos connaissances en matière de syntaxe des modules, des bonnes pratiques et des techniques avancées garantira que vos compétences en développement restent affûtées et que vos projets restent à la pointe.