Formation publique · Jour 6 / 6

Architecture & polish

Sections

  1. 01 Modules ES dans le navigateur (60 min)
  2. 02 Fonctions d’ordre supérieur (pratique) (40 min)
  3. 03 Architecture légère sans framework (50 min)
  4. 04 Exploration libre & suite
  5. Extra 1 jQuery (exploration libre)
  6. Extra 2 Chart.js (exploration libre)
  7. Extra 3 Aperçu TypeScript (≈ 1 h)
  8. Récap Refactoriser l’application de notes en modules

1 Modules ES dans le navigateur (60 min)

Jusqu’ici tout le code vivait dans un seul fichier. Ça marche. Ça ne scale pas.

Les modules permettent de découper le code en fichiers responsables, avec des frontières explicites.

1.1 Un fichier = un module

Chaque fichier JavaScript chargé avec type="module" est un module.

Il a sa propre portée. Les variables déclarées dedans ne polluent plus le scope global.

1.2 type="module"

<script type="module" src="main.js"></script>

Différences importantes :

  • Le navigateur traite le fichier en mode strict automatiquement.
  • Le script est différé par défaut (comme defer).
  • On peut utiliser import / export.

1.3 export nommé

// calc.js
export function calculateTTC(ht, rate = 0.2) {
  return ht * (1 + rate);
}

export const DEFAULT_RATE = 0.2;
// main.js
import { calculateTTC, DEFAULT_RATE } from './calc.js';

console.log(calculateTTC(100, DEFAULT_RATE));

Les accolades sont obligatoires pour les exports nommés.

1.4 export default

// format.js
export default function formatPrice(value) {
  return new Intl.NumberFormat('fr-FR', {
    style: 'currency',
    currency: 'EUR'
  }).format(value);
}
// main.js
import formatPrice from './format.js';

console.log(formatPrice(120));

Un seul export default par module. On l’importe sans accolades.

1.5 Chemins relatifs uniquement

Le chemin doit commencer par ./ ou ../.

import { calculateTTC } from './calc.js';     // correct
import { calculateTTC } from 'calc.js';       // erreur

Le navigateur ne résout pas les « bare imports » comme Node.

1.6 Serveur local obligatoire

Les modules ES ne fonctionnent pas en file://.

Le navigateur bloque le chargement (CORS / module scripts).

Utilisez le même serveur local qu’hier (Live Server, python -m http.server, etc.).

1.7 DevTools – ce qu’il faut regarder

  • Sources : chaque module apparaît comme un fichier distinct. On peut y poser des breakpoints.
  • Network : on voit les requêtes des fichiers .js modules (status 200, type script).

Habitude utile : après chaque changement d’import, regardez Network pour vérifier que les bons fichiers sont bien chargés.

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-6/s1_modules

Travaillez dans les fichiers .js. Suivez les commentaires dans l’ordre. Après chaque étape : sauvegardez → rafraîchissez → regardez Console + Sources + Network.

Checkpoint

Vous savez :

  • déclarer un script en type="module",
  • exporter et importer des fonctions (named + default),
  • utiliser uniquement des chemins relatifs,
  • vérifier le chargement des modules dans Network et Sources.

2 Fonctions d’ordre supérieur (pratique) (40 min)

Vous avez déjà utilisé des fonctions d’ordre supérieur sans forcément le nommer.

Une fonction d’ordre supérieur est une fonction qui reçoit une autre fonction en argument ou qui retourne une fonction.

map, filter, addEventListener : toutes reçoivent une fonction en argument.

Aujourd’hui on regarde explicitement ce pattern, très brièvement, pour le rendre conscient et utile.

2.1 Une fonction qui reçoit une fonction

C’est le cas le plus courant.

function process(list, fn) {
  const result = [];
  for (const item of list) {
    result.push(fn(item));
  }
  return result;
}

const prices = [10, 25, 8];
const doubled = process(prices, (n) => n * 2);
console.log(doubled); // [20, 50, 16]

Ici, process est la fonction d’ordre supérieur : elle reçoit fn en argument. process ne sait pas comment transformer chaque élément. C’est fn qui le décide.

C’est exactement le même principe que Array.prototype.map.

