Maîtrisez les concepts avancés de JavaScript moderne : ES6+, Async/Await, API REST, Modules, et techniques d'expert pour des applications complexes.
Maîtrisez les fonctionnalités modernes de JavaScript qui révolutionnent le développement web.
Syntaxe concise pour les fonctions avec bind automatique du this
.
// Fonction classique
function add(a, b) {
return a + b;
}
// Arrow function
const add = (a, b) => a + b;
// Array methods avec arrow functions
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
// This binding
class Counter {
constructor() {
this.count = 0;
}
// Arrow function préserve le this
increment = () => {
this.count++;
console.log(this.count);
}
}
Extraction élégante des données depuis objets et tableaux.
// Destructuring d'objet
const user = { name: 'John', age: 30, email: 'john@example.com' };
const { name, age, email } = user;
// Avec renommage et valeurs par défaut
const { name: userName, country = 'France' } = user;
// Destructuring de tableau
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// Destructuring en paramètres
function greet({ name, age }) {
return `Bonjour ${name}, vous avez ${age} ans`;
}
// Destructuring imbriqué
const response = {
data: {
users: [{ name: 'Alice' }, { name: 'Bob' }]
}
};
const { data: { users: [firstUser] } } = response;
Chaînes de caractères avancées avec interpolation et multilignes.
const name = 'John';
const age = 30;
// Interpolation simple
const message = `Bonjour ${name}, vous avez ${age} ans`;
// Expressions complexes
const price = 99.99;
const formatted = `Prix: ${(price * 1.2).toFixed(2)}€`;
// Multilignes
const html = `
${name}
Age: ${age}
`;
// Tagged template literals
function highlight(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] ? `${values[i]}` : '';
return result + string + value;
}, '');
}
const highlighted = highlight`Hello ${name}, welcome!`;
Opérateurs polyvalents pour manipulation de données.
// Spread operator avec tableaux
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
// Spread avec objets
const defaults = { theme: 'dark', lang: 'fr' };
const userSettings = { lang: 'en', fontSize: 14 };
const config = { ...defaults, ...userSettings };
// Rest parameters
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
// Rest dans destructuring
const [first, ...remaining] = [1, 2, 3, 4, 5];
const { name, ...otherProps } = user;
// Copie superficielle
const userCopy = { ...user };
const arrayClone = [...originalArray];
Syntaxe moderne pour la programmation orientée objet.
class User {
// Propriétés privées
#privateKey = 'secret';
constructor(name, email) {
this.name = name;
this.email = email;
}
// Méthode getter
get displayName() {
return `User: ${this.name}`;
}
// Méthode setter
set email(value) {
if (value.includes('@')) {
this._email = value;
}
}
// Méthode statique
static isValid(user) {
return user.name && user.email;
}
// Méthode privée
#validateKey() {
return this.#privateKey === 'secret';
}
}
// Héritage
class Admin extends User {
constructor(name, email, permissions) {
super(name, email);
this.permissions = permissions;
}
hasPermission(action) {
return this.permissions.includes(action);
}
}
Méthodes avancées pour Array, Object, String et plus.
// Array methods
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 30, active: false },
{ name: 'Carol', age: 35, active: true }
];
// find/findIndex
const activeUser = users.find(u => u.active);
const index = users.findIndex(u => u.name === 'Bob');
// includes
const hasAlice = users.some(u => u.name === 'Alice');
// Object methods
const entries = Object.entries(users[0]);
const keys = Object.keys(users[0]);
const values = Object.values(users[0]);
// Object.assign
const merged = Object.assign({}, defaults, options);
// Optional chaining (ES2020)
const userName = user?.profile?.name ?? 'Anonymous';
// Nullish coalescing
const theme = settings.theme ?? 'default';
Maîtrisez la programmation asynchrone moderne avec Promises, async/await et gestion d'erreurs.
Fondement de la programmation asynchrone en JavaScript.
// Création d'une Promise
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id, name: `User ${id}` });
} else {
reject(new Error('Invalid ID'));
}
}, 1000);
});
}
// Chaînage de Promises
fetchUser(1)
.then(user => {
console.log('User:', user);
return fetchUser(2);
})
.then(secondUser => {
console.log('Second user:', secondUser);
})
.catch(error => {
console.error('Error:', error.message);
})
.finally(() => {
console.log('Operation completed');
});
// Promise.all - Exécution parallèle
Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]).then(users => {
console.log('All users:', users);
});
Syntaxe synchrone pour code asynchrone - plus lisible et maintenable.
// Async function
async function getUser(id) {
try {
const user = await fetchUser(id);
console.log('User:', user);
return user;
} catch (error) {
console.error('Error:', error.message);
throw error;
}
}
// Appel séquentiel
async function getMultipleUsers() {
try {
const user1 = await fetchUser(1);
const user2 = await fetchUser(2);
return [user1, user2];
} catch (error) {
console.error('Failed to fetch users:', error);
}
}
// Appel parallèle avec await
async function getAllUsersParallel() {
try {
const users = await Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
]);
return users;
} catch (error) {
console.error('Some requests failed:', error);
}
}
Stratégies robustes pour gérer les erreurs asynchrones.
// Try/catch avec async/await
async function robustFetch(url) {
let retries = 3;
while (retries > 0) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
retries--;
if (retries === 0) {
console.error('Max retries reached:', error);
throw error;
}
// Attendre avant de réessayer
await new Promise(resolve =>
setTimeout(resolve, 1000)
);
}
}
}
// Promise.allSettled - Tolérance aux erreurs
async function fetchAllUsers(ids) {
const results = await Promise.allSettled(
ids.map(id => fetchUser(id))
);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
return { successful, failed };
}
Techniques d'expert pour l'asynchrone complexe.
// Async Generator
async function* fetchPages(baseUrl) {
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await fetch(`${baseUrl}?page=${page}`);
const data = await response.json();
yield data.items;
hasMore = data.hasNext;
page++;
}
}
// Utilisation
for await (const items of fetchPages('/api/users')) {
console.log('Page items:', items);
}
// Timeout avec Promise.race
async function fetchWithTimeout(url, timeout = 5000) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), timeout);
});
return Promise.race([
fetch(url),
timeoutPromise
]);
}
// Queue asynchrone
class AsyncQueue {
constructor(concurrency = 1) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
}
async add(asyncFn) {
return new Promise((resolve, reject) => {
this.queue.push({
asyncFn,
resolve,
reject
});
this.process();
});
}
async process() {
if (this.running >= this.concurrency || this.queue.length === 0) {
return;
}
this.running++;
const { asyncFn, resolve, reject } = this.queue.shift();
try {
const result = await asyncFn();
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.process();
}
}
}
Maîtrisez les API REST : Fetch avancé, authentification, gestion d'état et architecture.
Maîtrise complète de l'API Fetch moderne.
// Configuration avancée
const apiConfig = {
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
// Classe API wrapper
class ApiClient {
constructor(config) {
this.config = config;
this.token = localStorage.getItem('authToken');
}
async request(endpoint, options = {}) {
const url = `${this.config.baseURL}${endpoint}`;
const config = {
...options,
headers: {
...this.config.headers,
...options.headers,
...(this.token && {
Authorization: `Bearer ${this.token}`
})
}
};
const response = await fetch(url, config);
if (!response.ok) {
throw new ApiError(response.status, response.statusText);
}
return response.json();
}
// Méthodes CRUD
get(endpoint) {
return this.request(endpoint);
}
post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
put(endpoint, data) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
});
}
delete(endpoint) {
return this.request(endpoint, {
method: 'DELETE'
});
}
}
Gestion sécurisée de l'authentification et des tokens.
class AuthManager {
constructor() {
this.token = localStorage.getItem('authToken');
this.refreshToken = localStorage.getItem('refreshToken');
}
async login(credentials) {
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
});
if (!response.ok) {
throw new Error('Login failed');
}
const { token, refreshToken, user } = await response.json();
this.setTokens(token, refreshToken);
return { user, token };
} catch (error) {
console.error('Login error:', error);
throw error;
}
}
setTokens(token, refreshToken) {
this.token = token;
this.refreshToken = refreshToken;
localStorage.setItem('authToken', token);
localStorage.setItem('refreshToken', refreshToken);
}
async refreshAuthToken() {
if (!this.refreshToken) {
throw new Error('No refresh token available');
}
try {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
refreshToken: this.refreshToken
})
});
const { token } = await response.json();
this.setTokens(token, this.refreshToken);
return token;
} catch (error) {
this.logout();
throw error;
}
}
logout() {
this.token = null;
this.refreshToken = null;
localStorage.removeItem('authToken');
localStorage.removeItem('refreshToken');
}
isAuthenticated() {
return !!this.token && !this.isTokenExpired();
}
isTokenExpired() {
if (!this.token) return true;
try {
const payload = JSON.parse(atob(this.token.split('.')[1]));
return payload.exp * 1000 < Date.now();
} catch {
return true;
}
}
}
Gestion intelligente du cache et de l'état des données.
class DataManager {
constructor() {
this.cache = new Map();
this.loading = new Set();
this.subscribers = new Map();
}
async getData(key, fetcher, ttl = 300000) {
// Si en cours de chargement, attendre
if (this.loading.has(key)) {
return this.waitForData(key);
}
// Vérifier le cache
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.data;
}
// Charger les données
this.loading.add(key);
try {
const data = await fetcher();
this.cache.set(key, {
data,
timestamp: Date.now()
});
this.notifySubscribers(key, data);
return data;
} finally {
this.loading.delete(key);
}
}
subscribe(key, callback) {
if (!this.subscribers.has(key)) {
this.subscribers.set(key, new Set());
}
this.subscribers.get(key).add(callback);
return () => {
const subs = this.subscribers.get(key);
if (subs) {
subs.delete(callback);
}
};
}
notifySubscribers(key, data) {
const subscribers = this.subscribers.get(key);
if (subscribers) {
subscribers.forEach(callback => callback(data));
}
}
invalidateCache(pattern) {
if (typeof pattern === 'string') {
this.cache.delete(pattern);
} else if (pattern instanceof RegExp) {
for (const [key] of this.cache) {
if (pattern.test(key)) {
this.cache.delete(key);
}
}
}
}
}
WebSockets et Server-Sent Events pour données temps réel.
class RealtimeManager {
constructor(url) {
this.url = url;
this.ws = null;
this.listeners = new Map();
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket connected');
this.reconnectAttempts = 0;
};
this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
this.handleMessage(data);
} catch (error) {
console.error('Invalid message format:', error);
}
};
this.ws.onclose = () => {
console.log('WebSocket disconnected');
this.attemptReconnect();
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
}
subscribe(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(callback);
return () => {
const eventListeners = this.listeners.get(event);
if (eventListeners) {
eventListeners.delete(callback);
}
};
}
emit(event, data) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ event, data }));
}
}
handleMessage({ event, data }) {
const listeners = this.listeners.get(event);
if (listeners) {
listeners.forEach(callback => callback(data));
}
}
attemptReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = Math.pow(2, this.reconnectAttempts) * 1000;
setTimeout(() => {
console.log(`Reconnecting... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
this.connect();
}, delay);
}
}
disconnect() {
if (this.ws) {
this.ws.close();
}
}
}
Architecture modulaire moderne : Import/Export, bundling, et organisation du code.
Différentes façons d'exporter des fonctionnalités.
// utils.js - Named exports
export function formatDate(date) {
return date.toLocaleDateString('fr-FR');
}
export const API_BASE_URL = 'https://api.example.com';
export class Logger {
static log(message) {
console.log(`[${new Date().toISOString()}] ${message}`);
}
}
// Export en fin de fichier
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
function applyDiscount(total, discount) {
return total * (1 - discount);
}
export { calculateTotal, applyDiscount };
// user.js - Default export
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
getDisplayName() {
return `${this.name} (${this.email})`;
}
}
export default User;
// Mixed exports
export { User as DefaultUser };
export const USER_ROLES = ['admin', 'user', 'guest'];
Techniques d'importation flexibles et optimisées.
// Import nommés
import { formatDate, Logger, API_BASE_URL } from './utils.js';
// Import avec renommage
import { calculateTotal as getTotal, applyDiscount } from './utils.js';
// Import default
import User from './user.js';
// Import mixte
import User, { USER_ROLES } from './user.js';
// Import tout
import * as Utils from './utils.js';
Utils.formatDate(new Date());
// Import dynamique
async function loadModule() {
const { default: User } = await import('./user.js');
return new User('John', 'john@example.com');
}
// Import conditionnel
if (process.env.NODE_ENV === 'development') {
const devTools = await import('./dev-tools.js');
devTools.enableDebugMode();
}
// Re-export
// index.js
export { formatDate, Logger } from './utils.js';
export { default as User } from './user.js';
export * from './constants.js';
// Tree shaking friendly
import { debounce } from 'lodash-es'; // Seul debounce sera inclus
Organisation et architecture des modules d'une application.
// Structure recommandée
src/
├── components/
│ ├── ui/
│ │ ├── Button.js
│ │ ├── Modal.js
│ │ └── index.js
│ ├── forms/
│ │ ├── LoginForm.js
│ │ └── ContactForm.js
│ └── index.js
├── services/
│ ├── api/
│ │ ├── auth.js
│ │ ├── users.js
│ │ └── index.js
│ ├── storage.js
│ └── index.js
├── utils/
│ ├── date.js
│ ├── validation.js
│ └── index.js
├── constants/
│ ├── api.js
│ ├── app.js
│ └── index.js
└── main.js
// components/index.js - Barrel export
export { Button } from './ui/Button.js';
export { Modal } from './ui/Modal.js';
export { LoginForm } from './forms/LoginForm.js';
export { ContactForm } from './forms/ContactForm.js';
// services/index.js
export * as auth from './api/auth.js';
export * as users from './api/users.js';
export { StorageManager } from './storage.js';
// main.js - Point d'entrée
import { Button, Modal } from './components/index.js';
import { auth, StorageManager } from './services/index.js';
import { formatDate } from './utils/index.js';
Techniques avancées pour l'optimisation et le bundling.
// Dynamic imports pour code splitting
class ComponentLoader {
static async loadComponent(name) {
const components = {
'user-profile': () => import('./components/UserProfile.js'),
'admin-panel': () => import('./components/AdminPanel.js'),
'dashboard': () => import('./components/Dashboard.js')
};
const loader = components[name];
if (!loader) {
throw new Error(`Component ${name} not found`);
}
const module = await loader();
return module.default;
}
}
// Lazy loading avec cache
const componentCache = new Map();
async function lazyLoad(componentName) {
if (componentCache.has(componentName)) {
return componentCache.get(componentName);
}
const component = await ComponentLoader.loadComponent(componentName);
componentCache.set(componentName, component);
return component;
}
// Web Workers avec modules
// worker.js
import { processData } from './utils/data-processor.js';
self.onmessage = async function(e) {
const { data, options } = e.data;
const result = await processData(data, options);
self.postMessage(result);
};
// main.js
const worker = new Worker('./worker.js', { type: 'module' });
worker.postMessage({ data: largeDataset, options: {} });
// Service Worker avec modules
// sw.js
import { CacheManager } from './cache-manager.js';
const cacheManager = new CacheManager();
self.addEventListener('fetch', async (event) => {
event.respondWith(cacheManager.handleRequest(event.request));
});
Patterns avancés, optimisations performance et techniques d'expert pour applications complexes.
Patterns essentiels pour architectures robustes.
// Singleton Pattern
class AppConfig {
constructor() {
if (AppConfig.instance) {
return AppConfig.instance;
}
this.settings = new Map();
AppConfig.instance = this;
}
static getInstance() {
return new AppConfig();
}
}
// Observer Pattern
class EventEmitter {
constructor() {
this.events = new Map();
}
on(event, callback) {
if (!this.events.has(event)) {
this.events.set(event, new Set());
}
this.events.get(event).add(callback);
return () => this.off(event, callback);
}
emit(event, data) {
const callbacks = this.events.get(event);
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
off(event, callback) {
const callbacks = this.events.get(event);
if (callbacks) {
callbacks.delete(callback);
}
}
}
// Factory Pattern
class ComponentFactory {
static create(type, props) {
const components = {
'button': () => new Button(props),
'input': () => new Input(props),
'modal': () => new Modal(props)
};
const creator = components[type];
if (!creator) {
throw new Error(`Unknown component type: ${type}`);
}
return creator();
}
}
Techniques de performance et optimisation mémoire.
// Memoization
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const expensiveCalculation = memoize((n) => {
// Calcul coûteux
return n * n * n;
});
// Debounce & Throttle
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// WeakMap pour éviter fuites mémoire
const privateData = new WeakMap();
class User {
constructor(name, email) {
privateData.set(this, {
name,
email,
loginCount: 0
});
}
getName() {
return privateData.get(this).name;
}
incrementLogin() {
const data = privateData.get(this);
data.loginCount++;
}
}
Approches fonctionnelles modernes en JavaScript.
// Curry & Partial Application
const curry = (fn) => {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function(...nextArgs) {
return curried.apply(this, [...args, ...nextArgs]);
};
};
};
const add = curry((a, b, c) => a + b + c);
const addTen = add(10);
const addTenAndFive = addTen(5);
console.log(addTenAndFive(3)); // 18
// Composition de fonctions
const compose = (...fns) => (value) =>
fns.reduceRight((acc, fn) => fn(acc), value);
const pipe = (...fns) => (value) =>
fns.reduce((acc, fn) => fn(acc), value);
// Example d'utilisation
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 30, active: false },
{ name: 'Carol', age: 35, active: true }
];
const processUsers = pipe(
users => users.filter(user => user.active),
users => users.map(user => ({ ...user, ageGroup: user.age < 30 ? 'young' : 'adult' })),
users => users.sort((a, b) => a.name.localeCompare(b.name))
);
const result = processUsers(users);
// Immutable updates
const updateUser = (user, updates) => ({
...user,
...updates,
updatedAt: new Date()
});
// Lens pattern pour deep updates
const lens = (path) => {
const getter = (obj) => path.reduce((current, key) => current?.[key], obj);
const setter = (obj, value) => {
const clone = structuredClone(obj);
let current = clone;
for (let i = 0; i < path.length - 1; i++) {
current = current[path[i]];
}
current[path[path.length - 1]] = value;
return clone;
};
return { get: getter, set: setter };
};
Meta-programmation avancée avec Proxy et Reflect.
// Validation avec Proxy
function createValidatedObject(schema) {
return new Proxy({}, {
set(target, property, value) {
const validator = schema[property];
if (validator && !validator(value)) {
throw new Error(`Invalid value for ${property}: ${value}`);
}
return Reflect.set(target, property, value);
},
get(target, property) {
if (property in target) {
return Reflect.get(target, property);
}
throw new Error(`Property ${property} does not exist`);
}
});
}
// Utilisation
const userSchema = {
name: value => typeof value === 'string' && value.length > 0,
age: value => typeof value === 'number' && value >= 0,
email: value => typeof value === 'string' && value.includes('@')
};
const user = createValidatedObject(userSchema);
// Observable avec Proxy
function createObservable(target, onChange) {
return new Proxy(target, {
set(obj, property, value) {
const oldValue = obj[property];
const result = Reflect.set(obj, property, value);
if (oldValue !== value) {
onChange(property, value, oldValue);
}
return result;
}
});
}
const state = createObservable({}, (property, newValue, oldValue) => {
console.log(`${property} changed from ${oldValue} to ${newValue}`);
});
// API fluide avec Proxy
function createFluentAPI() {
const operations = [];
return new Proxy({}, {
get(target, property) {
if (property === 'execute') {
return () => operations.reduce((result, op) => op(result), null);
}
return (...args) => {
operations.push(data => ({
...data,
[property]: args.length === 1 ? args[0] : args
}));
return target;
};
}
});
}
// Utilisation
const query = createFluentAPI();
const result = query
.select('name', 'email')
.where('age', '>', 18)
.limit(10)
.execute();
Mettez en pratique vos connaissances avec ces exercices progressifs de complexité croissante.
ApiManager
complèteclass ApiManager {
constructor(config) {
// Configuration : baseURL, timeout, headers
// Cache : Map avec TTL
// Auth : tokens, refresh logic
// Events : EventEmitter
}
// Authentification
async login(credentials) { /* ... */ }
async refreshToken() { /* ... */ }
logout() { /* ... */ }
// Requêtes CRUD
async get(endpoint, options) { /* ... */ }
async post(endpoint, data, options) { /* ... */ }
async put(endpoint, data, options) { /* ... */ }
async delete(endpoint, options) { /* ... */ }
// Gestion cache
getCached(key) { /* ... */ }
setCache(key, data, ttl) { /* ... */ }
invalidateCache(pattern) { /* ... */ }
// Utilitaires
async request(config) { /* ... */ }
addInterceptor(type, handler) { /* ... */ }
}
💡 Conseil : Commencez par la structure de base, puis ajoutez progressivement chaque fonctionnalité. Testez chaque partie avant de passer à la suivante.
const store = new StateManager({
modules: {
user: {
state: { profile: null, loading: false },
mutations: {
SET_LOADING(state, loading) {
state.loading = loading;
},
SET_PROFILE(state, profile) {
state.profile = profile;
}
},
actions: {
async fetchProfile({ commit }, userId) {
commit('SET_LOADING', true);
try {
const profile = await api.get(`/users/${userId}`);
commit('SET_PROFILE', profile);
} finally {
commit('SET_LOADING', false);
}
}
},
getters: {
isLoggedIn: state => !!state.profile,
userName: state => state.profile?.name || 'Guest'
}
}
},
plugins: [persistencePlugin, loggingPlugin]
});
// Utilisation
store.dispatch('user/fetchProfile', 123);
store.subscribe(state => updateUI(state));
const microFrontendLoader = new MicroFrontendLoader({
registry: 'https://registry.example.com',
container: '#app-container',
sandbox: true
});
// Configuration des micro-frontends
await microFrontendLoader.register([
{
name: 'header',
url: 'https://header.example.com/bundle.js',
mount: '#header',
props: { user: currentUser }
},
{
name: 'dashboard',
url: 'https://dashboard.example.com/bundle.js',
mount: '#main-content',
route: '/dashboard/*'
}
]);
// Communication entre modules
microFrontendLoader.on('user-updated', (user) => {
microFrontendLoader.broadcast('user-changed', user);
});
// Chargement conditionnel
if (userRole === 'admin') {
await microFrontendLoader.load('admin-panel');
}
🎯 Challenge : Cet exercice vous prépare aux architectures modernes de grandes applications. Concentrez-vous sur l'isolation et la communication entre modules.