Rattraper les dix dernières années de JavaScript : d’ES2015 à l’ère de l’IA, qu’est-ce qui a vraiment changé ?

Écouter cet article

Onze éditions d’ECMAScript, quelques révolutions, beaucoup de petites réparations et suffisamment de nouveaux outils pour éviter d’installer un paquet npm simplement afin de retourner un tableau.

Si vous avez appris JavaScript à l’époque où var, les fonctions anonymes et les concaténations de chaînes régnaient sans partage, le langage actuel peut donner l’impression d’avoir été remplacé pendant votre pause-café. Bonne nouvelle : JavaScript est toujours JavaScript. Il convertit encore des types avec l’enthousiasme d’un stagiaire qui veut aider, this continue de punir les personnes trop confiantes et [] + [] produit toujours une chaîne vide — parce qu’il faut bien préserver quelques traditions familiales.

Mais le langage de 2026 n’est plus celui de 2015. Il est plus structuré, plus lisible, mieux équipé pour l’asynchronisme, les modules, les collections, l’immuabilité et le traitement de données. Surtout, l’écosystème a changé autour de lui : navigateurs modernes, Node.js, TypeScript, outils de compilation, tests, frameworks, runtimes alternatifs et assistants d’intelligence artificielle.

Le piège consiste à tout mélanger. Une nouvelle méthode de tableau n’est pas un nouveau framework. fetch() n’est pas défini par ECMAScript. TypeScript n’est pas JavaScript avec un abonnement premium. Et une IA capable de générer cinquante fichiers en trente secondes n’a pas rendu ces cinquante fichiers corrects.

Faisons donc le tri.

JavaScript, ECMAScript, TC39 : qui fait quoi dans cette réunion ?

JavaScript est le nom couramment utilisé pour le langage. ECMAScript est sa spécification standardisée, c’est-à-dire le document qui décrit précisément sa syntaxe et son comportement. Le TC39 est le comité technique qui fait évoluer cette spécification.

En juin 2015, ECMAScript 2015, également appelé ES6, est devenu la sixième édition de la norme ECMA-262. Depuis, une édition est publiée chaque année. Au 26 août 2026, la version officiellement publiée est ECMAScript 2026, dix-septième édition de la norme.

ES6 = ECMAScript 2015 = 6e édition
ES2025 = ECMAScript 2025 = 16e édition
ES2026 = ECMAScript 2026 = 17e édition

La spécification officielle confirme l’édition 2026 et conserve les archives des éditions précédentes : ECMA-262 — Ecma International.

Depuis ES2015, le langage n’attend plus plusieurs années avant de livrer une énorme cargaison de nouveautés. Les propositions passent par plusieurs étapes au TC39. Lorsqu’elles atteignent le stade 4, elles sont considérées comme terminées et destinées à intégrer la spécification. Le registre officiel est disponible dans la liste des propositions terminées du TC39.

Cette cadence annuelle a produit un effet curieux : les numéros changent tous les ans, mais toutes les éditions ne bouleversent pas votre façon de programmer. ES2015 a déplacé les murs porteurs. Certaines éditions suivantes ont surtout installé de meilleures poignées de porte. Les poignées sont utiles, mais personne n’organise une pendaison de crémaillère pour String.prototype.trimStart().

2015 : l’année où JavaScript a décidé de devenir fréquentable

ES2015 est la grande rupture. La spécification elle-même présente les modules, les classes, la portée lexicale par bloc, les itérateurs, les générateurs, les promesses et la déstructuration parmi ses évolutions majeures. Son ambition était claire : mieux prendre en charge les grandes applications et la création de bibliothèques. La spécification ES2015 reste la source de référence.

let et const remplacent progressivement var

var possède une portée de fonction et accepte plusieurs comportements historiques surprenants. let et const ont une portée de bloc, c’est-à-dire qu’ils n’existent que dans la zone délimitée par les accolades où ils sont déclarés.

if (true) {
  // Cette variable reste dans le bloc.
  let message = 'Bonjour';

  // Cette référence ne pourra pas être réaffectée.
  const langage = 'JavaScript';
}

// ReferenceError : message n'existe pas ici.
// console.log(message);

La règle moderne est simple : utilisez const par défaut, puis let lorsque la variable doit recevoir une nouvelle valeur. Gardez var pour la maintenance de code ancien et les soirées consacrées à raconter des histoires qui commencent par « à l’époque, Internet Explorer… ».

Attention : const interdit la réaffectation de la variable, pas la modification interne de l’objet.

const utilisateur = {
  nom: 'Alice'
};

// Autorisé : l'objet reste le même, sa propriété change.
utilisateur.nom = 'Bob';

// Interdit : la variable ne peut pas viser un autre objet.
// utilisateur = {};

Les fonctions fléchées raccourcissent la syntaxe — et changent this

// Ancienne écriture.
const multiplierAvant = function (a, b) {
  return a * b;
};

// Fonction fléchée avec retour implicite.
const multiplier = (a, b) => a * b;

Le gain n’est pas uniquement esthétique. Une fonction fléchée n’a pas son propre this : elle récupère celui du contexte où elle a été créée. On parle de this lexical.

class Chronometre {
  secondes = 0;

  demarrer() {
    setInterval(() => {
      // La flèche conserve le `this` de demarrer().
      this.secondes += 1;
    }, 1000);
  }
}

Une fonction fléchée n’est toutefois pas un remplacement universel. Elle ne peut pas servir de constructeur avec new et convient mal comme méthode lorsqu’on veut que this soit fourni au moment de l’appel. Oui, même la syntaxe courte a une notice. Non, personne ne la lit avant le premier bug.

Les chaînes de gabarit mettent fin à la plomberie de +

Les template literals, ou chaînes de gabarit, utilisent des accents graves et permettent l’interpolation avec ${...}.

const nom = 'Alice';
const age = 32;

// Avant : une petite clôture de signes +.
const ancienTexte = 'Je m’appelle ' + nom + ' et j’ai ' + age + ' ans.';

// Après : la phrase ressemble enfin à une phrase.
const texte = `Je m’appelle ${nom} et j’ai ${age} ans.`;

Elles acceptent aussi plusieurs lignes et peuvent être utilisées avec des fonctions de balisage, qui reçoivent séparément les fragments de texte et les valeurs interpolées.

Déstructuration, paramètres par défaut, rest et spread

La déstructuration extrait des valeurs d’un objet ou d’un tableau. Le paramètre rest rassemble plusieurs valeurs. L’opérateur spread déploie les valeurs d’un itérable, par exemple un tableau.

const profil = {
  nom: 'Alice',
  role: 'développeuse'
};

// Déstructuration et valeur par défaut.
const { nom, role, actif = true } = profil;

// Rest : les arguments deviennent un tableau.
function additionner(...nombres) {
  return nombres.reduce((total, nombre) => total + nombre, 0);
}

// Spread : les éléments sont déployés dans un nouveau tableau.
const nombres = [1, 2, 3];
const copieEtSuite = [...nombres, 4, 5];

En ES2015, le spread concernait les appels de fonctions et les éléments de tableaux. La forme { ...objet }, aujourd’hui omniprésente, a été standardisée en ES2018. Internet l’a depuis utilisée avec tant d’ardeur qu’on pourrait croire qu’un objet ne peut plus être créé sans être cloné trois fois.

Les objets deviennent moins répétitifs

const nom = 'Alice';
const role = 'développeuse';
const cle = 'actif';

const utilisateur = {
  // Propriétés raccourcies.
  nom,
  role,

  // Nom de propriété calculé.
  [cle]: true,

  // Méthode raccourcie.
  saluer() {
    return `Bonjour, je suis ${this.nom}`;
  }
};

Les classes arrivent, mais les prototypes ne partent pas