2.2 Une fonction qui retourne une fonction

Utile pour créer des variantes configurées.

function makeMultiplier(factor) {
  return function (n) {
    return n * factor;
  };
}

const double = makeMultiplier(2);
const triple = makeMultiplier(3);

console.log(double(10)); // 20
console.log(triple(10)); // 30

Ici, makeMultiplier est la fonction d’ordre supérieur : elle retourne une fonction. On crée une fonction spécialisée une fois, puis on la réutilise.

2.3 Pattern pratique : logger configurable

function makeLogger(prefix) {
  return function (message) {
    console.log(`[${prefix}] ${message}`);
  };
}

const logInfo = makeLogger("INFO");
const logError = makeLogger("ERROR");

logInfo("Calcul terminé");
logError("Valeur invalide");

Ici, makeLogger est la fonction d’ordre supérieur : elle retourne une fonction. Simple, lisible, et déjà très utile au quotidien.

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-6/s2_hof

Travaillez uniquement dans scripts.js. Suivez les commentaires dans l’ordre. Après chaque bloc : sauvegardez → rafraîchissez → observez la Console.

Checkpoint

Vous savez :

  • écrire une fonction qui reçoit une autre fonction en argument,
  • écrire une fonction qui retourne une fonction (usine simple),
  • reconnaître que map, filter et addEventListener sont des cas du même pattern.

3 Architecture légère sans framework (50 min)

Le code qui mélange tout (état, calculs, DOM) devient rapidement fragile.

On sépare clairement trois responsabilités.

3.1 Les trois couches

  • État – une seule source de vérité (un objet ou un module qui le possède).
  • Logique pure – fonctions qui reçoivent des données et retournent un résultat. Pas d’effet de bord.
  • Interface – lit l’état, écoute les événements, met à jour le DOM.

Le rendu ne calcule pas. La logique ne touche pas au DOM.

3.2 Une seule source de vérité

// state.js
export const state = {
  value: 0,
  history: []
};

Tout le monde lit et met à jour le même objet. Pas de copies dispersées.

3.3 Fonctions pures

Même entrée → même sortie. Aucune modification cachée de l’extérieur.

// logic.js
export function increment(current) {
  return {
    value: current.value + 1,
    history: [...current.history, current.value + 1]
  };
}

export function decrement(current) {
  return {
    value: current.value - 1,
    history: [...current.history, current.value - 1]
  };
}

export function reset() {
  return { value: 0, history: [] };
}

On retourne un nouvel objet d’état. On ne mute pas l’ancien.

3.4 Le rendu et les événements restent minces

// main.js
import { state } from './state.js';
import { increment, decrement, reset } from './logic.js';

function render() {
  document.querySelector('#value').textContent = state.value;
  document.querySelector('#history').textContent = state.history.join(' → ');
}

document.querySelector('#btn-inc').addEventListener('click', () => {
  Object.assign(state, increment(state));
  render();
});

Les gestionnaires appellent la logique, mettent à jour la source de vérité, puis demandent un rendu.

3.5 Classes ou fonctions ?

Une classe peut regrouper état + méthodes quand le regroupement clarifie vraiment le code.

Pour la majorité des cas simples, des fonctions pures + un objet d’état suffisent et restent plus faciles à tester et à lire.

On reste volontairement fonctionnel dans cet exercice.

À essayer

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-6/s3_architecture

Travaillez dans les fichiers .js. Suivez les commentaires dans l’ordre. Après chaque étape : sauvegardez → rafraîchissez → regardez Console + Sources.

Checkpoint

Vous savez :

  • séparer état / logique pure / interface,
  • garder une seule source de vérité,
  • écrire des fonctions pures qui retournent le prochain état,
  • garder le code d’événements et de rendu mince.

4 Exploration libre & suite

Le tronc commun de la formation s’arrête ici.

Le reste de l’après-midi est libre. Choisissez selon votre énergie et votre curiosité.

4.1 Ce qui vient après

Vous avez maintenant les bases solides du JavaScript dans le navigateur et des DevTools.

