# Atelier 00 — JavaScript Moderne & ES Modules

> **Prérequis :** Notions de base HTML/CSS/JS (même rouillées)  
> **Durée estimée :** 1 à 2 jours  
> **Environnement :** Chrome, un éditeur de texte, un serveur local simple

---

## Pourquoi cet atelier existe

Les Web Components reposent entièrement sur des fonctionnalités ES6+ : classes, héritage, template literals, modules. Si ces concepts ne sont pas solides, tout ce qui vient ensuite sera flou.

Par ailleurs, l'approche **Vanilla Web sans bundler** que tu cibles implique une contrainte importante : les ES Modules ne fonctionnent pas via le protocole `file://`. Tu as besoin d'un serveur HTTP local dès le premier fichier JS que tu veux importer.

---

## 1. L'environnement de travail

### 1.1 Serveur local

Chrome bloque les ES Modules chargés en `file://` pour des raisons de sécurité (CORS). Tu as besoin d'un serveur HTTP minimal.

**Option recommandée — Python (disponible partout) :**

```bash
# Dans le dossier de ton projet
python3 -m http.server 3000
```

Puis ouvre `http://localhost:3000` dans Chrome.

**Option alternative — Extension VS Code :**  
[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) fait la même chose avec rechargement automatique.

### 1.2 Structure de projet type pour GitLab Pages

Chaque outil que tu créeras suivra cette structure. Apprends-la maintenant, elle sera utilisée dans tous les ateliers suivants.

```
mon-outil/
├── index.html
├── components/
│   └── (tes Web Components ici)
├── css/
│   └── global.css
└── .gitlab-ci.yml
```

**Le `.gitlab-ci.yml` minimal pour GitLab Pages :**

```yaml
pages:
  stage: deploy
  script:
    - echo "Deploying static files"
  artifacts:
    paths:
      - public
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
```

> **Note :** GitLab Pages exige que les fichiers soient dans un dossier `public/`. Adapte la structure en conséquence ou configure le CI pour copier.

**Référence :** [GitLab Pages — Getting Started](https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_from_scratch.html)

---

## 2. Classes JavaScript

Les Web Components sont des **classes qui héritent de `HTMLElement`**. Sans une compréhension solide des classes, tu seras bloqué dès l'atelier 1.

### Concept : class, constructor, extends, super

```js
class Animal {
  constructor(nom) {
    this.nom = nom;
  }

  parler() {
    return `${this.nom} fait un bruit.`;
  }
}

class Chien extends Animal {
  constructor(nom) {
    super(nom); // Obligatoire avant d'accéder à `this`
    this.pattes = 4;
  }

  parler() {
    return `${this.nom} aboie.`;
  }
}

const rex = new Chien('Rex');
console.log(rex.parler()); // "Rex aboie."
console.log(rex.pattes);   // 4
```

**Points clés :**
- `extends` crée une relation d'héritage
- `super()` appelle le constructeur de la classe parente — **obligatoire** dans le constructeur d'une classe enfant avant tout accès à `this`
- Une méthode redéfinie dans la classe enfant **remplace** celle du parent

### Concept : méthodes statiques

```js
class MaClasse {
  static creer(config) {
    return new MaClasse(config);
  }
}
```

Les méthodes statiques sont appelées sur la **classe** elle-même, pas sur une instance. Tu les rencontreras dans les Web Components avec `observedAttributes`.

---

## 3. Template Literals

Indispensables pour générer du HTML dans les Web Components.

```js
const titre = 'Monde';
const compte = 3;

// Interpolation simple
const html = `<h1>Bonjour ${titre}</h1>`;

// Expression quelconque
const msg = `Il y a ${compte * 2} éléments`;

// Multilignes (les sauts de ligne sont préservés)
const template = `
  <div class="card">
    <h2>${titre}</h2>
    <p>${msg}</p>
  </div>
`;
```

**Attention aux injections :** générer du HTML par interpolation directe de valeurs venant de l'utilisateur est une faille XSS. On y reviendra dans l'atelier 1.

---

## 4. Destructuring et Spread

Tu les verras dans des exemples de la communauté.

```js
// Destructuring objet
const { nom, age } = { nom: 'Alice', age: 30 };

// Destructuring avec renommage
const { nom: prenom } = { nom: 'Alice' };

// Destructuring tableau
const [premier, second] = [1, 2, 3];

// Spread
const base = { a: 1, b: 2 };
const etendu = { ...base, c: 3 };
```

---

## 5. ES Modules

C'est le cœur de l'approche Vanilla Web. Chaque composant vivra dans **son propre fichier**, importé là où c'est nécessaire.

### Exporter

```js
// components/mon-composant.js

// Export nommé
export class MonComposant extends HTMLElement { ... }

// Export par défaut (un seul par fichier)
export default class MonComposant extends HTMLElement { ... }
```

### Importer

```js
// index.html → <script type="module" src="main.js"></script>

// main.js
import { MonComposant } from './components/mon-composant.js';
import AutreComposant from './components/autre.js'; // import par défaut
```

### Chargement dans HTML

```html
<!-- CORRECT : type="module" est obligatoire -->
<script type="module" src="main.js"></script>

<!-- INCORRECT pour les modules : -->
<script src="main.js"></script>
```

**Comportements importants de `type="module"` :**
- Le script est **différé** automatiquement (équivalent à `defer`)
- Le scope est isolé — les variables ne polluent pas le scope global
- `"use strict"` est implicite
- Chaque module est chargé **une seule fois**, même si importé plusieurs fois

**Référence :** [MDN — JavaScript Modules](https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Modules)

---

## 6. Manipulation DOM moderne

