Loading...
Please waitLoading...
Please waitBuild a runtime graph of which components depend on which stores/hooks to spot tight coupling and analyze architectural patterns.
pnpm dlx uselab@latest add use-dependency-graph
import * as React from "react"
import { useDependencyGraph } from "@/hooks/use-dependency-graph"
function UserProfile() {
const { registerHook, registerContext } = useDependencyGraph({
componentName: "UserProfile",
})
const auth = useAuth()
const data = useFetch("/api/user")
React.useEffect(() => {
registerHook("useFetch")
registerContext("AuthContext")
}, [registerHook, registerContext])
return <div>...</div>
}
function Dashboard() {
const { getInspectorOutput } = useDependencyGraph({
componentName: "Dashboard",
})
// Later, analyze the entire dependency graph
const analysis = getInspectorOutput()
console.log("Coupling score:", analysis.metrics.couplingScore)
console.log("Recommendations:", analysis.recommendations)
return <div>...</div>
}useDependencyGraph(options?)| Name | Type | Description | Default |
|---|---|---|---|
componentName | string | Component name to register (auto-detected if not provided). | Auto-detected |
autoTrack | boolean | Whether to automatically track hook dependencies (not implemented). | false |
filePath | string | Custom file path for the component. | — |
| Name | Type | Description |
|---|---|---|
registerDependency | (targetName: string, targetType: DependencyNode["type"], edgeType?: DependencyEdge["type"]) => void | Register a generic dependency relationship. |
registerHook | (hookName: string, metadata?: Record<string, unknown>) => void | Register that this component uses a specific hook. |
registerStore | (storeName: string, metadata?: Record<string, unknown>) => void | Register that this component consumes a specific store. |
registerContext | (contextName: string, metadata?: Record<string, unknown>) => void | Register that this component consumes a specific context. |
getGraph | () => DependencyGraph | Get the raw dependency graph structure. |
getInspectorOutput | () => InspectorOutput | Get analyzed inspector output with metrics, clusters, and recommendations. |
clear | () => void | Clear all tracked dependencies (useful for testing or resetting analysis). |
exportGraph | () => string | Export the complete graph and analysis as JSON string. |
downloadGraph | (filename?: string) => void | Download the graph and analysis as a JSON file. |
The getInspectorOutput() method returns an InspectorOutput object with the following structure:
interface InspectorOutput {
graph: DependencyGraph
metrics: {
totalNodes: number
totalEdges: number
components: number
hooks: number
stores: number
contexts: number
maxDependencies: number
minDependencies: number
avgDependencies: number
couplingScore: number // 0-1, higher = more tightly coupled
}
clusters: Array<{
nodes: string[]
type: "tightly-coupled" | "loosely-coupled" | "isolated"
score: number
}>
recommendations: string[]
}interface DependencyGraph {
nodes: Map<string, DependencyNode>
edges: DependencyEdge[]
timestamp: number
}
interface DependencyNode {
id: string
name: string
type: "component" | "hook" | "store" | "context"
filePath?: string
lineNumber?: number
metadata?: Record<string, unknown>
}
interface DependencyEdge {
from: string // source node ID
to: string // target node ID
type: "uses" | "provides" | "consumes" | "depends-on"
weight?: number // optional coupling strength indicator
}Track dependencies in your components:
function ShoppingCart() {
const { registerHook, registerStore } = useDependencyGraph({
componentName: "ShoppingCart",
})
const cart = useCartStore()
const data = useFetch("/api/cart")
React.useEffect(() => {
registerHook("useFetch")
registerStore("CartStore")
}, [registerHook, registerStore])
return <div>...</div>
}Get insights about your application's coupling:
function ArchitectureAnalyzer() {
const { getInspectorOutput, downloadGraph } = useDependencyGraph()
const handleAnalyze = () => {
const output = getInspectorOutput()
// Check coupling score
if (output.metrics.couplingScore > 0.7) {
console.warn("High coupling detected!")
}
// Review recommendations
output.recommendations.forEach((rec) => {
console.log("💡", rec)
})
// Download as JSON file
downloadGraph("architecture-analysis.json")
}
return <button onClick={handleAnalyze}>Analyze Architecture</button>
}Find components that are too tightly coupled:
function CouplingInspector() {
const { getInspectorOutput } = useDependencyGraph()
const output = getInspectorOutput()
const tightClusters = output.clusters.filter(
(c) => c.type === "tightly-coupled"
)
return (
<div>
<h3>Tightly Coupled Clusters</h3>
{tightClusters.map((cluster, idx) => (
<div key={idx}>
<p>
Cluster {idx + 1}: {cluster.nodes.length} nodes
</p>
<p>Score: {cluster.score.toFixed(2)}</p>
</div>
))}
</div>
)
}componentName values for better accuracy.exportGraph() to save analysis results for later review or to share with your team.Uses: useFetch, AuthContext
Uses: useFetch, CartStore
Uses: useFetch (2x), DashboardStore, AuthContext
Click "Analyze Graph" to inspect component dependencies and coupling patterns.