class Personne {
  constructor(nom) {
    this.nom = nom;
  }

  sePresenter() {
    return `Je m’appelle ${this.nom}`;
  }
}

class Developpeur extends Personne {
  constructor(nom, langage) {
    super(nom);
    this.langage = langage;
  }
}

Les classes offrent une syntaxe plus lisible pour construire des objets et organiser l’héritage. Elles reposent toujours sur le système de prototypes, le mécanisme par lequel les objets JavaScript héritent d’autres objets. ES2015 n’a donc pas transformé JavaScript en Java. Il lui a simplement prêté une veste qui ressemble à celle de Java, ce qui a suffi pour déclencher dix ans de débats parfaitement sereins sur l’architecture logicielle.

Les modules donnent enfin une structure native aux applications

// calculs.js
export function additionner(a, b) {
  return a + b;
}

export const PI = 3.14159;

// application.js
import { additionner, PI } from './calculs.js';

console.log(additionner(10, 20));
console.log(PI);

Les modules ECMAScript, souvent abrégés ESM, définissent nativement import et export. Ils permettent l’analyse statique des dépendances : un outil peut déterminer les imports avant l’exécution du programme. Les modules appliquent automatiquement le mode strict.

Dans un navigateur :

<!-- Le navigateur charge application.js comme module ECMAScript. -->
<script type="module" src="application.js"></script>

Les modules ont progressivement offert un langage commun aux navigateurs, aux outils de compilation et aux environnements serveur. Le voyage a été moins direct qu’un import ne le laisse penser, notamment à cause de l’héritage de CommonJS dans Node.js. Mais en 2026, écrire du code neuf en modules ESM est devenu un choix normal, pas une expérience sociale.

Les promesses civilisent l’asynchronisme

Une promesse représente le résultat futur d’une opération. Elle peut être en attente, réussie ou échouée.

function chargerProfil() {
  return fetch('/api/profil')
    .then((reponse) => {
      if (!reponse.ok) {
        throw new Error(`HTTP ${reponse.status}`);
      }

      return reponse.json();
    });
}

chargerProfil()
  .then((profil) => console.log(profil))
  .catch((erreur) => console.error(erreur));

Les promesses ont fourni une base standard au code asynchrone. Elles ont surtout préparé le terrain pour async et await, arrivés deux ans plus tard. Avant cela, les rappels imbriqués formaient parfois une pyramide assez ambitieuse pour obtenir un permis de construire.

Itérateurs, générateurs, for...of, Map, Set, Symbol, Proxy et Reflect

ES2015 ajoute aussi les mécanismes qui permettront de mieux parcourir, produire et contrôler des données.

// Set stocke des valeurs sans doublons.
const etiquettes = new Set(['js', 'web', 'js']);

// Map associe des clés à des valeurs.
const scores = new Map([
  ['Alice', 18],
  ['Bob', 15]
]);

// for...of parcourt les valeurs d'un itérable.
for (const etiquette of etiquettes) {
  console.log(etiquette);
}

// Un générateur produit des valeurs à la demande.
function* compteur() {
  yield 1;
  yield 2;
  yield 3;
}

Un itérable est une valeur que JavaScript sait parcourir selon un protocole standard. Un générateur est une fonction qui peut se mettre en pause avec yield, puis reprendre. Symbol fournit des valeurs uniques et sert notamment à définir des protocoles internes comme Symbol.iterator. Proxy intercepte des opérations sur un objet ; Reflect regroupe des opérations standard sur les objets.

Vous n’utiliserez probablement pas Proxy chaque mardi. C’est plutôt rassurant : on n’utilise pas non plus un chalumeau pour tartiner du beurre, même s’il est techniquement disponible.

De 2016 à 2019 : consolider le chantier

Après l’explosion d’ES2015, les éditions suivantes deviennent plus petites et plus régulières.

ÉditionAjouts à retenirCe que cela change réellement
ES2016Array.prototype.includes(), opérateur **Des tests d’appartenance plus lisibles et une puissance mathématique sans détour par Math.pow()
ES2017async/await, Object.values(), Object.entries(), padStart(), padEnd(), mémoire partagée et AtomicsL’asynchronisme devient lisible comme du code séquentiel
ES2018itération asynchrone, Promise.prototype.finally(), rest/spread pour objets, fortes améliorations des expressions régulièresLe traitement de flux asynchrones et la copie d’objets deviennent plus naturels
ES2019flat(), flatMap(), Object.fromEntries(), trimStart(), trimEnd(), paramètre de catch optionnelMoins de petites fonctions utilitaires écrites à la main

La vedette de cette période est évidemment async/await.

async function chargerProfil() {
  const reponse = await fetch('/api/profil');

  if (!reponse.ok) {
    throw new Error(`HTTP ${reponse.status}`);
  }

  return reponse.json();
}

try {
  const profil = await chargerProfil();
  console.log(profil);
} catch (erreur) {
  console.error(erreur);
}

Une fonction async renvoie toujours une promesse. await suspend cette fonction jusqu’au règlement de la promesse, sans bloquer tout le programme. Le code paraît séquentiel, mais l’opération reste asynchrone. C’est plus lisible ; ce n’est pas magique. Si vous lancez trois appels indépendants l’un après l’autre avec trois await, ils seront toujours lents l’un après l’autre, mais avec une syntaxe très élégante.

// Les trois opérations indépendantes démarrent ensemble.
const [profil, messages, alertes] = await Promise.all([
  chargerProfil(),
  chargerMessages(),
  chargerAlertes()
]);

ES2018 ajoute aussi l’itération asynchrone :

// Chaque élément peut arriver plus tard.
for await (const evenement of fluxEvenements) {
  console.log(evenement);
}

Et ES2019 complète les transformations de collections :

const groupes = [[1, 2], [3, 4]];

// Aplatit un niveau de tableaux imbriqués.
const valeurs = groupes.flat();

const entrees = [
  ['nom', 'Alice'],
  ['actif', true]
];

// Réalise l'opération inverse d'Object.entries().
const profil = Object.fromEntries(entrees);

2020 : l’année où JavaScript supprime plusieurs irritants quotidiens

ES2020 rassemble des ajouts qui ont rapidement modifié le style du code moderne : le chaînage optionnel ?., la coalescence des valeurs nulles ??, BigInt, Promise.allSettled(), globalThis, les imports dynamiques et String.prototype.matchAll().

?. : arrêter d’escalader un objet avec un casque

// Renvoie undefined si profil ou adresse est null ou undefined.
const ville = profil?.adresse?.ville;

// Appelle la méthode seulement si elle existe.
plugin.initialiser?.();

Avant, il fallait enchaîner des tests ou confier la mission à une bibliothèque. ?. s’arrête uniquement devant null ou undefined, pas devant toutes les valeurs considérées comme fausses.

?? : respecter enfin 0, false et la chaîne vide

const configuration = {
  volume: 0,
  notifications: false
};

// Conserve 0, car il ne s'agit ni de null ni de undefined.
const volume = configuration.volume ?? 50;

// Conserve false pour la même raison.
const notifications = configuration.notifications ?? true;

Avec ||, les valeurs 0, false et '' auraient été remplacées. L’opérateur ?? ne choisit la valeur de secours que pour null ou undefined. Une différence minuscule, jusqu’au jour où votre application remet le volume à 50 après que l’utilisateur a clairement demandé le silence.

BigInt, les promesses regroupées et les imports à la demande

// Le suffixe n crée un entier de précision arbitraire.
const tresGrandEntier = 9_007_199_254_740_993n;

// Attend toutes les promesses sans s'arrêter au premier échec.
const resultats = await Promise.allSettled([
  chargerProfil(),
  chargerMessages()
]);