Les prochaines étapes réalistes, dans l’ordre où elles ont le plus de sens :

  • Approfondir le DOM et les événements sur des interfaces un peu plus riches.
  • Apprendre à structurer un projet un peu plus grand (toujours en vanilla).
  • Quand la taille du code commence à faire mal : un framework (React, Vue, Svelte…) peut devenir utile. Pas avant.
  • TypeScript – pour gagner en robustesse dès que le projet dépasse quelques fichiers.
  • Les tests (au minimum les tests unitaires des fonctions pures).

Il n’y a pas d’urgence. Maîtriser bien le vanilla reste le meilleur investissement.

4.2 Trois pistes d’exploration libre

Trois sections Extra sont dédiées à jQuery, Chart.js et TypeScript pour celles et ceux qui le souhaitent.

4.3 Clôture

Quelques questions ouvertes, un retour collectif rapide, et on s’arrête proprement.

Merci d’avoir tenu six jours. Le vrai travail commence maintenant : écrire du code, le casser, le réparer, et recommencer.

Fin de la formation

Vous repartez avec :

  • les fondamentaux du langage dans le navigateur,
  • une aisance réelle avec les DevTools,
  • les premiers réflexes d’architecture légère,
  • et la capacité de continuer seul ou de choisir la suite (bibliothèques, TypeScript, framework…).

x1 Extra – jQuery (exploration libre)

Le tronc commun reste 100 % vanilla. Cette piste est purement optionnelle.

jQuery est encore très présent dans du code existant. Il est utile de savoir le lire et d’en comprendre le coût.

x1.1 Chargement via CDN

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

Une seule balise. Pas de build tool.

x1.2 Patterns encore courants

// Sélection
const $btn = $("#my-btn");
const $items = $(".item");

// Événement
$btn.on("click", function () {
  console.log("cliqué");
});

// Classes
$btn.addClass("active");
$btn.removeClass("active");
$btn.toggleClass("active");

// Contenu
$("#title").text("Nouveau titre");
$("#title").html("<strong>Nouveau titre</strong>");

x1.3 Coût / bénéfice

  • Bénéfice : syntaxe courte, beaucoup de code legacy l’utilise, quelques utilitaires pratiques.
  • Coût : dépendance externe, taille non négligeable, style différent du vanilla moderne, moins nécessaire aujourd’hui.

Règle simple : on ne l’ajoute dans un nouveau projet que s’il y a une vraie raison.

x1.4 Référence de l’API jQuery

Consultez la documentation officielle de l’API jQuery.

À essayer (optionnel)

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-6/x1_jquery

Travaillez dans scripts.js. Suivez les commentaires. L’objectif est de sentir la différence de style, pas de devenir expert jQuery.

x2 Extra – Chart.js (exploration libre)

Le tronc commun reste 100 % vanilla. Cette piste est purement optionnelle.

Chart.js permet d’afficher rapidement un graphique sans framework ni outil de build.

x2.1 Chargement via CDN

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

Une seule balise. Le navigateur charge la bibliothèque.

x2.2 Un graphique minimal

Il faut un élément <canvas> et un peu de configuration.

const ctx = document.getElementById("myChart");

new Chart(ctx, {
  type: "bar",
  data: {
    labels: ["Jan", "Fév", "Mar", "Avr", "Mai"],
    datasets: [{
      label: "Experts autoproclamés se vantant de l’IA sur LinkedIn",
      data: [12, 19, 8, 15, 22]
    }]
  }
});

Les types les plus simples à essayer en premier : "bar" et "line".

x2.3 Objectif de cette exploration

Comprendre comment on intègre une bibliothèque utile avec un simple script CDN.

On ne cherche pas à maîtriser Chart.js en profondeur. On veut juste le faire fonctionner et voir le résultat.

Graphique en barres du nombre mensuel d’experts autoproclamés se vantant de l’IA sur LinkedIn.
Percentage of LinkedIn users who became AI experts by chatting with GPT in 2026.

x2.4 Référence de l’API Chart.js

Consultez la documentation officielle de Chart.js.

À essayer (optionnel)

Ouvrez le dossier
https://github.com/Dercetech/intro-to-js-6-days/tree/main/www/day-6/x2_chartjs

Travaillez dans scripts.js. Suivez les commentaires. Changez les données, essayez "line" à la place de "bar".

