Visualize Module Dependency Graph Using Dependency Cruiser

Dependency Cruiser Documentation

Dependency Cruiser is a tool that helps you visualize and validate the dependencies in your JavaScript and TypeScript projects. It generates dependency graphs and checks for issues like circular dependencies, orphan modules, and adherence to architectural rules.

Installation

  1. Install as a development dependency in your project:
npm install --save-dev dependency-cruiser
  1. Install Graphviz for visualization:
# For Ubuntu/Debian
sudo apt-get install graphviz

# For MacOS
brew install graphviz

# For Windows (using chocolatey)
choco install graphviz

Basic Usage

Generate Dependency Graph

# Basic command to generate a dependency graph in SVG format
npx depcruise --output-type dot . | dot -T svg > dependency-graph.svg

# Generate a dependency graph using a specific configuration file
npx depcruise --config .dependency-cruiser.js --output-type dot . | dot -T svg > dependency-graph.svg

Configuration File Setup

Create .dependency-cruiser.js in your project root:

/** @type {import('dependency-cruiser').IConfiguration} */
module.exports = {
  forbidden: [{
    name: 'no-circular',
    severity: 'warn',
    comment: 'Circular dependencies are not allowed',
    from: {},
    to: {
      circular: true
    }
  }],
  options: {
    doNotFollow: {
      dependencyTypes: [
        'npm',
        'npm-dev',
        'npm-optional',
        'npm-peer',
        'npm-bundled'
      ],
      path: [
        'node_modules'
      ]
    },
    exclude: {
      path: [
        'node_modules',
        'test',
        'tests',
        'dist',
        'build'
      ]
    },
    reporterOptions: {
      dot: {
        collapsePattern: 'node_modules/[^/]+',
        theme: {
          graph: { rankdir: 'LR' },
          modules: [
            {
              criteria: { source: '\\.json$' },
              attributes: { fillcolor: '#ffcccc' }
            },
            {
              criteria: { source: '\\.js$' },
              attributes: { fillcolor: '#ccffcc' }
            }
          ]
        }
      }
    }
  }
};

Advanced Configuration Options

Customize File Extensions

options: {
  knownExtensions: [
    'js',
    'cjs',
    'mjs',
    'ts',
    'json'
  ]
}

Include/Exclude Specific Paths

options: {
  exclude: {
    path: [
      '^node_modules',
      '^test',
      '\\.test\\.',
      '\\.spec\\.'
    ]
  },
  includeOnly: {
    path: [
      '^src',
      '^app'
    ]
  }
}

Customize Graph Appearance

options: {
  reporterOptions: {
    dot: {
      theme: {
        graph: {
          rankdir: 'LR',          // Left to right direction
          splines: 'ortho',       // Orthogonal lines
          ranksep: '1.0',         // Rank separation
          nodesep: '0.8'          // Node separation
        },
        modules: [
          {
            criteria: { source: '\\.controller\\.js$' },
            attributes: {
              fillcolor: '#ccffcc',
              shape: 'box'
            }
          },
          {
            criteria: { source: '\\.service\\.js$' },
            attributes: {
              fillcolor: '#ffffcc',
              shape: 'ellipse'
            }
          }
        ]
      }
    }
  }
}

Dependency Validation Rules

forbidden: [
  {
    name: 'no-circular',
    severity: 'error',
    comment: 'Circular dependencies are not allowed',
    from: {},
    to: { circular: true }
  },
  {
    name: 'no-orphans',
    severity: 'warn',
    comment: 'Modules should have at least one dependency',
    from: {
      orphan: true,
      pathNot: ['^src/types']
    },
    to: {}
  },
  {
    name: 'controllers-services',
    comment: 'Controllers can only depend on services',
    severity: 'error',
    from: { path: '^src/controllers' },
    to: { path: '^src/(?!services)' }
  }
]

Common Use Cases

1. Generate Backend API Dependencies

# Generate a dependency graph for backend API modules
npx depcruise --include-only "^src/api|^src/services|^src/models" --output-type dot . | dot -T svg > api-dependencies.svg

2. Check for Circular Dependencies

# Validate the project for circular dependencies using the configuration file
npx depcruise --validate .dependency-cruiser.js .

3. Generate Module Overview

# Generate a flat list of modules in the project
npx depcruise --output-type flat . > modules.txt

4. Focus on Specific Module

# Generate a dependency graph focusing on a specific module
npx depcruise --focus "^src/auth" --output-type dot . | dot -T svg > auth-module.svg

Output Formats

  1. SVG (Default visualization):
npx depcruise --output-type dot . | dot -T svg > graph.svg
  1. DOT format:
npx depcruise --output-type dot . > graph.dot
  1. Text format:
npx depcruise --output-type text .
  1. JSON format:
npx depcruise --output-type json . > dependencies.json

Best Practices

  1. Always use a configuration file for consistent results
  2. Start with basic visualization, then add complexity
  3. Use meaningful colors and shapes for different types of modules
  4. Regularly validate dependencies to catch issues early
  5. Keep the graph focused by using includeOnly options
  6. Use meaningful names for output files
  7. Add comments to validation rules for better documentation

Troubleshooting

  1. If graph is too complex:

    • Use includeOnly to focus on specific parts
    • Increase ranksep and nodesep values
    • Use different rankdir settings
  2. For performance issues:

    • Exclude test files and node_modules
    • Focus on specific directories
    • Use simpler themes
  3. For validation errors:

    • Check the configuration file syntax
    • Verify path patterns
    • Review forbidden rules
6 Likes