Visualiseur de graphe de dépendances Angular
Séparez chaque fichier par un en-tête // FILE: chemin/fichier.ts.
Les imports relatifs (./, ../) sont analysés.
Glissez les nœuds, zoomez avec la molette. Les arcs rouges signalent une dépendance circulaire.
⚠ Dépendances circulaires détectées
Collez vos fichiers TypeScript et obtenez un graphe interactif des dependances Angular : detection des cycles et suggestions de refactoring.
Pourquoi visualiser le graphe de dépendances ?
Dans un projet Angular, chaque composant, service,
directive, pipe ou module dépend
d'autres fichiers via les directives import TypeScript. Au fil des
fonctionnalités ajoutées, ces relations forment un graphe orienté souvent invisible
pour le développeur — jusqu'au jour où une dépendance circulaire casse la
compilation ou où un module simple importe la moitié de l'application.
Visualiser ce graphe répond à plusieurs besoins concrets :
- Onboarding rapide sur un projet legacy : comprendre l'architecture en quelques minutes.
- Code review : repérer un module qui dépend du core alors qu'il devrait être indépendant.
- Refactoring : identifier les hubs (fichiers importés par tout le monde) avant de les casser.
- Détection précoce des circular dependencies, source de bugs subtils en lazy loading.
- Documentation vivante : exporter un PNG pour le wiki technique de l'équipe.
Core → Shared → Features.
Comment utiliser l'outil pas à pas
Le visualiseur fonctionne entièrement dans le navigateur (Cytoscape.js). Votre code n'est jamais envoyé à un serveur — utilisez-le en toute sécurité sur du code propriétaire.
1. Préparer le code à analyser
Concaténez plusieurs fichiers .ts dans la zone de saisie, séparés par
des en-têtes // FILE: chemin/fichier.ts. C'est la seule convention requise.
// FILE: src/app/app.component.ts
import { Component } from '@angular/core';
import { UserService } from './services/user.service';
import { HeaderComponent } from './shared/header.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [HeaderComponent],
template: `<app-header></app-header>`
})
export class AppComponent {
constructor(private users: UserService) {}
}
// FILE: src/app/services/user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
}
// FILE: src/app/shared/header.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-header',
standalone: true,
template: `<header>App</header>`
})
export class HeaderComponent {}
2. Lancer l'analyse
Cliquez sur Analyser le code. Le parseur extrait tous les
import ... from '...' et ne retient que les imports relatifs
(commençant par ./ ou ../) ou ceux qui pointent vers
un autre fichier collé. Les imports @angular/* et autres packages
npm sont volontairement ignorés.
3. Explorer le graphe
Chaque nœud représente un fichier, chaque arc un
import. Glissez les nœuds, zoomez à la molette, double-cliquez pour
recentrer. Le menu Disposition permet de basculer entre algorithmes
cose (force-directed), breadthfirst (hiérarchique),
circle, concentric ou grid.
4. Lire les métriques
- Fichiers : nombre total de nœuds.
- Dépendances : nombre total d'arcs.
- Cycles détectés : nombre de cycles circulaires (idéalement 0).
- Score complexité : note A à E basée sur la densité du graphe (edges / nodes). Au-dessus de B, le découpage mérite une revue.
Détecter les dépendances circulaires
Une dépendance circulaire survient quand le fichier A importe B
qui importe (directement ou indirectement) A. En TypeScript / ES Modules, cela
produit souvent des valeurs undefined à l'exécution, ou pire, des
erreurs aléatoires liées à l'ordre d'évaluation des modules.
Exemple typique en Angular
// FILE: auth/auth.service.ts
import { UserService } from '../users/user.service';
@Injectable({ providedIn: 'root' })
export class AuthService {
constructor(private users: UserService) {}
}
// FILE: users/user.service.ts
import { AuthService } from '../auth/auth.service'; // ⚠ cycle !
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private auth: AuthService) {} // ⚠ cycle !
}
Algorithme utilisé
L'outil utilise un parcours DFS (Depth First Search) avec marquage
des nœuds en cours d'exploration. Si un nœud déjà en cours est revisité,
un cycle est enregistré et la pile actuelle est extraite pour afficher le chemin
exact (ex : A → B → C → A).
Comment résoudre un cycle
- Extraire un contrat partagé (interface, token DI) dans un fichier tiers neutre.
- Utiliser
forwardRef()uniquement en dernier recours pour les injections cycliques. - Remonter la logique commune dans un service core dont dépendent A et B.
- Découper le fichier le plus dense en deux fichiers à responsabilité unique.
- Pour un cycle entre composants, passer par un service médiateur (event bus).
Clean architecture Angular
Le graphe idéal en Angular respecte une hiérarchie en couches strictement orientée du haut vers le bas. Les flèches ne remontent jamais.
| Couche | Rôle | Peut dépendre de | Ne doit jamais dépendre de |
|---|---|---|---|
| Core | Services globaux, guards, interceptors, config | Rien (sauf Angular) | Shared, Features |
| Shared | UI réutilisable, pipes, directives | Core | Features |
| Features | Pages métier (lazy loaded) | Core, Shared | Autres Features (sauf via routes) |
| App | Bootstrap, routes principales | Core, Shared, Features (lazy) | — |
features/orders → features/users
dans le graphe, c'est un signal de refactoring immédiat.
Refactorings à appliquer
1. Le fichier « hub »
Un fichier importé par plus de 10 autres fichiers est un hub. Toute modification de ce fichier impacte une grande partie de l'application. Solution : le découper en services à responsabilité unique (SRP) et n'exposer que les interfaces nécessaires.
2. Le « god service »
Un service qui dépend de tous les autres services concentre trop de logique. Appliquez le principe de Single Responsibility et déléguez à des services spécialisés.
3. Imports verticaux interdits
Dans le graphe, repérez les arcs qui remontent : shared → features
ou core → shared. Inversez la dépendance via une interface
injectée par token DI (Dependency Inversion).
4. Lazy loading et code splitting
Quand le graphe montre qu'une feature importe la moitié de l'app, le lazy loading ne sert plus à rien. Vérifiez avec cet outil avant chaque release que les features restent isolées.
Alternatives : Madge, Compodoc, Nx Graph
Plusieurs outils existent en ligne de commande ou en mode local :
| Outil | Mode | Points forts | Limites |
|---|---|---|---|
| Madge | CLI npm | Détection cycles, export DOT/SVG | Installation locale requise |
| Compodoc | CLI Angular | Documentation complète, classes, modules | Lourd à intégrer, projet complet nécessaire |
| Nx Graph | CLI Nx | Graphe monorepo, affected, lint | Réservé aux workspaces Nx |
| Cet outil web | Navigateur | Aucune installation, copier-coller, instantané | Analyse partielle (les fichiers collés uniquement) |
Conclusion
La santé d'une codebase Angular se lit dans son graphe de dépendances. Un graphe en couches strictes, sans cycle, avec un faible facteur de connexion est le signe d'une architecture maintenable. Visualiser ce graphe à chaque code review ou onboarding évite de découvrir trop tard un module qui a « infecté » tout le projet.
Utilisez cet outil pendant vos revues de code, vos sessions de refactoring ou vos audits d'architecture. Aucun envoi serveur, aucune installation : collez, analysez, partagez l'export PNG dans le wiki technique de l'équipe.