Locating cyclic dependencies in JavaScript/TypeScript using dpdm

Keywords: Javascript JSON github TypeScript npm

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

  1. 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
  2. Use in the command line: directly use the command dpdm [optional parameters] < entry file >, output examples:

    1. 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).
    2. You can use -- output < File > to output results to json files
    3. By default, the content in node_modules is omitted and can be cancelled with -- exclude'.
    4. 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]
  3. 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~

Posted by onthespot on Fri, 19 Jul 2019 01:20:07 -0700