// Charge un module uniquement lorsque nécessaire.
const moduleGraphique = await import('./graphique.js');
moduleGraphique.afficher();

BigInt représente des entiers au-delà de la plage exacte du type Number. Il ne faut pas mélanger directement BigInt et Number dans les calculs. JavaScript refuse, probablement parce qu’il connaît déjà la réputation de ses conversions implicites.

2021 et 2022 : moins de cérémonial, de vraies données privées

ES2021 apporte notamment replaceAll(), Promise.any(), les séparateurs numériques, les opérateurs d’affectation logique et les références faibles.

// Le séparateur améliore la lecture sans changer la valeur.
const budget = 1_000_000;

// Remplace toutes les occurrences littérales.
const slug = 'java script moderne'.replaceAll(' ', '-');

// Affecte seulement si cache vaut null ou undefined.
cache ??= creerCache();

Promise.any() renvoie le premier résultat réussi et échoue seulement si toutes les promesses échouent. Les WeakRef et FinalizationRegistry concernent des usages avancés liés au ramasse-miettes, le mécanisme qui libère automatiquement la mémoire. Si vous n’avez pas un besoin précis, ne les utilisez pas « pour optimiser ». L’optimisation sans mesure est souvent une manière coûteuse de déplacer un problème imaginaire.

ES2022 modernise fortement les classes : champs publics, champs privés avec #, méthodes privées, champs statiques et blocs statiques. Il ajoute aussi await au niveau supérieur des modules, .at(), Object.hasOwn(), la cause des erreurs et les indices de correspondance des expressions régulières.

class Compte {
  // Champ public.
  devise = 'EUR';

  // Champ réellement privé au niveau du langage.
  #solde = 0;

  deposer(montant) {
    this.#solde += montant;
  }

  consulter() {
    return this.#solde;
  }
}

const valeurs = ['a', 'b', 'c'];

// Accès au dernier élément sans valeurs[valeurs.length - 1].
console.log(valeurs.at(-1));

Le mot « privé » n’est plus une convention reposant sur un _nomDePropriete et la politesse des collègues. Le moteur interdit réellement l’accès externe au champ #solde.

2023 et 2024 : copier sans muter, regrouper sans bricoler

ES2023 introduit findLast() et findLastIndex(), ainsi que quatre méthodes de tableau qui renvoient une copie au lieu de modifier le tableau original : toReversed(), toSorted(), toSpliced() et with().

const nombres = [3, 1, 2];

// sort() modifierait nombres ; toSorted() renvoie une copie triée.
const tries = nombres.toSorted((a, b) => a - b);

// Remplace l'élément d'index 1 dans une nouvelle copie.
const corriges = nombres.with(1, 10);

console.log(nombres);  // [3, 1, 2]
console.log(tries);    // [1, 2, 3]
console.log(corriges); // [3, 10, 2]

Ces méthodes facilitent une programmation immuable, c’est-à-dire un style où l’on crée une nouvelle valeur plutôt que de modifier l’ancienne. Ce principe est utile pour raisonner sur les états d’interface et les traitements de données. Il ne transforme pas chaque copie en vertu morale ; copier des structures gigantesques sans réfléchir reste une excellente façon de chauffer une pièce.

ES2024 ajoute notamment Object.groupBy(), Map.groupBy(), Promise.withResolvers(), les chaînes Unicode bien formées, des ArrayBuffer redimensionnables ou transférables, Atomics.waitAsync() et le drapeau v des expressions régulières.

const produits = [
  { nom: 'Clavier', categorie: 'matériel' },
  { nom: 'Éditeur', categorie: 'logiciel' },
  { nom: 'Souris', categorie: 'matériel' }
];

// Regroupe les objets selon la valeur renvoyée.
const parCategorie = Object.groupBy(
  produits,
  (produit) => produit.categorie
);

Promise.withResolvers() évite une petite cérémonie lors de la création d’une promesse dont les fonctions de résolution doivent être conservées à l’extérieur.

const { promise, resolve, reject } = Promise.withResolvers();

// Ces fonctions peuvent être transmises à un autre composant.
connecterSourceExterne({ resolve, reject });

const resultat = await promise;

2025 : les collections et les itérateurs passent enfin à l’âge adulte

ES2025 ajoute plusieurs outils qui évitent des boucles et des dépendances utilitaires : méthodes d’ensembles, aides pour les itérateurs, attributs d’import, modules JSON, modificateurs d’expressions régulières, groupes de capture nommés dupliqués dans certaines branches, RegExp.escape(), Promise.try() et la prise en charge des nombres flottants 16 bits dans les tableaux typés.

Les nouvelles méthodes de Set rendent directement disponibles les opérations classiques sur les ensembles.

const equipeFrontend = new Set(['Alice', 'Bob']);
const equipeBackend = new Set(['Bob', 'Chloé']);

// Union : tous les membres sans doublons.
const toutLeMonde = equipeFrontend.union(equipeBackend);

// Intersection : les membres présents dans les deux ensembles.
const polyvalents = equipeFrontend.intersection(equipeBackend);

// Différence : les membres uniquement dans la première équipe.
const uniquementFrontend = equipeFrontend.difference(equipeBackend);

Les aides d’itérateurs permettent d’enchaîner des opérations de façon paresseuse. « Paresseuse » signifie que les valeurs sont calculées lorsqu’elles sont demandées, pas toutes à l’avance.

const resultat = Iterator
  .from([1, 2, 3, 4, 5, 6])
  .filter((nombre) => nombre % 2 === 0)
  .map((nombre) => nombre * 10)
  .take(2)
  .toArray();

console.log(resultat); // [20, 40]

Les attributs d’import précisent la nature d’une ressource importée.

// La syntaxe signale explicitement un module JSON.
import configuration from './configuration.json' with { type: 'json' };

La présence d’une fonctionnalité dans la norme ne garantit pas qu’elle soit immédiatement disponible dans tous vos environnements cibles. Il faut vérifier les versions des navigateurs et runtimes réellement pris en charge. « Ça marche sur ma machine » n’est pas une matrice de compatibilité, même lorsque la machine possède beaucoup de mémoire vive et des autocollants rassurants.

2026 : des outils précis plutôt qu’une nouvelle révolution

ECMAScript 2026, dix-septième édition publiée en juin 2026, poursuit la stratégie des améliorations ciblées. Parmi les ajouts figurent l’insertion conditionnelle dans Map et WeakMap, l’accès au texte source lors de JSON.parse(), Iterator.concat(), les conversions Base64 et hexadécimales de Uint8Array, Math.sumPrecise(), Error.isError() et Array.fromAsync().

Map.getOrInsert() : le cache sans danse rituelle

const utilisateurs = new Map();

// Renvoie la valeur existante ou insère la valeur par défaut.
const profil = utilisateurs.getOrInsert('alice', {
  nom: 'Alice',
  connexions: 0
});

// Calcule la valeur uniquement lorsqu'elle est absente.
const preferences = utilisateurs.getOrInsertComputed(
  'preferences:alice',
  () => chargerPreferencesParDefaut()
);

Les variantes existent également sur WeakMap. Le mécanisme est souvent appelé upsert, contraction de update et insert, même si les noms standardisés utilisent getOrInsert.

Array.fromAsync() et Iterator.concat()

// Transforme un itérable asynchrone en tableau.
const evenements = await Array.fromAsync(fluxEvenements());

// Concatène plusieurs itérables sans construire d'abord un grand tableau.
const nombres = Iterator
  .concat([1, 2], new Set([3, 4]))
  .toArray();

Array.fromAsync() est l’équivalent asynchrone de Array.from(). Iterator.concat() produit un itérateur parcourant successivement plusieurs itérables.

Base64 et hexadécimal directement sur Uint8Array

