When writing large-scale projects, you will accidentally step into the pit of direct circular dependency. The so-called direct circular dependency refers to the situation that other members of the module factory function have direct calls to other modules that depend on themselves. For example:
Suppose there are two modules a.js and b.js, where a.js is as follows:
const b = require('./b') exports.hello_a = function hello_a() { return 'a' } exports.hello_from_b = function hello_from_b() { return b.hello_b() }
The contents of b.js are as follows:
const a = require('./a') // The following line leads to direct circular dependency exports.hello_from_a = a.hello_a() exports.hello_b = function hello_b() { return 'b' }
At this point, executing a.js will report a TypeError: a.hello_a is not a function error, because the factory function of module a.js is still executing, and the declaration of hello_a function has not yet been executed, while b.js calls a.hello_a directly, so if this variable does not exist, it will report an error, if it is not a function and If it is a variable, it will not report an error, but the value obtained is undefined, which makes it more difficult to locate the problem.
Although there is a project called madge that can be used to locate cyclic dependencies, the output of this repository when dealing with TypeScript is a metaphysical problem, and it often ignores files that should not be ignored inexplicably. I will give an example of this problem later.
So I spent a day building a wheel: dpdm It is designed to detect cyclic dependencies in JavaScript and TypeScript projects. It can currently detect the following four situations:
- require(...) function call of CommonJS
- ESM static import... from... statement
- Dynamic import(...) function call of ESM
- ESM static export... from... statement
It meets the needs of most situations, because few people now use AMD and System.
Usage
-
Installation: dpdm can be used on command line or js project. If you want to use it on command line (recommended), global installation is recommended. Otherwise, it can be installed in your project.
# Global Installation npm i -g dpdm # Or use yarn: yarn global add dpdm # Installation in Project Catalog npm i dpdm # Or use yarn: yarn add dpdm
-
Use in the command line: directly use the command dpdm [optional parameters] < entry file >, output examples:
- By default, dependency trees, circular dependency lists, and warning messages are output. You can use parameters to close any of them, such as DPDM -- tree false -- warning false. / SRC / index. ts to close dependency trees and warning information (showing only circular dependency tables).
- You can use -- output < File > to output results to json files
- By default, the content in node_modules is omitted and can be cancelled with -- exclude'.
-
Use -- help to view the complete help document:
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: "\.m?[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]
-
Use in the code: dpdm provides several API s, specifically to view the definitions provided by. d.ts in the package, or to view documents in GitHub:
For example:
import { parseCircular, parseDependencyTree, parseWarnings, prettyCircular, prettyTree, prettyWarning, } from 'dpdm'; parseDependencyTree(['./src/**/*'] /* Entry, glob matching, can be an array */, { /* A list of parameters. Here are the default parameters */ context: process.cwd(), // Prefix, used to abbreviate file names extensions: ['', '.ts', '.tsx', '.mjs', '.js', '.jsx', '.json'], // Suffix include: /\.m?[tj]sx?$/, // Files to be parsed exclude: /\/node_modules\//,//Files to be Ignored }).then((tree) => { console.log('Tree:'); console.log(prettyTree(tree, Object.keys(tree))); console.log(''); console.log('Circular:'); console.log(prettyCircular(parseCircular(tree))); console.log(''); console.log('Warning:'); console.log(prettyWarning(parseWarnings(tree))); });
Ask questions
The project is open source in GitHub at https://github.com/acrazing/dpdm You can mention issue or submit pr.
By the way, please~