dpdm — A robust tool to find out circular dependencies in your JavaScript/TypeScript project

Young joking
3 min readJul 18, 2019

--

When you are building large projects, if you are not particularly careful, circular references are inevitable. When your application is restarted during the development progress, suddenly nothing can be seen, and it will become overwhelming.
Although there is now a tool called madge that can be used to analyze dependencies, the results of the analysis are confusing, especially when analyzing JavaScript and TypeScript mixed projects, sometimes .ts files are inexplicably ignored. I tried to read the source code of the project, but the core logic relied on additional repositories. It seems that it is very troublesome to make improvements, so I wrote a project dpdm to analyze the dependencies.
This project uses TypeScript as the abstract syntax tree (AST) parsing tool, so it can parse JavaScript and TypeScript very accurately. It also borrows some configuration methods of webpack, such as custom file extensions, module resolving, etc. It also provides a command line interface and a package interface for Node.js, so it is very convenient to use. Let me tell you how to use this repository!

Install at first

First you need to install this package, you can use npm or yarn. If you want to use it in the command line (recommended), you may need to install it globally. If you want to use it as an package, you only need to install it locally in your project.

# Install locally
npm i dpdm # or yarn add dpdm
# Install globally
npm i -g dpdm # or yarn global add dpdm
dpdm --help

Command line usage

dpdm provides a command line entry, which is called dpdm, you just need to use dpdm <entrypoint> to get the circular dependencies information. For example, if you has a project with the following directory tree:

$ tree example
example
├── circular_a.js
├── circular_b.js
├── circular_c.js
├── circular_d.js
└── index.js
0 directories, 5 files

And the contents of the files is:

$ cat example/*# circular_a.js
require('./circular_b');
# circular_b.js
require('./circular_c');
# circular_c.js
require('./circular_d');
#circular_d.js
require('./circular_a');
require('./circular_b');
# index.js
require('./circular_a');

Then run dpdm ./example, you will get the following output:

You can see the example at dpdm/example.

Of course you can use dpdm --help to get the help message as following:

$ dpdm --help
dpdm [<options>] entry...
Options:
--version Show version number [boolean]
--context the context directory to shorten path, default is process.cwd() [string]
--extensions, --ext comma separated extensions to resolve [string] [default: ".ts,.tsx,.mjs,.js,.jsx,.json"]
--include included filenames regexp in string [string] [default: "\.[tj]sx?$"]
--exclude excluded filenames regexp in string [string] [default: "/node_modules/"]
--output, -o output json to file [string]
--tree print tree to stdout [boolean] [default: true]
--circular print circular to stdout [boolean] [default: true]
--warning print warning to stdout [boolean] [default: true]
-h, --help Show help [boolean]

Package usage

import {
parseDependencyTree,
parseCircular,
prettyCircular,
} from 'dpdm'
const tree = await parseDependencyTree(
'./src/entries/**/*.*', // support glob or glob array
{
context: process.cwd(),
extensions: ['', '.ts', '.tsx', '.mjs', '.js', '.jsx', '.json'],
include: /\.[tj]sx?$/,
exclude: /\/node_modules\//,
}
);
const circulars = await parseCircular(tree)console.log(prettyCircular(circulars))

You can see the detailed document on GitHub: https://github.com/acrazing/dpdm#readme.

Enjoy your life~

--

--