Différence entre un module JavaScript et un module Angular

Le terme “module” ne désigne pas la même chose selon qu’il s’applique au langage JavaScript ou au framework Angular. Quelle est la différence exactement ?

Comparaison module JavaScript et module Angular

Module JavaScript (ES6)Module Angular (NgModule)
Vient deLangage JavaScript ES6 / TypeScriptFramework Angular
Utilisable où ?Dans n'importe quelle appli ES6/TypeScriptDans une appli Angular uniquement
DéfinitionFichier dont le code a un scope privéClasse décorée avec @NgModule
UtilitéÉviter le scope global
Rendre les dépendances de code explicites
Encapsuler les fonctionnalités
Organiser le code de l'appli
Syntaxe d'exportexport const a = 'foo';
@NgModule({
  exports: [ NavbarComponent ]
})
Syntaxe d'importimport { a } from './fichier-a';
@NgModule({
  imports: [ SharedModule ]
})

Qu’est-ce qu’un module JavaScript (ES6) ?

Un module JavaScript est une fonctionnalité du langage JavaScript, disponible à partir de ES6 et également dans Typescript. Il désigne un fichier dont le code a un scope privé.

Les symboles déclarés dans un module ne sont pas accessibles depuis les autres modules, à moins de les exporter explicitement en les précédant du mot-clé export. Par ailleurs, les modules qui souhaitent accéder aux symboles exportés doivent les importer avec le mot-clé import.

Ici, le module fichier-a.ts exporte la variable firstName, mais pas la variable lastName :

// fichier-a.ts
export const firstName = 'James';  // Accessible depuis les autres modules, car exportée
const lastName = 'Bond';           // Pas accessible depuis les autres modules

Cet autre module (fichier-b.ts) importe la variable firstName et peut ensuite l’utiliser :

// fichier-b.ts
import { firstName } from './fichier-a';

console.log(firstName);

Notez que la variable lastName n’est pas importable, car pas exportée de son module d’origine :

// fichier-b.ts
import { lastName } from './fichier-a';  // ERREUR

Fini le scope GLOBAL (JavaScript ES5)

En JavaScript ES5, il est fréquent qu’on charge plusieurs fichiers .js via une série de balises <script>, et les symboles déclarés dans ces fichiers se retrouvent dans le scope global. Ainsi, un fichier peut facilement accéder aux symboles déclarés dans un autre fichier, pourvu qu’il soit chargé après.

La plupart des librairies JavaScript utilisent le scope global. Prenons l’exemple de jQuery et d’un fichier de code qui utilise cette librairie.

On pourrait charger nos deux fichiers dans une page web de la manière suivante :

<script src="jquery.js"></script>     <!-- Librairie jQuery -->
<script src="my-script.js"></script>  <!-- Mon code -->

jQuery déclare le symbole $ dans le scope global, et comme le fichier my-script.js est chargé après, il peut utiliser le $ :

// my-script.js
$(document).ready(function() {
  console.log("ready!");
});

Cette solution n’est pas très robuste : le code planterait si on inversait l’ordre de chargement des fichiers ; la dépendance de notre fichier à la librairie jQuery n’est pas explicite…

Qu’est-ce qu’un module Angular (NgModule) ?

Un module Angular est une fonctionnalité du framework Angular. Il désigne une classe décorée avec @NgModule. On utilise d’ailleurs parfois le terme de “ngmodules” pour désigner un module Angular et éviter la confusion avec un module JavaScript.

Un module Angular est un registre qui référence les différentes briques de code de l’application (composants, directives, pipes, services…). Une application Angular est souvent découpée en plusieurs NgModules, chacun centré sur une fonctionnalité précise. Un NgModule peut accéder aux fonctionnalités d’un autre en l’important via la propriété @NgModule.imports. Un NgModule peut exposer certains de ses composants/directives/pipes aux autres en les exportant via la propriété @NgModule.exports.

Ici, le NgModule SharedModule exporte un composant réutilisable NavbarComponent :

@NgModule({
  declarations: [ NavbarComponent ],
  exports: [ NavbarComponent ]
}
export class SharedModule {}

Le NgModule AppModule importe le SharedModule et peut ensuite utiliser son composant exporté NavbarComponent :

@NgModule({
  imports: [ BrowserModule, SharedModule ],
  ...
}
export class AppModule {}

 

Cette recette vous a plus ? Rejoignez-nous à Paris pour une formation Angular de 3 jours dans laquelle vous coderez une application professionnelle que vous déploierez en production.

Le jour où j'ai enfin compris Angular