// Convertit une chaîne Base64 en octets.
const octets = Uint8Array.fromBase64('SGVsbG8=');

// Reconvertit les octets en représentations textuelles.
const base64 = octets.toBase64();
const hexadecimal = octets.toHex();

Un Uint8Array est un tableau typé contenant des entiers non signés sur 8 bits, donc des octets. Ces méthodes évitent des détours historiques par des API conçues autour de chaînes binaires.

Des additions plus fiables et des erreurs mieux reconnues

// Additionne un itérable avec une meilleure précision numérique.
const total = Math.sumPrecise([0.1, 0.2, 0.3]);

// Reconnaît un véritable objet Error, y compris entre différents contextes.
if (Error.isError(erreur)) {
  console.error(erreur.message);
}

Math.sumPrecise() réduit les erreurs accumulées lors de l’addition de nombres flottants. Il ne transforme toutefois pas les nombres binaires en monnaie exacte. Pour des calculs financiers, une représentation adaptée — par exemple des montants en unités entières — reste nécessaire.

JSON.parse() conserve le texte d’origine lorsque c’est nécessaire

const json = '{"identifiant":9007199254740993}';

const donnees = JSON.parse(json, (cle, valeur, contexte) => {
  if (cle === 'identifiant') {
    // Le texte source évite de réutiliser un Number déjà arrondi.
    return BigInt(contexte.source);
  }

  return valeur;
});

Le troisième argument du reviver — la fonction qui transforme les valeurs pendant l’analyse du JSON — peut exposer le texte source d’une valeur primitive non modifiée. C’est utile lorsque la conversion automatique en Number aurait perdu de la précision.

Le détail essentiel n’est pas de mémoriser chaque méthode d’ES2026. Il est de comprendre la direction : le langage intègre progressivement des opérations courantes qui exigeaient auparavant du code auxiliaire, une bibliothèque ou un arrangement artisanal vaguement documenté dans un commentaire daté de 2018.

Ce qui a vraiment changé dans la manière d’écrire du JavaScript

La chronologie annuelle est utile pour les quiz. Pour travailler, cinq transformations comptent davantage.

1. Le code est structuré en modules

Les dépendances ne reposent plus nécessairement sur des variables globales, l’ordre mystérieux de dix balises <script> ou un chargeur propre à chaque projet. import et export ont créé une base commune au navigateur, au serveur et aux outils.

Conséquence pratique : on raisonne davantage en interfaces de modules, en dépendances explicites et en chargement à la demande.

2. L’asynchronisme possède un vocabulaire cohérent

Promesses, fonctions async, await, itérateurs asynchrones et méthodes de combinaison forment désormais un ensemble. Le problème n’a pas disparu : concurrence, annulation, délais, erreurs partielles et ordre d’exécution demandent toujours de la réflexion. La syntaxe permet simplement de réfléchir au problème au lieu de compter les parenthèses fermantes.

3. Le langage favorise les transformations déclaratives

Déstructuration, spread, map(), filter(), flatMap(), Object.fromEntries(), groupBy(), méthodes de Set, aides d’itérateurs et méthodes de copie permettent de décrire davantage ce que l’on veut obtenir.

Cela ne signifie pas qu’une chaîne de quatorze méthodes est automatiquement lisible. À partir d’un certain point, le code cesse d’être déclaratif et devient un rébus avec coloration syntaxique.

4. Les valeurs absentes sont mieux traitées

Le couple ?. et ??, Object.hasOwn(), les causes d’erreurs et les résultats détaillés des promesses réduisent plusieurs ambiguïtés historiques. Le langage distingue mieux « absent », « faux », « vide » et « en échec ».

5. L’immuabilité est plus simple, mais pas obligatoire

Les méthodes toSorted(), toReversed(), toSpliced() et with() évitent de modifier accidentellement les tableaux. Le spread facilite les copies superficielles.

Le mot superficiel est crucial :

const original = {
  profil: {
    nom: 'Alice'
  }
};

// Le premier niveau est copié, mais profil reste partagé.
const copie = { ...original };

copie.profil.nom = 'Bob';

console.log(original.profil.nom); // "Bob"

Le spread ne réalise pas une copie profonde. Il ne lit pas vos intentions et n’a jamais promis de sauver votre état Redux à votre place.

Ce qui n’est pas JavaScript, même si tout le monde l’appelle JavaScript

Une partie du sentiment d’accélération vient de technologies situées autour du langage.

ÉlémentCe que c’est réellement
DOMAPI du navigateur pour manipuler les documents HTML
fetch()API fournie par l’environnement d’exécution, pas par ECMA-262
Boucle d’événementsMécanisme défini par l’environnement hôte, notamment la plateforme Web
Node.js, Deno, BunEnvironnements capables d’exécuter JavaScript hors du navigateur
TypeScriptLangage ajoutant notamment des types statiques, puis transformé en JavaScript
React, Vue, Angular, SvelteOutils ou frameworks d’interface, pas des éditions d’ECMAScript
npmRegistre et écosystème de paquets
Babel, esbuild, SWC, ViteOutils de transformation, compilation ou construction
WebAssemblyFormat d’instructions distinct, conçu pour cohabiter avec JavaScript sur le Web

Cette distinction est plus qu’une querelle de vocabulaire. Elle aide à chercher la bonne documentation et à diagnostiquer les problèmes. Si fetch() se comporte différemment entre deux runtimes, ouvrir ECMA-262 avec détermination ne résoudra rien. Ce sera très professionnel, simplement inutile.

Le standard HTML du WHATWG décrit notamment le modèle de traitement et la boucle d’événements de la plateforme Web : HTML — Web application APIs. ECMAScript décrit le langage lui-même.

L’écosystème : la seconde révolution, moins proprement numérotée

Entre 2015 et 2026, le changement le plus visible ne vient pas toujours de la norme.

TypeScript a déplacé la détection de nombreuses erreurs

Le typage statique analyse le code avant son exécution afin de vérifier la cohérence des valeurs et des interfaces. TypeScript n’empêche ni les mauvaises exigences, ni les erreurs métier, ni les développeurs de forcer un type avec une assurance spectaculaire. Il rend toutefois explicites de nombreux contrats qui vivaient autrefois dans des commentaires, des tests ou la mémoire d’une personne actuellement en congé.

Les outils de construction sont devenus plus rapides et plus intégrés

Compilation, rechargement à chaud, découpage du code, tests, formatage et analyse statique sont désormais attendus dans de nombreux projets. Le bundling consiste à regrouper et optimiser les modules pour la livraison. La transpilation transforme une syntaxe récente en syntaxe compatible avec des environnements plus anciens.

Ces outils restent des moyens, pas une architecture. Un démarrage en 40 millisecondes ne compense pas un modèle de données incohérent ; il permet seulement de découvrir l’incohérence plus rapidement.

Le navigateur moderne exécute davantage de JavaScript récent directement

La nécessité de transformer chaque nouveauté a diminué pour les projets ciblant des environnements récents. Mais le choix dépend toujours du public, des navigateurs, des versions de runtime et des contraintes du produit. La bonne question n’est pas « est-ce que JavaScript supporte cette syntaxe ? », mais « est-ce que tous mes environnements cibles la supportent, et quelle stratégie de repli ai-je choisie ? ».

Le serveur et le client partagent plus facilement des conventions

Les modules ESM, les API Web adoptées par plusieurs runtimes et les outils communs réduisent certaines différences entre navigateur et serveur. Elles ne les effacent pas. Un système de fichiers, le DOM et les politiques de sécurité du navigateur ne deviennent pas interchangeables parce que les deux côtés comprennent async.

Puis l’IA est arrivée : le langage n’a pas changé, le goulot d’étranglement oui