Révision rapide des méthodes que tu utiliseras dans chaque composant.

```js
// Sélection
const el = document.querySelector('.ma-classe');
const tous = document.querySelectorAll('p');

// Création
const div = document.createElement('div');

// Attributs
el.getAttribute('data-id');
el.setAttribute('data-id', '42');
el.hasAttribute('disabled');
el.removeAttribute('disabled');

// Contenu
el.textContent = 'Texte pur (sûr)';
el.innerHTML = '<strong>HTML</strong>'; // attention XSS

// Classes
el.classList.add('active');
el.classList.remove('active');
el.classList.toggle('active');

// Événements
el.addEventListener('click', (event) => {
  console.log(event.target);
});
```

---

## Exercices

### Exercice 0.1 — Environnement

**Objectif :** Valider que ton environnement fonctionne avec des ES Modules.

Crée la structure suivante :

```
exercice-00/
├── index.html
└── utils.js
```

`utils.js` doit exporter une fonction `saluer(nom)` qui retourne la chaîne `"Bonjour, [nom] !"`.

`index.html` doit importer cette fonction et afficher le résultat dans un `<p>` au chargement.

**Critère de succès :** Ouvrir `http://localhost:3000/exercice-00/` affiche "Bonjour, Monde !" sans erreur dans la console.

---

> **Indice 1** — Si tu vois une erreur CORS ou un module non chargé, tu es probablement en `file://`. Lance ton serveur Python.

> **Indice 2** — La balise script dans `index.html` doit avoir l'attribut `type="module"` pour que `import` fonctionne.

> **Indice 3** — Le chemin dans `import` doit être **relatif et complet** : `'./utils.js'` et non `'./utils'` (sans extension, ça ne fonctionne pas sans bundler).

---

### Exercice 0.2 — Classes et héritage

**Objectif :** Solidifier la compréhension de `extends` et `super`.

Sans framework, dans un fichier `classes.js` :

1. Crée une classe `UIElement` avec un constructeur qui prend un `id` et une méthode `render()` qui retourne `"[UIElement: id]"`.
2. Crée une classe `Button` qui étend `UIElement`, ajoute une propriété `label`, et surcharge `render()` pour retourner `"[Button: id — label]"`.
3. Instancie un `Button` et affiche `render()` dans la console.

**Critère de succès :** Tu comprends pourquoi `super(id)` est nécessaire et ce qui se passerait sans.

---

> **Indice 1** — `extends` seul ne suffit pas. Dans le constructeur de `Button`, que faut-il appeler en premier avant d'écrire `this.label = ...` ?

> **Indice 2** — Essaie de retirer `super()` et observe l'erreur dans la console. L'erreur est explicite.

---

### Exercice 0.3 — Modules multi-fichiers

**Objectif :** Mettre en pratique l'organisation en modules, qui sera la norme dans tous tes outils.

Crée la structure :

```
exercice-03/
├── index.html
├── main.js
└── components/
    ├── header.js
    └── footer.js
```

- `header.js` exporte une fonction `renderHeader(titre)` qui retourne une chaîne HTML `<header><h1>titre</h1></header>`.
- `footer.js` exporte une fonction `renderFooter(annee)` qui retourne `<footer>© annee</footer>`.
- `main.js` importe les deux et injecte le résultat dans `document.body`.
- `index.html` ne charge que `main.js` via `<script type="module">`.

**Critère de succès :** La page s'affiche correctement, `index.html` ne contient aucun autre `<script>`.

---

> **Indice 1** — Dans `main.js`, utilise `document.body.insertAdjacentHTML('afterbegin', ...)` pour le header et `'beforeend'` pour le footer.

> **Indice 2** — Vérifie que les chemins d'import dans `main.js` correspondent exactement à la structure de dossiers (`./components/header.js`).

---

### Exercice 0.4 — Template Literals et DOM

**Objectif :** Pratiquer la génération de HTML dynamique, pattern central dans les Web Components.

Crée un tableau de données :

```js
const taches = [
  { id: 1, titre: 'Lire la doc MDN', faite: true },
  { id: 2, titre: 'Écrire mon premier composant', faite: false },
  { id: 3, titre: 'Déployer sur GitLab Pages', faite: false },
];
```

Génère une liste `<ul>` en HTML à partir de ce tableau (avec un `map` et un `join`) et injecte-la dans le DOM. Les tâches faites doivent avoir une classe CSS `done`.

**Critère de succès :** La liste s'affiche. Modifier le tableau en JS met à jour l'affichage après rechargement.

---

> **Indice 1** — `array.map(item => `...`).join('')` est l'idiome classique pour transformer un tableau en chaîne HTML.

> **Indice 2** — Pour la classe conditionnelle : `class="${tache.faite ? 'done' : ''}"` — le ternaire fonctionne dans les template literals.

---

## Checklist de sortie

Avant de passer à l'atelier 1, tu dois pouvoir répondre sans hésiter :

- [ ] Pourquoi `super()` est-il obligatoire avant `this` dans un constructeur enfant ?
- [ ] Quelle différence entre `export` et `export default` ?
- [ ] Pourquoi `<script src="...">` ne suffit pas pour les modules ?
- [ ] Comment lancer un serveur HTTP local sans Node.js ni bundler ?
- [ ] Qu'est-ce que `type="module"` change au comportement du script ?

---

## Références

| Sujet | URL |
|---|---|
| Classes JS | https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes |
| ES Modules | https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Modules |
| Template Literals | https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Template_literals |
| GitLab Pages | https://docs.gitlab.com/ee/user/project/pages/ |
| javascript.info — Classes | https://fr.javascript.info/classes |