APIs dépréciées
À éviter
// ❌ document.write (bloque le parsing)
document.write('<script src="..."></script>');
// ✅ Chargement dynamique de script
const script = document.createElement('script');
script.src = '...';
document.head.appendChild(script);
// ❌ XHR synchrone (bloque le thread principal)
const xhr = new XMLHttpRequest();
xhr.open('GET', url, false); // false = synchrone
// ✅ Fetch asynchrone
const response = await fetch(url);
// ❌ Application Cache (déprécié)
<html manifest="cache.manifest">
// ✅ Service Workers
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Event listener passif
// ❌ Touch/wheel non-passif (peut bloquer le scroll)
element.addEventListener('touchstart', handler);
element.addEventListener('wheel', handler);
// ✅ Listeners passifs (permet un scroll fluide)
element.addEventListener('touchstart', handler, { passive: true });
element.addEventListener('wheel', handler, { passive: true });
// ✅ Si vous avez besoin de preventDefault, soyez explicite
element.addEventListener('touchstart', handler, { passive: false });
Console et erreurs
Aucune erreur en console
// ❌ Erreurs en production
console.log('Debug info'); // Supprimer en production
throw new Error('Unhandled'); // Attraper toutes les erreurs
// ✅ Gestion d'erreur appropriée
try {
riskyOperation();
} catch (error) {
// Envoyer vers un service de suivi des erreurs
errorTracker.captureException(error);
// Afficher un message convivial
showErrorMessage('Something went wrong. Please try again.');
}
Limites d'erreur (React)
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
errorTracker.captureException(error, { extra: info });
}
render() {
if (this.state.hasError) {
return <FallbackUI />;
}
return this.props.children;
}
}
// Utilisation
<ErrorBoundary>
<App />
</ErrorBoundary>
Gestionnaire d'erreur global
// Attraper les erreurs non gérées
window.addEventListener('error', (event) => {
errorTracker.captureException(event.error);
});
// Attraper les rejets de promise non gérés
window.addEventListener('unhandledrejection', (event) => {
errorTracker.captureException(event.reason);
});
Source maps
Configuration pour la production
// ❌ Source maps exposées en production
// webpack.config.js
module.exports = {
devtool: 'source-map', // Expose le code source
};
// ✅ Source maps cachées (téléchargées vers le suivi des erreurs)
module.exports = {
devtool: 'hidden-source-map',
};
// ✅ Ou pas de source maps en production
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
};
Bonnes pratiques de performance
Éviter les motifs bloquants
// ❌ Script bloquant
<script src="heavy-library.js"></script>
// ✅ Script différé
<script defer src="heavy-library.js"></script>
// ❌ Import CSS bloquant
@import url('other-styles.css');
// ✅ Balises link (chargement parallèle)
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="other-styles.css">
Gestionnaires d'événement efficaces
// ❌ Gestionnaire sur chaque élément
items.forEach(item => {
item.addEventListener('click', handleClick);
});
// ✅ Délégation d'événement
container.addEventListener('click', (e) => {
if (e.target.matches('.item')) {
handleClick(e);
}
});
Gestion de la mémoire
// ❌ Fuite mémoire (jamais supprimé)
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);
// ✅ Nettoyage quand terminé
const handler = () => { /* ... */ };
window.addEventListener('resize', handler);
// Plus tard, lors du démontage du composant :
window.removeEventListener('resize', handler);
// ✅ En utilisant AbortController
const controller = new AbortController();
window.addEventListener('resize', handler, { signal: controller.signal });
// Nettoyage :
controller.abort();
Qualité du code
HTML valide
<!-- ❌ HTML invalide -->
<div id="header">
<div id="header"> <!-- ID dupliqué -->
<ul>
<div>Item</div> <!-- Enfant invalide -->
</ul>
<a href="/"><button>Click</button></a> <!-- Imbrication invalide -->
<!-- ✅ HTML valide -->
<header id="site-header">
</header>
<ul>
<li>Item</li>
</ul>
<a href="/" class="button">Click</a>
HTML sémantique
<!-- ❌ Non-sémantique -->
<div class="header">
<div class="nav">
<div class="nav-item">Home</div>
</div>
</div>
<div class="main">
<div class="article">
<div class="title">Headline</div>
</div>
</div>
<!-- ✅ HTML5 sémantique -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Headline</h1>
</article>
</main>
Rapports d'aspect des images
<!-- ❌ Images déformées -->
<img src="photo.jpg" width="300" height="100">
<!-- Si le rapport réel est 4:3, cela compresse l'image -->
<!-- ✅ Préserver le rapport d'aspect -->
<img src="photo.jpg" width="300" height="225">
<!-- Dimensions réelles 4:3 -->
<!-- ✅ CSS object-fit pour plus de flexibilité -->
<img src="photo.jpg" style="width: 300px; height: 200px; object-fit: cover;">
Permissions et confidentialité
Demander les permissions correctement
// ❌ Demander au chargement de la page (mauvaise UX, souvent refusé)
navigator.geolocation.getCurrentPosition(success, error);
// ✅ Demander en contexte, après une action utilisateur
findNearbyButton.addEventListener('click', async () => {
// Expliquer pourquoi vous en avez besoin
if (await showPermissionExplanation()) {
navigator.geolocation.getCurrentPosition(success, error);
}
});
Politique de permissions
<!-- Restreindre les fonctionnalités puissantes -->
<meta http-equiv="Permissions-Policy"
content="geolocation=(), camera=(), microphone=()">
<!-- Ou autoriser pour des origines spécifiques -->
<meta http-equiv="Permissions-Policy"
content="geolocation=(self 'https://maps.example.com')">
Liste de vérification d'audit
Sécurité (critique)
- [ ] HTTPS activé, aucun contenu mixte
- [ ] Aucune dépendance vulnérable (
npm audit)
- [ ] En-têtes CSP configurés
- [ ] En-têtes de sécurité présents
- [ ] Aucune source map exposée
Compatibilité
- [ ] Doctype HTML5 valide
- [ ] Charset déclaré en premier dans head
- [ ] Balise meta viewport présente
- [ ] Aucune API dépréciée utilisée
- [ ] Event listeners passifs pour scroll/touch
Qualité du code
- [ ] Aucune erreur en console
- [ ] HTML valide (aucun ID dupliqué)
- [ ] Éléments HTML sémantiques utilisés
- [ ] Gestion d'erreur appropriée
- [ ] Nettoyage de mémoire dans les composants
UX
- [ ] Aucun interstitiel intrusif
- [ ] Demandes de permission en contexte
- [ ] Messages d'erreur clairs
- [ ] Rapports d'aspect d'image appropriés
Outils
Références