Un projet qui grandit finit toujours par déborder d'un seul fichier. Le jour où une fonction écrite pour le panier doit servir à la facturation, il faut la partager sans la recopier : c'est le rôle de import.
Il s'écrit en une ligne, mais obéit à des règles qui surprennent : il est lu avant l'exécution du fichier, et le nom qu'il introduit ne peut plus être réaffecté.
Définition
import déclare qu'un fichier a besoin de valeurs mises à disposition par un autre fichier grâce à export. Il crée dans le fichier courant un nom qui pointe vers la valeur d'origine.
// panier.js
export const TVA = 0.2;
export function totalTTC(ht) {
return ht * (1 + TVA);
}
// facture.js
import { totalTTC, TVA } from './panier.js';
console.log(totalTTC(100)); // 120Le chemin entre guillemets désigne le fichier source : commençant par ./ ou ../, il pointe vers un fichier du projet ; sans point, il désigne un paquet installé, comme import React from 'react'.
Les quatre formes à connaître
- Import nommé avec
import { a, b } from './x.js': reprend les noms exportés, entre accolades. - Import par défaut avec
import panier from './x.js': récupère l'export marqué default, et le nom local est libre. - Import complet avec
import * as Panier from './x.js': regroupe tous les exports dans un objet. - Import pour effet de bord avec
import './styles.css': exécute le fichier sans rien en récupérer.
Le renommage s'écrit avec as, utile quand deux fichiers exportent le même nom.
Les accolades ne sont pas décoratives. import { panier } réclame un export nommé panier, alors que import panier réclame l'export par défaut. Confondre les deux produit un undefined inexpliqué.
Trois règles qui expliquent la plupart des pannes
Les imports sont remontés en haut du fichier. Le moteur les traite avant d'exécuter la moindre ligne, donc une fonction importée marche même si elle est appelée au-dessus de sa propre ligne import. Les grouper en tête reste une convention de lisibilité.
Un import ne se met pas dans un if ni dans une function. Il vit au niveau supérieur du fichier. Pour charger un module au moment voulu, il existe la forme import(), qui est un appel de fonction, renvoie une Promise et se consomme avec await.
Le nom importé est en lecture seule. Il se comporte comme une const : lui affecter une nouvelle valeur échoue. Il reste en revanche branché sur la variable d'origine, donc si le fichier exportateur la modifie, la valeur lue change aussi.
Questions fréquentes
Faut-il écrire l'extension du fichier ?
Dans un navigateur et dans Node, oui : le chemin est une adresse réelle, donc ./panier.js et non ./panier. Vite ou Webpack tolèrent l'omission parce qu'ils devinent l'extension : le code marche avec eux, et casse s'il est servi tel quel au navigateur.
Pourquoi mon import vaut-il undefined ?
Trois causes couvrent presque tous les cas : le nom entre accolades n'est pas exporté sous ce nom exact, la casse diffère, ou le fichier ne propose qu'un export par défaut alors que vous réclamez un export nommé. Placez la ligne import et la ligne export côte à côte : la différence saute aux yeux.
Quelle différence avec require ?
require appartient à l'ancien système de modules de Node, chargé au moment où la ligne s'exécute, alors que import est le système officiel du langage, analysé avant l'exécution. Les deux coexistent dans beaucoup de projets, et savoir lequel s'applique dépend du fichier package.json. Notre formation Node.js détaille ce partage, une des confusions les plus fréquentes côté serveur.