x3 Extra – Aperçu TypeScript (≈ 1 h)

Le tronc commun de la formation reste 100 % vanilla JavaScript.

TypeScript est un sur-ensemble de JavaScript.
Il ajoute des types statiques et un compilateur.
Le navigateur, lui, ne comprend que le JavaScript généré.

Le petit écureuil vert de Reactor 4, sain et sauf. Le petit écureuil vert de Reactor 4, fondu dans une flaque radioactive.
C’est une incitation mignonne à essayer TypeScript.

Essayez de faire fondre le petit héros de Reactor 4. Ce personnage est gracieusement prêté par Bad Sector Games. Prenez-en soin.

x3.1 Une exploration, pas un problème à résoudre

Le mini-projet est déjà complet. Lisez-le, compilez-le, modifiez-le.

Le jeu calcule une division. Si le diviseur vaut zéro, l’écureuil vert du Réacteur 4 fond sous l’effet des radiations. JavaScript retourne normalement Infinity. Le jeu applique une règle un peu plus stricte.

x3.2 Ce que contient le mini-projet

Un projet npm autonome se trouve ici :

extra/day6/extra3-typescript/

  • src/main.ts – une application TypeScript complète, avec types, interface et fonctions typées,
  • assets/ – les deux états graphiques de l’écureuil,
  • tsconfig.json – la configuration minimale du compilateur,
  • package.json – les scripts dev, build et serve.

Après npm run build, le dossier dist/ contient le JavaScript compilé, le HTML et une copie de assets/.

Le compilateur TypeScript ne copie pas les images. Le script copy s’en charge explicitement. Rien ne se téléporte dans dist/.

x3.3 Commandes essentielles

cd extra/day6/extra3-typescript
npm install
npm run dev          # compile en continu (watch)
npm run build        # compile et copie HTML + assets
npm run serve        # sert le contenu de dist/

À essayer (optionnel)

Ouvrez le dossier extra/day6/extra3-typescript dans votre éditeur.

Lancez npm run build, puis regardez le contenu de dist/. Les images doivent se trouver dans dist/assets/.

Lancez npm run serve. Essayez une division normale, puis une division par zéro. Regardez ensuite src/main.ts pour identifier les annotations, l’interface et le type union.

Récap — Refactoriser l’application de notes en modules

Le dernier défi part d’une application de notes complète et fonctionnelle. Votre objectif n’est pas d’ajouter une longue liste de fonctionnalités : vous allez réorganiser le code sans modifier son comportement.

Ouvrez le dossier Day6_redux dans le dépôt js-extra, puis démarrez la version lab.

Le contrat de refactorisation

  1. Extrayez les sélecteurs et calculs purs dans src/logic/notes.js.
  2. Déplacez l’état initial et le reducer dans src/state/reducer.js.
  3. Isolez la création du store et dispatch dans src/state/store.js.
  4. Isolez la persistance locale dans src/persistence/storage.js.
  5. Dans src/instrumentation/logger.js, créez un logger configurable puis une fonction qui reçoit dispatch et retourne un dispatch journalisé.
  6. Regroupez les références et le rendu du DOM dans src/view/view.js.
  7. Gardez src/app.js comme couche d’orchestration mince : imports, événements et démarrage.

Utilisez uniquement des imports relatifs explicites comme ./state/store.js. Après chaque extraction, vérifiez l’ajout, la sélection, la modification, la suppression, l’épinglage, la recherche, l’import/export et la persistance locale.

La persistance du récap utilise deux clés distinctes : day6_redux_notes et day6_redux_next_note_id.

Les preuves à recueillir dans DevTools

  • Dans Network, chaque module répond sans erreur inattendue.
  • Dans Sources, posez un breakpoint dans le reducer, une fonction pure et le rendu.
  • Dans l’inspecteur de l’application, comparez l’état précédent avec l’état actuel et suivez le journal des actions.
  • Rafraîchissez la page : les notes persistent et aucun gestionnaire ne produit une action en double.

Suivez le README.md pour lancer npm install, npm run dev puis npm run build. La version lab_solved montre une architecture possible ; comparez les responsabilités des modules plutôt que le nombre de lignes.