# Chapitre 4 : Modules ES6 ## Introduction Les modules ES6 permettent d'organiser le code en fichiers séparés, avec un système d'import/export explicite. En PHP, vous utilisez `require`, `include`, ou l'autoloading PSR-4. En JavaScript moderne, on utilise `import` et `export`. ## Export ### Export nommé (Named Export) Permet d'exporter plusieurs éléments depuis un fichier : ```javascript // utils/math.js // Export à la déclaration export const PI = 3.14159; export function add(a, b) { return a + b; } export const multiply = (a, b) => a * b; // OU export groupé à la fin const PI = 3.14159; function add(a, b) { return a + b; } const multiply = (a, b) => a * b; export { PI, add, multiply }; ``` ### Export par défaut (Default Export) Un seul export par défaut par fichier. Généralement utilisé pour le composant/classe principal : ```javascript // components/Button.jsx const Button = ({ label, onClick }) => { return ; }; export default Button; // OU directement export default function Button({ label, onClick }) { return ; } ``` ### Mélange des deux ```javascript // services/api.js // Export par défaut : le client API principal const apiClient = { get: (url) => fetch(url).then(r => r.json()), post: (url, data) => fetch(url, { method: 'POST', body: JSON.stringify(data) }) }; // Exports nommés : utilitaires export const API_URL = "https://api.example.com"; export const handleError = (error) => console.error(error); export default apiClient; ``` ## Import ### Import nommé ```javascript // Importer des exports nommés (accolades obligatoires) import { add, multiply } from './utils/math.js'; import { PI } from './utils/math.js'; // Renommer à l'import import { add as addition } from './utils/math.js'; // Importer tout sous un namespace import * as MathUtils from './utils/math.js'; // Utilisation : MathUtils.add(1, 2), MathUtils.PI ``` ### Import par défaut ```javascript // Importer l'export par défaut (pas d'accolades) import Button from './components/Button.jsx'; // Le nom est libre (pas lié au nom dans le fichier source) import MonBouton from './components/Button.jsx'; // OK ``` ### Import mixte ```javascript // Default + named dans le même import import apiClient, { API_URL, handleError } from './services/api.js'; ``` ## Chemins d'import ### Chemins relatifs ```javascript // Même dossier import { helper } from './helper.js'; // Dossier parent import { config } from '../config.js'; // Sous-dossier import Button from './components/Button.jsx'; ``` ### Imports de packages (node_modules) ```javascript // Packages npm - pas de chemin relatif import React from 'react'; import { useState, useEffect } from 'react'; import axios from 'axios'; ``` ### Alias de chemins (Vite/Webpack) SmartMaker configure un alias `src` : ```javascript // Sans alias (chemins relatifs fragiles) import Button from '../../../components/Button.jsx'; // Avec alias (plus propre) import Button from 'src/components/Button.jsx'; ``` Configuration dans `vite.config.js` : ```javascript export default defineConfig({ resolve: { alias: { 'src': '/src' } } }); ``` ## Comparaison avec PHP ```php // PHP - autoloading PSR-4 namespace App\Services; use App\Models\User; use App\Utils\Helper; class UserService { // ... } ``` ```javascript // JavaScript ES6 import User from 'src/models/User.js'; import { formatDate } from 'src/utils/helper.js'; export default class UserService { // ... } ``` ^ PHP ^ JavaScript ^ | `namespace` | Pas d'équivalent direct (le fichier = le module) | | `use App\Class` | `import Class from 'path'` | | `new Class()` | `new Class()` ou composant `` | | Autoloading | Bundler (Vite/Webpack) résout les imports | ## Organisation des fichiers React ### Structure typique SmartMaker ``` src/ ├── components/ │ ├── app/ # Providers, Router │ │ ├── SmartCommonProvider/ │ │ │ └── index.jsx # export default SmartCommonProvider │ │ └── Router/ │ │ └── index.jsx │ │ │ ├── pages/ │ │ ├── public/ │ │ │ └── LoginPage/ │ │ │ └── index.jsx │ │ └── private/ │ │ └── HomePage/ │ │ └── index.jsx │ │ │ └── common/ │ ├── Button/ │ │ └── index.jsx │ └── Card/ │ └── index.jsx │ ├── hooks/ │ └── useAuth.js │ ├── services/ │ └── api.js │ └── utils/ └── format.js ``` ### Convention : index.jsx Quand un dossier contient `index.jsx`, on peut importer le dossier directement : ```javascript // Ces deux imports sont équivalents import Button from './components/common/Button/index.jsx'; import Button from './components/common/Button'; ``` ### Fichier barrel (re-export) Un fichier qui re-exporte plusieurs modules : ```javascript // components/common/index.js export { default as Button } from './Button'; export { default as Card } from './Card'; export { default as Modal } from './Modal'; // Utilisation import { Button, Card, Modal } from 'src/components/common'; ``` ## Import dynamique Pour le code-splitting (chargement à la demande) : ```javascript // Import statique (chargé au démarrage) import HeavyComponent from './HeavyComponent'; // Import dynamique (chargé quand nécessaire) const HeavyComponent = React.lazy(() => import('./HeavyComponent')); // Utilisation avec Suspense }> ``` ## Exercices ### Exercice 1 : Créer un module Créer un fichier `utils/string.js` qui exporte : - Une constante `DEFAULT_LOCALE = "fr-FR"` - Une fonction `capitalize(str)` qui met la première lettre en majuscule - Une fonction par défaut `formatName(firstName, lastName)` qui retourne "LASTNAME Firstname" **Solution :** ```javascript // utils/string.js export const DEFAULT_LOCALE = "fr-FR"; export function capitalize(str) { if (!str) return ''; return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); } export default function formatName(firstName, lastName) { return `${lastName.toUpperCase()} ${capitalize(firstName)}`; } ``` ### Exercice 2 : Importer le module Importer et utiliser le module créé : ```javascript // app.js // 1. Importer formatName (default) // 2. Importer capitalize et DEFAULT_LOCALE (named) // 3. Afficher formatName("jean", "dupont") // 4. Afficher capitalize("bonjour") ``` **Solution :** ```javascript // app.js import formatName, { capitalize, DEFAULT_LOCALE } from './utils/string.js'; console.log(formatName("jean", "dupont")); // "DUPONT Jean" console.log(capitalize("bonjour")); // "Bonjour" console.log(DEFAULT_LOCALE); // "fr-FR" ``` ## Points clés à retenir 1. **Export nommé** : `export const x` ou `export { x, y }` 2. **Export default** : `export default X` (un seul par fichier) 3. **Import nommé** : `import { x, y } from './file'` (accolades) 4. **Import default** : `import X from './file'` (pas d'accolades) 5. **Alias** : `import { x as alias } from './file'` 6. **Tout importer** : `import * as Module from './file'` 7. **index.jsx** : permet `import X from './folder'` ## Récapitulatif du Module 1 Vous avez maintenant les bases JavaScript ES6+ nécessaires pour React : ^ Concept ^ Syntaxe ^ | Variables | `const`, `let` | | Déstructuration | `const { a, b } = obj` | | Spread | `{ ...obj }`, `[...arr]` | | Arrow functions | `(x) => x * 2` | | Paramètres défaut | `(x = 10) => ...` | | Template literals | `` `Hello ${name}` `` | | Promises | `.then()`, `.catch()` | | async/await | `async function`, `await` | | Modules | `import`, `export` | [[:15_training:module1-javascript-es6:asynchrone|← Chapitre précédent]] | [[:15_training:module1-javascript-es6:start|Retour au module]] | [[:15_training:module2-introduction-react:start|Module suivant : Introduction à React →]]