Les assistants fondés sur des modèles de langage — des systèmes entraînés à produire du texte et du code à partir d’instructions — ont changé le coût de génération du logiciel. Ils peuvent produire rapidement une fonction, un test, une migration, une documentation, un exemple d’API ou une première version de composant.

Avant, le temps était souvent dépensé à écrire le premier jet. Avec l’IA, il se déplace vers la formulation du besoin, la vérification, l’intégration et la maintenance.

Cela produit quatre changements concrets.

1. La syntaxe devient moins chère, le contexte devient plus précieux

Une IA peut générer une fonction utilisant ?., ??, Promise.allSettled() ou les aides d’itérateurs sans que vous mémorisiez l’année de standardisation. Elle ne connaît pas automatiquement vos contraintes métier, votre matrice de compatibilité, vos conventions, vos menaces de sécurité ou la raison pour laquelle un bout de code apparemment absurde existe depuis six ans.

Le développeur apporte donc moins de valeur en récitant la liste des méthodes et davantage en définissant le problème, les invariants, les limites et les critères de réussite.

Un invariant est une condition qui doit toujours rester vraie. Exemple : « le solde ne peut jamais devenir négatif » est plus utile à une IA que « crée-moi une classe moderne et élégante », formulation qui appelle surtout une généreuse portion d’adjectifs.

2. Produire plus vite permet aussi de produire des erreurs plus vite

L’IA peut inventer une API, utiliser une proposition non standardisée, mélanger les comportements de plusieurs runtimes ou ajouter une dépendance disproportionnée. Elle peut générer du code plausible, c’est-à-dire exactement le type de code qui passe une revue distraite.

Le risque n’est pas seulement l’erreur visible. C’est la dette logicielle produite à haute vitesse : duplications, abstractions prématurées, tests décoratifs, dépendances inutiles et gestion incomplète des erreurs. L’automatisation a toujours été excellente pour accélérer. Elle demande seulement de préciser dans quelle direction.

3. Les tests et les outils d’analyse deviennent encore plus importants

Le code généré doit passer par les mêmes contrôles que le code humain : formatage, analyse statique, typage, tests unitaires, tests d’intégration, vérification de sécurité et revue du changement.

Une réponse d’IA n’est pas une preuve. Un test qui échoue est une information. Un test qui passe est une information meilleure, mais limitée aux cas couverts. Et cent pour cent de couverture ne prouve pas que les assertions racontent quelque chose d’intéressant. On peut parfaitement tester avec une précision industrielle que la mauvaise fonction produit le mauvais résultat attendu.

4. Comprendre le langage reste nécessaire pour relire

L’IA réduit l’effort de rappel, pas le besoin de jugement. Pour vérifier une fonction asynchrone, il faut comprendre les promesses, les erreurs et la concurrence. Pour repérer une copie superficielle, il faut comprendre les références. Pour évaluer un champ privé, il faut comprendre les classes. Pour juger une API récente, il faut connaître le niveau de compatibilité attendu.

Autrement dit, l’IA peut tenir le clavier. Elle ne signe pas l’incident de production.

Une méthode raisonnable pour travailler avec l’IA sur du JavaScript moderne

Un processus utile tient en six étapes.

  1. Définir la cible. Préciser le navigateur minimal, la version du runtime, le format de modules et l’usage éventuel de TypeScript.
  2. Donner le contexte utile. Fournir les interfaces, conventions, exemples d’entrée et de sortie, ainsi que les contraintes métier.
  3. Limiter le changement. Demander un diff minimal et interdire les nouvelles dépendances sauf justification.
  4. Exiger des tests significatifs. Couvrir les cas normaux, les limites, les erreurs et les comportements asynchrones.
  5. Exécuter les contrôles. Lancer le typage, le linter, les tests et la construction réelle du projet.
  6. Relire le raisonnement. Vérifier l’API, la compatibilité, les erreurs, la sécurité, les performances et la maintenabilité.

Un prompt technique devient plus fiable lorsqu’il fixe des contraintes observables :

Implémente cette fonction en JavaScript ESM pour Node.js 24, sans nouvelle dépendance. Conserve l’API publique, gère l’annulation et les erreurs HTTP, ajoute des tests pour les réponses 200, 404, 500 et le dépassement de délai. N’utilise que des fonctionnalités disponibles dans cette cible et présente le changement sous forme de diff minimal.

Ce prompt ne garantit pas un bon résultat. Il réduit simplement l’espace disponible pour l’improvisation. C’est déjà beaucoup, y compris avec certains collègues humains.

Ce qu’un développeur revenu de 2015 doit apprendre en priorité

Il n’est pas nécessaire d’étudier chaque édition comme une collection de timbres. L’ordre suivant couvre l’essentiel du JavaScript professionnel moderne.

Niveau 1 — indispensable

  • const, let et portée de bloc ;
  • fonctions fléchées et comportement de this ;
  • chaînes de gabarit ;
  • déstructuration, paramètres par défaut, rest et spread ;
  • modules import/export ;
  • promesses, async/await et gestion des erreurs ;
  • méthodes de tableaux : map, filter, reduce, find, some, every ;
  • Map, Set et for...of ;
  • chaînage optionnel ?. et coalescence ??.

Niveau 2 — très utile dans les projets actuels

  • imports dynamiques et découpage du code ;
  • Promise.all(), allSettled(), any() et race() ;
  • champs de classes, champs privés et méthodes statiques ;
  • méthodes de copie des tableaux ;
  • Object.entries(), Object.fromEntries() et Object.groupBy() ;
  • itérateurs et itérateurs asynchrones ;
  • bases de TypeScript et de l’analyse statique ;
  • compréhension de la cible d’exécution et de la compatibilité.

Niveau 3 — à apprendre lorsqu’un besoin apparaît

  • générateurs avancés ;
  • Proxy, Reflect et métaprogrammation ;
  • WeakMap, WeakSet, WeakRef et FinalizationRegistry ;
  • tableaux typés, mémoire partagée et Atomics ;
  • fonctionnalités fines des expressions régulières ;
  • méthodes ES2025 et ES2026 encore inégalement déployées dans les environnements pris en charge.

Moderniser un ancien projet sans déclencher un programme spatial

La modernisation peut suivre une progression contrôlée.

  1. Établir le comportement existant. Ajouter ou stabiliser les tests avant de modifier la syntaxe.
  2. Définir les environnements cibles. Navigateurs, versions de Node.js, appareils embarqués ou autres runtimes déterminent les choix possibles.
  3. Automatiser le style. Un formateur et un linter réduisent les débats et détectent des constructions risquées.
  4. Remplacer var avec attention. La portée et le hissage — le traitement des déclarations avant l’exécution — peuvent modifier le comportement.
  5. Passer aux modules par frontières claires. Éviter la conversion simultanée de tout le dépôt si les dépendances sont emmêlées.
  6. Moderniser l’asynchronisme avec des tests. Une conversion mécanique de rappels vers async/await peut changer l’ordre et la gestion des erreurs.
  7. Réduire les dépendances devenues inutiles. Vérifier d’abord la compatibilité et l’impact sur le bundle.
  8. Introduire TypeScript progressivement si le projet en bénéficie. Commencer par les interfaces publiques et les zones à risque.
  9. Utiliser l’IA sur des changements bornés. Une fonction, un module ou une migration vérifiable vaut mieux qu’un ordre héroïque comme « modernise toute l’application ».
  10. Mesurer avant d’optimiser. Temps de démarrage, taille livrée, mémoire et latence doivent être observés, pas devinés avec intensité.

Alors, qu’est-ce qui a vraiment changé ?

