Mise à jour des dépendances
Maîtrisez les mises à jour majeures de dépendances, l'analyse de compatibilité, les stratégies de mise à niveau échelonnées et les approches de test complètes.
Quand utiliser cette compétence
- Mettre à niveau les versions majeures de frameworks
- Mettre à jour les dépendances vulnérables à la sécurité
- Moderniser les dépendances héritées
- Résoudre les conflits de dépendances
- Planifier les chemins de mise à niveau progressifs
- Tester les matrices de compatibilité
- Automatiser les mises à jour de dépendances
Révision du versionnage sémantique
MAJOR.MINOR.PATCH (p. ex., 2.3.1)
MAJOR : changements incompatibles
MINOR : nouvelles fonctionnalités, rétrocompatible
PATCH : corrections de bogues, rétrocompatible
^2.3.1 = >=2.3.1 <3.0.0 (mises à jour mineures)
~2.3.1 = >=2.3.1 <2.4.0 (mises à jour de patch)
2.3.1 = version exacte
Analyse des dépendances
Audit des dépendances
# npm
npm outdated
npm audit
npm audit fix
# yarn
yarn outdated
yarn audit
# Vérifier les mises à jour majeures
npx npm-check-updates
npx npm-check-updates -u # Mettre à jour package.json
Analyser l'arborescence des dépendances
# Voir pourquoi un package est installé
npm ls package-name
yarn why package-name
# Trouver les packages en doublon
npm dedupe
yarn dedupe
# Visualiser les dépendances
npx madge --image graph.png src/
Matrice de compatibilité
// compatibility-matrix.js
const compatibilityMatrix = {
react: {
"16.x": {
"react-dom": "^16.0.0",
"react-router-dom": "^5.0.0",
"@testing-library/react": "^11.0.0",
},
"17.x": {
"react-dom": "^17.0.0",
"react-router-dom": "^5.0.0 || ^6.0.0",
"@testing-library/react": "^12.0.0",
},
"18.x": {
"react-dom": "^18.0.0",
"react-router-dom": "^6.0.0",
"@testing-library/react": "^13.0.0",
},
},
};
function checkCompatibility(packages) {
// Valider les versions des packages par rapport à la matrice
}
Stratégie de mise à niveau échelonnée
Phase 1 : Planification
# 1. Identifier les versions actuelles
npm list --depth=0
# 2. Vérifier les changements incompatibles
# Lire CHANGELOG.md et MIGRATION.md
# 3. Créer un plan de mise à niveau
echo "Ordre de mise à niveau :
1. TypeScript
2. React
3. React Router
4. Bibliothèques de test
5. Outils de build" > UPGRADE_PLAN.md
Phase 2 : Mises à jour progressives
# Ne pas tout mettre à niveau d'un coup !
# Étape 1 : Mettre à niveau TypeScript
npm install typescript@latest
# Tester
npm run test
npm run build
# Étape 2 : Mettre à niveau React (une version majeure à la fois)
npm install react@17 react-dom@17
# Tester à nouveau
npm run test
# Étape 3 : Continuer avec d'autres packages
npm install react-router-dom@6
# Et ainsi de suite...
Phase 3 : Validation
// tests/compatibility.test.js
describe("Compatibilité des dépendances", () => {
it("devrait avoir des versions React compatibles", () => {
const reactVersion = require("react/package.json").version;
const reactDomVersion = require("react-dom/package.json").version;
expect(reactVersion).toBe(reactDomVersion);
});
it("ne devrait pas avoir d'avertissements de peer dependency", () => {
// Exécuter npm ls et vérifier les avertissements
});
});
Gestion des changements incompatibles
Identifier les changements incompatibles
# Vérifier le changelog directement
curl https://raw.githubusercontent.com/facebook/react/master/CHANGELOG.md
Codemod pour les corrections automatisées
# Exécuter jscodeshift avec l'URL de transformation
npx jscodeshift -t <transform-url> <path>
# Exemple : Renommer les méthodes de cycle de vie non sûres
npx jscodeshift -t https://raw.githubusercontent.com/reactjs/react-codemod/master/transforms/rename-unsafe-lifecycles.js src/
# Pour les fichiers TypeScript
npx jscodeshift -t https://raw.githubusercontent.com/reactjs/react-codemod/master/transforms/rename-unsafe-lifecycles.js --parser=tsx src/
# Exécution à blanc pour prévisualiser les modifications
npx jscodeshift -t https://raw.githubusercontent.com/reactjs/react-codemod/master/transforms/rename-unsafe-lifecycles.js --dry src/
Script de migration personnalisé
// migration-script.js
const fs = require("fs");
const glob = require("glob");
glob("src/**/*.tsx", (err, files) => {
files.forEach((file) => {
let content = fs.readFileSync(file, "utf8");
// Remplacer l'ancienne API par la nouvelle API
content = content.replace(
/componentWillMount/g,
"UNSAFE_componentWillMount",
);
// Mettre à jour les imports
content = content.replace(
/import { Component } from 'react'/g,
"import React, { Component } from 'react'",
);
fs.writeFileSync(file, content);
});
});
Stratégie de test
Tests unitaires
// Vérifier que les tests réussissent avant et après la mise à niveau
npm run test
// Mettre à jour les utilitaires de test si nécessaire
npm install @testing-library/react@latest
Tests d'intégration
// tests/integration/app.test.js
describe("Intégration de l'app", () => {
it("devrait être rendu sans crash", () => {
render(<App />);
});
it("devrait gérer la navigation", () => {
const { getByText } = render(<App />);
fireEvent.click(getByText("Navigate"));
expect(screen.getByText("New Page")).toBeInTheDocument();
});
});
Tests de régression visuelle
// visual-regression.test.js
describe("Régression visuelle", () => {
it("devrait correspondre au snapshot", () => {
const { container } = render(<App />);
expect(container.firstChild).toMatchSnapshot();
});
});
Tests E2E
// cypress/e2e/app.cy.js
describe("Tests E2E", () => {
it("devrait compléter le flux utilisateur", () => {
cy.visit("/");
cy.get('[data-testid="login"]').click();
cy.get('input[name="email"]').type("user@example.com");
cy.get('button[type="submit"]').click();
cy.url().should("include", "/dashboard");
});
});
Mises à jour automatisées des dépendances
Configuration de Renovate
// renovate.json
{
"extends": ["config:base"],
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
},
{
"matchUpdateTypes": ["major"],
"automerge": false,
"labels": ["major-update"]
}
],
"schedule": ["before 3am on Monday"],
"timezone": "America/New_York"
}
Configuration de Dependabot
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
reviewers:
- "team-leads"
commit-message:
prefix: "chore"
include: "scope"
Plan de restauration
// rollback.sh
#!/bin/bash
# Enregistrer l'état actuel
git stash
git checkout -b upgrade-branch
# Tenter la mise à niveau
npm install package@latest
# Exécuter les tests
if npm run test; then
echo "Mise à niveau réussie"
git add package.json package-lock.json
git commit -m "chore: upgrade package"
else
echo "Mise à niveau échouée, restauration"
git checkout main
git branch -D upgrade-branch
npm install # Restaurer à partir de package-lock.json
fi
Modèles de mise à niveau courants
Gestion du fichier de verrouillage
# npm
npm install --package-lock-only # Mettre à jour le fichier de verrouillage uniquement
npm ci # Installation complète à partir du fichier de verrouillage
# yarn
yarn install --frozen-lockfile # Mode CI
yarn upgrade-interactive # Mises à niveau interactives
Résolution des peer dependencies
# npm 7+ : peer dependencies stricts
npm install --legacy-peer-deps # Ignorer les peer deps
# npm 8+ : remplacer les peer dependencies
npm install --force
Mises à niveau d'espace de travail
# Mettre à jour tous les packages de l'espace de travail
npm install --workspaces
# Mettre à jour un espace de travail spécifique
npm install package@latest --workspace=packages/app