JavaScript a moins changé par accumulation de gadgets que par construction d’un vocabulaire cohérent.

  • ES2015 a donné une architecture moderne au langage : portée de bloc, modules, classes, promesses, itérables et syntaxe expressive.
  • ES2017 a rendu l’asynchronisme nettement plus lisible avec async/await.
  • ES2020 a supprimé plusieurs irritants quotidiens avec ?., ??, BigInt et de meilleurs outils pour les promesses et les modules.
  • ES2022 a donné aux classes de vrais champs privés et permis await au niveau supérieur des modules.
  • ES2023 à ES2026 ont enrichi les transformations immuables, le regroupement, les ensembles, les itérateurs, les données binaires, JSON et les calculs précis.
  • L’écosystème a déplacé une partie de la complexité vers les types, les outils, les runtimes et les chaînes de construction.
  • L’IA a diminué le coût du premier jet, mais augmenté l’importance du contexte, des tests, de la revue et de la responsabilité technique.

Le développeur de 2026 n’a donc pas besoin de réciter ECMA-262. Il doit savoir reconnaître les bons outils, comprendre leurs limites, vérifier leur compatibilité et relire du code produit plus vite qu’avant. La compétence rare n’est plus seulement d’écrire une boucle. C’est de savoir si cette boucle devait exister, si elle traite les bons cas et si la machine qui l’a proposée n’a pas discrètement importé un paquet abandonné pour additionner deux nombres.

Sources et pistes d’approfondissement

Comment exporter la liste des polices utilisées dans un document Adobe InDesign avec un script JSX

Écouter cet article

Lorsque vous travaillez sur un document Adobe InDesign contenant de nombreuses pages, styles et blocs de texte, identifier toutes les polices utilisées peut rapidement devenir fastidieux.

Cette information est pourtant utile dans plusieurs situations :

  • préparer un document pour l’impression ;
  • transmettre un projet à un autre graphiste ;
  • vérifier les polices avant de créer un package InDesign ;
  • repérer des polices manquantes ;
  • documenter les ressources typographiques d’un projet ;
  • effectuer un audit graphique d’une publication.

Adobe InDesign permet déjà de consulter les polices utilisées dans un document, notamment avec la fonction Rechercher une police. Mais lorsqu’on souhaite récupérer ces informations sous forme de fichier exploitable dans Excel, LibreOffice Calc ou Google Sheets, un petit script peut être beaucoup plus pratique.

Nous allons donc créer un script JSX capable d’analyser le document InDesign ouvert et d’exporter les polices utilisées dans un fichier CSV.


Qu’est-ce qu’un script JSX dans InDesign ?

Un fichier .jsx est un fichier JavaScript destiné à l’environnement de script des applications Adobe.

Dans InDesign, les scripts permettent d’automatiser de nombreuses opérations :

  • créer des blocs ;
  • modifier des styles ;
  • analyser du texte ;
  • exporter des données ;
  • renommer des éléments ;
  • générer automatiquement des documents ;
  • effectuer des contrôles avant impression.

Le langage utilisé historiquement par InDesign pour ces scripts est basé sur ExtendScript, une implémentation de JavaScript adaptée aux applications Adobe.

Dans notre cas, le script va parcourir le texte du document et récupérer trois informations pour chaque police rencontrée :

  1. la famille de caractères ;
  2. le style typographique ;
  3. le nom PostScript.

Par exemple :

FamilleStyleNom PostScript
Minion ProRegularMinionPro-Regular
Minion ProBoldMinionPro-Bold
Helvetica Neue55 RomanHelveticaNeue-Roman
Helvetica Neue75 BoldHelveticaNeue-Bold

Le nom PostScript est le nom technique de la police utilisé par certains logiciels, systèmes d’impression et workflows de production.


Étape 1 — Ouvrir le panneau Scripts d’InDesign

Commencez par ouvrir le document InDesign que vous souhaitez analyser.

Dans InDesign, ouvrez ensuite :

Fenêtre → Utilitaires → Scripts

Dans une interface anglaise :

Window → Utilities → Scripts

Le panneau affiche généralement plusieurs catégories de scripts.

Nous allons travailler dans le dossier User, c’est-à-dire le dossier contenant vos scripts personnels.


Étape 2 — Localiser le dossier des scripts

La procédure est pratiquement identique sur macOS et Windows.

Sur macOS

Dans le panneau Scripts :

  1. repérez le dossier User ;
  2. effectuez un clic droit dessus ;
  3. choisissez Reveal in Finder ou son équivalent dans votre version française d’InDesign.

Le Finder s’ouvre directement dans le dossier correspondant.

Vous pourrez y placer votre fichier .jsx.


Sur Windows

Dans le panneau Scripts :

  1. repérez le dossier User ;
  2. effectuez un clic droit ;
  3. choisissez Reveal in Explorer ou son équivalent français.

L’Explorateur de fichiers Windows s’ouvre dans le dossier des scripts utilisateur d’InDesign.

L’intérêt de cette méthode est qu’il n’est pas nécessaire de rechercher manuellement le dossier dans les fichiers système.


Étape 3 — Créer le fichier ExportFonts.jsx

Dans le dossier qui vient de s’ouvrir, créez un nouveau fichier appelé :

ExportFonts.jsx

Attention à l’extension du fichier.

Le fichier doit réellement se terminer par :

.jsx

et non :

ExportFonts.jsx.txt

Ce problème est particulièrement fréquent sous Windows lorsque les extensions de fichiers sont masquées.


Créer le fichier sur macOS

Vous pouvez utiliser un éditeur comme :

  • Visual Studio Code ;
  • Sublime Text ;
  • BBEdit ;
  • CotEditor ;
  • un autre éditeur de texte brut.

Évitez les traitements de texte comme Microsoft Word ou Apple Pages, car ils ajoutent des informations de mise en forme qui ne conviennent pas à un fichier JavaScript.


Créer le fichier sous Windows

Vous pouvez utiliser :

  • Visual Studio Code ;
  • Notepad++ ;
  • Sublime Text ;
  • le Bloc-notes ;
  • n’importe quel éditeur de texte brut.

Si vous utilisez le Bloc-notes, lors de l’enregistrement, choisissez si nécessaire Tous les fichiers comme type de fichier afin d’éviter que Windows ajoute automatiquement l’extension .txt.

Le nom doit rester exactement :

ExportFonts.jsx


Étape 4 — Ajouter le script

Copiez le script suivant dans votre fichier.

// ================================================================
// Adobe InDesign
// Export de toutes les polices réellement utilisées dans le document
// vers un fichier CSV.
//
// Le script récupère :
// - la famille de la police ;
// - le style de la police ;
// - le nom PostScript.
//
// Le fichier CSV peut ensuite être ouvert dans Excel,
// LibreOffice Calc, Numbers ou Google Sheets.
// ================================================================


// ---------------------------------------------------------------
// 1. Vérifier qu'un document InDesign est ouvert
// ---------------------------------------------------------------

// app.documents représente la collection des documents
// actuellement ouverts dans InDesign.
//
// Si sa longueur est égale à zéro, aucun document n'est ouvert.
if (app.documents.length === 0) {

    // Affiche un message à l'utilisateur.
    alert("Aucun document InDesign n'est ouvert.");

    // Interrompt immédiatement l'exécution du script.
    exit();
}


// ---------------------------------------------------------------
// 2. Récupérer le document actif
// ---------------------------------------------------------------

// app.activeDocument correspond au document actuellement sélectionné.
var doc = app.activeDocument;


// ---------------------------------------------------------------
// 3. Créer un objet destiné à mémoriser les polices
// ---------------------------------------------------------------

// Cet objet va servir de dictionnaire.
//
// Chaque police rencontrée sera enregistrée une seule fois,
// même si elle apparaît plusieurs centaines de fois dans le document.
var fonts = {};


// ---------------------------------------------------------------
// 4. Récupérer toutes les stories du document
// ---------------------------------------------------------------

// Une "story" InDesign représente un flux de texte.
//
// Un même flux peut traverser plusieurs blocs de texte chaînés.
//
// getElements() transforme la collection InDesign
// en éléments que nous pouvons parcourir avec une boucle.
var stories = doc.stories.everyItem().getElements();


// ---------------------------------------------------------------
// 5. Parcourir toutes les stories
// ---------------------------------------------------------------

for (var i = 0; i < stories.length; i++) {

    // textContainers contient les blocs qui accueillent
    // le texte de cette story.
    var textFrames = stories[i].textContainers;


    // -----------------------------------------------------------
    // 6. Parcourir les blocs de texte
    // -----------------------------------------------------------

    for (var j = 0; j < textFrames.length; j++) {

        // Récupération du contenu textuel du bloc.
        var text = textFrames[j].texts[0];


        // -------------------------------------------------------
        // 7. Analyser chaque caractère
        // -------------------------------------------------------

        // Nous examinons chaque caractère afin d'identifier
        // précisément la police réellement appliquée au texte.
        for (var k = 0; k < text.characters.length; k++) {

            try {

                // Récupération de la police appliquée
                // au caractère courant.
                var font = text.characters[k].appliedFont;


                // ---------------------------------------------------
                // 8. Construire une clé unique
                // ---------------------------------------------------

                // Une même famille peut exister dans plusieurs styles.
                //
                // Par exemple :
                // Minion Pro | Regular
                // Minion Pro | Bold
                //
                // Nous combinons donc famille + style.
                var key =
                    font.fontFamily +
                    " | " +
                    font.fontStyleName;


                // ---------------------------------------------------
                // 9. Ajouter la police seulement si elle
                //    n'a pas encore été rencontrée
                // ---------------------------------------------------

                if (!fonts[key]) {

                    fonts[key] = {

                        // Nom de la famille typographique.
                        family: font.fontFamily,

                        // Variante de la police :
                        // Regular, Bold, Italic, Light, etc.
                        style: font.fontStyleName,

                        // Nom technique PostScript.
                        postscript: font.postscriptName
                    };
                }

            } catch (e) {

                // Certaines situations particulières peuvent provoquer
                // une erreur lors de la lecture d'un caractère.
                //
                // Plutôt que d'interrompre tout le script,
                // nous ignorons simplement ce caractère.
            }
        }
    }
}


// ---------------------------------------------------------------
// 10. Construire le contenu du fichier CSV
// ---------------------------------------------------------------

// Première ligne : noms des colonnes.
//
// \r\n correspond à un retour à la ligne compatible
// avec les principaux tableurs.
var csv =
    "Font Family,Style,PostScript Name\r\n";


// ---------------------------------------------------------------
// 11. Ajouter les polices au fichier CSV
// ---------------------------------------------------------------

for (var key in fonts) {

    // Les valeurs sont entourées de guillemets.
    //
    // replace(/"/g, '""') permet d'échapper les éventuels
    // guillemets contenus dans les données.
    //
    // Cette méthode respecte la syntaxe classique d'un CSV.
    csv +=
        '"' +
        fonts[key].family.replace(/"/g, '""') +
        '","' +

        fonts[key].style.replace(/"/g, '""') +
        '","' +

        fonts[key].postscript.replace(/"/g, '""') +
        '"\r\n';
}


// ---------------------------------------------------------------
// 12. Demander à l'utilisateur où enregistrer le fichier
// ---------------------------------------------------------------

// Une boîte de dialogue système apparaît.
//
// L'utilisateur peut choisir :
// - le dossier ;
// - le nom du fichier.
var file =
    File.saveDialog(
        "Enregistrer la liste des polices au format CSV",
        "*.csv"
    );


// ---------------------------------------------------------------
// 13. Enregistrer le fichier
// ---------------------------------------------------------------

// Si l'utilisateur annule la fenêtre,
// la variable file ne contient aucune valeur.
//
// Nous vérifions donc qu'un fichier a bien été choisi.
if (file) {

    // Utilisation de l'encodage UTF-8.
    //
    // Cela permet notamment de gérer correctement
    // les caractères accentués.
    file.encoding = "UTF-8";


    // Ouverture du fichier en mode écriture.
    //
    // "w" signifie "write".
    file.open("w");


    // Écriture de toutes les données CSV.
    file.write(csv);


    // Fermeture du fichier.
    file.close();


    // Confirmation destinée à l'utilisateur.
    alert(
        "La liste des polices a été exportée avec succès."
    );
}

Étape 5 — Lancer le script dans InDesign

Une fois le fichier enregistré dans le dossier des scripts utilisateur, revenez dans InDesign.

Le fichier devrait apparaître automatiquement dans :

Fenêtre → Utilitaires → Scripts → User

Vous devriez voir :

ExportFonts.jsx

Double-cliquez simplement dessus.

Le script commence alors l’analyse du document.

À la fin, une fenêtre vous demande où enregistrer le fichier CSV.

Vous pouvez par exemple choisir :

polices-document.csv


Sur macOS : où enregistrer le CSV ?

La boîte de dialogue utilise le sélecteur de fichiers standard de macOS.

Vous pouvez par exemple enregistrer le fichier :

  • sur le Bureau ;
  • dans Documents ;
  • dans le dossier du projet InDesign ;
  • dans un dossier partagé avec votre équipe.

Une fois le fichier créé, vous pouvez l’ouvrir avec :

  • Microsoft Excel ;
  • Apple Numbers ;
  • LibreOffice Calc ;
  • Google Sheets après importation.

Sous Windows : où enregistrer le CSV ?

La boîte de dialogue utilise l’Explorateur de fichiers Windows.

Vous pouvez enregistrer le CSV :

  • sur le Bureau ;
  • dans Documents ;
  • dans le dossier de votre projet ;
  • sur un serveur ;
  • dans un dossier OneDrive.

Le fichier peut ensuite être ouvert avec Excel ou LibreOffice Calc.


Que contient le fichier CSV ?

Le script crée trois colonnes :

Font Family,Style,PostScript Name

Un fichier généré pourrait ressembler à ceci :

"Minion Pro","Regular","MinionPro-Regular"
"Minion Pro","Bold","MinionPro-Bold"
"Helvetica Neue","55 Roman","HelveticaNeue-Roman"
"Helvetica Neue","75 Bold","HelveticaNeue-Bold"

Une fois ouvert dans un tableur, le résultat devient beaucoup plus lisible.

Font FamilyStylePostScript Name
Minion ProRegularMinionPro-Regular
Minion ProBoldMinionPro-Bold
Helvetica Neue55 RomanHelveticaNeue-Roman
Helvetica Neue75 BoldHelveticaNeue-Bold

Comment fonctionne le script ?

Le principe est relativement simple.

Le script commence par récupérer le document actif :

var doc = app.activeDocument;

Il récupère ensuite toutes les stories du document.

Dans InDesign, une story correspond à un flux de texte.

Si vous avez par exemple trois blocs de texte chaînés, ils peuvent appartenir à une seule et même story.

var stories =
    doc.stories.everyItem().getElements();

Le script parcourt ensuite chaque bloc de texte et chaque caractère.

Pour chaque caractère, il demande à InDesign quelle police est appliquée :

var font =
    text.characters[k].appliedFont;

Il peut ensuite récupérer différentes propriétés de la police :

font.fontFamily
font.fontStyleName
font.postscriptName

Pourquoi analyser les caractères individuellement ?

On pourrait être tenté de simplement analyser les blocs de texte.

Le problème est qu’un seul bloc peut contenir plusieurs polices.

Prenons par exemple la phrase :

Découvrez notre nouvelle collection.

Le mot « Découvrez » pourrait être en Helvetica Neue Bold tandis que le reste de la phrase utilise Helvetica Neue Regular.

En analysant les caractères individuellement, le script peut détecter ces deux variantes.

Cette approche donne donc une vision plus précise des polices réellement utilisées dans le contenu.


Pourquoi utiliser un objet fonts ?

Supposons qu’un document contienne 150 000 caractères en Minion Pro Regular.

Nous ne voulons évidemment pas obtenir 150 000 lignes identiques dans le fichier CSV.

Le script utilise donc un objet JavaScript :

var fonts = {};

La combinaison suivante sert de clé :

font.fontFamily + " | " + font.fontStyleName

Par exemple :

Minion Pro | Regular
Minion Pro | Bold
Helvetica Neue | 55 Roman

Avant d’enregistrer une police, le script vérifie qu’elle n’a pas déjà été ajoutée :

if (!fonts[key]) {

Chaque combinaison famille/style n’apparaît donc qu’une seule fois dans le CSV.


Pourquoi exporter également le nom PostScript ?

Le nom affiché dans InDesign n’est pas toujours exactement le même que le nom technique de la police.

Par exemple :

Famille : Minion Pro
Style : Regular
PostScript : MinionPro-Regular

Le nom PostScript peut être particulièrement utile dans les environnements :

  • prépresse ;
  • impression professionnelle ;
  • PDF ;
  • automatisation ;
  • catalogues de polices ;
  • scripts ;
  • outils de gestion typographique.

Il permet également de distinguer plus précisément certaines variantes.


Une limite importante de cette méthode

Le script présenté ici recherche les polices réellement appliquées à des caractères présents dans les blocs de texte analysés.

Cela signifie qu’il est principalement destiné à répondre à la question :

Quelles polices sont réellement utilisées par le texte de mon document ?

Mais un document InDesign peut contenir des références à des polices qui ne sont actuellement appliquées à aucun caractère.

Cela peut notamment arriver dans :

  • des styles de paragraphe ;
  • des styles de caractère ;
  • des blocs de texte vides ;
  • certains éléments de gabarit ;
  • des styles importés mais inutilisés ;
  • des éléments masqués ;
  • certains contenus conditionnels.

Dans ces situations, une analyse plus complète du document est nécessaire.


Différence entre une police utilisée et une police référencée

Cette distinction est importante pour comprendre le résultat.

Une police utilisée est réellement appliquée à du texte présent dans le document.

Par exemple :

Helvetica Neue Bold

est utilisée si au moins un caractère du document utilise cette police.

Une police référencée, en revanche, peut simplement être enregistrée dans un style.

Imaginons un style de paragraphe nommé :

Citation

utilisant :

Garamond Premier Pro Italic

Si aucun paragraphe du document n’utilise actuellement ce style, Garamond peut être présente dans la définition du style sans être utilisée dans le texte.

Notre script simple ne détectera pas nécessairement cette situation.


Vers un véritable inventaire prépresse

Pour une utilisation professionnelle, notamment avant l’envoi d’un fichier chez un imprimeur ou à un autre graphiste, il peut être intéressant de créer une version plus complète du script.

Cette version pourrait exporter, pour chaque police :

  • la famille ;
  • le style ;
  • le nom PostScript ;
  • le nombre de caractères utilisant la police ;
  • le nombre d’occurrences ;
  • les styles de paragraphe qui utilisent la police ;
  • les styles de caractère qui utilisent la police ;
  • les pages sur lesquelles elle apparaît ;
  • les éléments de gabarit concernés ;
  • le statut de la police ;
  • les éventuelles polices manquantes.

On pourrait par exemple obtenir un CSV de ce type :

FamilleStylePostScriptCaractèresStatut
Minion ProRegularMinionPro-Regular42 315Disponible
Minion ProBoldMinionPro-Bold2 417Disponible
Helvetica Neue55 RomanHelveticaNeue-Roman839Disponible
GothamBoldGotham-Bold56Manquante

Ce type d’inventaire devient particulièrement utile dans un workflow de prépresse, c’est-à-dire l’ensemble des vérifications et préparations effectuées avant l’impression professionnelle.


Une amélioration possible : compter les caractères

Notre objet contient actuellement trois propriétés :

fonts[key] = {
    family: font.fontFamily,
    style: font.fontStyleName,
    postscript: font.postscriptName
};

Il serait possible d’ajouter un compteur :

fonts[key] = {
    family: font.fontFamily,
    style: font.fontStyleName,
    postscript: font.postscriptName,
    count: 0
};

Puis d’incrémenter ce compteur chaque fois que la police est rencontrée :

fonts[key].count++;

Le CSV pourrait alors indiquer approximativement l’importance de chaque police dans le document.

Une police utilisée sur 50 000 caractères n’a en effet pas la même importance qu’une police utilisée sur un seul symbole oublié dans un bloc.

Cette information peut être très utile lorsqu’on cherche à nettoyer un document.


Une amélioration possible : détecter les polices manquantes

InDesign sait également qu’une police référencée dans un document est indisponible.

Une version plus avancée du script pourrait analyser l’état de chaque police et créer une colonne supplémentaire :

Status

avec par exemple :

Installed
Missing
Substituted

Une telle fonction permettrait de transformer le script en véritable outil de contrôle avant production.


Une amélioration possible : afficher les pages concernées

Autre fonction intéressante : mémoriser les pages sur lesquelles chaque police est utilisée.

Le fichier pourrait alors contenir :

PoliceStylePages
Minion ProRegular1-24
Helvetica NeueBold1, 4, 8
GothamRegular17

Cela permettrait de retrouver rapidement une police problématique sans devoir parcourir manuellement tout le document.


CSV ou TXT : lequel choisir ?

Le CSV est généralement le format le plus pratique lorsque les données doivent être analysées dans un tableur.

CSV signifie Comma-Separated Values, c’est-à-dire « valeurs séparées par des virgules ».

Il est adapté à Excel, Numbers, LibreOffice Calc et Google Sheets.

Un fichier TXT peut cependant être intéressant lorsqu’on souhaite simplement obtenir une liste lisible.

Par exemple :

Minion Pro — Regular
Minion Pro — Bold
Helvetica Neue — 55 Roman
Helvetica Neue — 75 Bold

La modification du script pour produire un fichier texte est relativement simple.

Il suffit de construire le contenu sous cette forme :

// Création d'une chaîne de texte vide.
var txt = "";

// Parcours de toutes les polices trouvées.
for (var key in fonts) {

    // Une police est ajoutée par ligne.
    txt +=
        fonts[key].family +
        " - " +
        fonts[key].style +
        " - " +
        fonts[key].postscript +
        "\r\n";
}

Puis d’utiliser :

// Affichage d'une boîte de dialogue demandant
// où enregistrer le fichier texte.
var file =
    File.saveDialog(
        "Enregistrer la liste des polices",
        "*.txt"
    );

Où peut-on aller plus loin avec les scripts InDesign ?

L’export des polices n’est qu’un exemple relativement simple de ce qu’il est possible d’automatiser.

Le même principe permet de créer des scripts capables de :

  • exporter toutes les couleurs d’un document ;
  • lister les styles de paragraphe ;
  • détecter les images en basse résolution ;
  • rechercher les images manquantes ;
  • exporter les dimensions des images ;
  • vérifier les fonds perdus ;
  • analyser les liens ;
  • détecter les blocs contenant du texte en excès ;
  • créer automatiquement des rapports prépresse ;
  • générer des catalogues ;
  • produire des documents à partir de données CSV ou JSON.

Il devient même possible de créer un script générant automatiquement un rapport d’audit complet contenant les polices, les images, les couleurs, les pages problématiques et les ressources manquantes.