💥 Introducing Skott, the new Madge!
Tags: javascript, opensource, node, computerscience
Published: 2022-09-12 07:49:34


> Little announcement: thanks for anyone showing interest in skott! Just for your own information, this article was not recently updated to include all the latest features that skott has, but it still remains a good introduction to the spirit of the project. Feel free to check the GitHub repository to see the latest CLI/API versions! 

Hello everyone, hope you're doing well!

Today I'm very pleased to share a fun project I have been working on for several months now: **[skott](https://github.com/antoine-coulon/skott)**. 

![Skott](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hq7fy22e1qn17ztnyu5.png)

> **[skott](https://github.com/antoine-coulon/skott)** is a tool that generates a graph of dependencies from your **JavaScript/TypeScript/Node.js** projects (_including TSX/JSX and ES6/CommonJS modules!_) and helps you discover **circular dependencies, cost imports, file sizes, and many more** 💥

_Node.js builtin_ and/or _npm third-party dependencies_ can also be configured to be added in the graph. The main goal is to reproduce the architecture of your application at the file level.

### Installation and use

```console
$ npm install skott
```

**skott** provides an API to traverse the project graph, deeply search for circular dependencies, find parents or children for a given set of nodes, etc.

Here is a quick overview of the API:

```javascript
import skott from "skott";

const { 
  getStructure, 
  findCircularDependencies, 
  findParentsOf, 
  findLeaves 
} = await skott({
  /**
   * The entrypoint of the project. Must be either a CommonJS or ES6 module.
   * For now, TypeScript files are not supported as entrypoints.
   */ 
  entrypoint: "dist/index.js",
  /**
   * Define the max depth of for circular dependencies search. This can be useful 
   * for performance purposes. This defaults to POSITIVE_INFINITY.
   */
  circularMaxDepth: 5,
  /**
   * This defines whether the base directory of the entrypoint must be included
   * in all the relatives file paths.
   * For the specified `dist/index.js` above, it would consider the root path
   * to be `./` consequently `dist/` would never appear in any file paths.
   */
  includeBaseDir: false
});
```

**skott** can also be used through the CLI. 

## Web Visualization

Using the webapp display mode `skott --displayMode=webapp`, **skott** generates the graph and then automatically opens an interactive web application in which you can visualize the graph more precisely.

![webapp skott visualization](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjyg5x5uazz5hac8c2ng.png)

As shown above, we can see all the nodes created from files of your project, and edges are simply representing the links between files of your project. **Circular dependencies**, **third-party dependencies** and **built-in dependencies** can be displayed on demand to adapt the amount of information displayed at once.

## Console Visualization

Sometimes, you don't want to open a web interface to check what you want. For that, you can use other display mode that will render an UI in the console. Here is a quick preview of the graph generated for the **[fastify](https://github.com/fastify/fastify)** library:

![Skott CLI on fastify](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/js3afarccnjq5i15znox.png)

We can also decide to track more dependencies, for example the _npm third-party dependencies_ (by providing the "**--trackThirdPartyDependencies**" option) 

![Skott CLI on fastify](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysifefae7tnqkulfr3cg.png)

> Node.js builtin dependencies can also be tracked by providing the **"--trackBuiltinDependencies"** option.

### File tree display

Different modes of display are available from the CLI, including **file-tree** which reconstructs a directory of files from the graph which is far more concise:

![Skott CLI on fastify](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ge9667wbe8ctkpo14tpq.png)

### Static file generation

In addition to various display modes from the CLI, Skott is also able to create static files reflecting your project graph, including _.json_, _.svg_, _.md._ (using mermaid), and _.png_.

Here is an example creating a static file from `skott` itself:

```shell
$ skott dist/index.js --staticFile=svg
```

![Static graph image generation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/spegahc86krj9pxhy27b.png)

For medium to big size projects, you'll probably want to use the `webapp` display mode! 🫣

### Circular dependencies

**[skott](https://github.com/antoine-coulon/skott)** also helps finding out **circular dependencies very efficiently** in the project, you can even provide a max depth search to avoid deep searches that could be costly.

If you're not sure to see why circular dependencies _can be_ problematic, I created a section **Why you should care about circular dependencies and dead code in the [root documentation of skott](https://github.com/antoine-coulon/skott#readme)**

![Skott with Circular Dependencies](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tta0aus42gt0ijlxjboz.png)

Some options can also be provided to the CLI to configure the exit code that will be used when circular dependencies are met (defaults to "1" meaning error exit).

### Skott is fast

We can easily compare **[skott](https://github.com/antoine-coulon/skott)** with **[madge](https://www.npmjs.com/package/madge)** because **skott** already covers most of the features **madge** exposes for a Node.js project.

I did some benchmarks about the computing time required to build a set of graphs from popular libraries for both **skott** and **madge** and here are the results:

### [Webpack](https://github.com/webpack/webpack) (+560 files)

> **webpack** is a static module bundler for modern JavaScript applications.

Webpack is probably one of the heaviest open-source Node.js project I know. So let's do a benchmark!

- using **skott** takes **503ms** 

![webpack benchmark using skott](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qh4389cukliaoxye3jk.png)

- using **madge** takes **2.5 seconds**

![webpack benchmark using madge](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qexjg5jduujgknw6ebc.png)

> N.B: the difference of files between skott and madge is only because of .json files that are ignored by skott in the graph (as well as other files such as binaries).

### [Knex.js](https://github.com/knex/knex) (+6O files)

> **knex.js** A SQL query builder that is flexible, portable, and fun to use! 

- using **skott** takes **60ms**
![knex benchmark using skott](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jry447wsv9579ts4le77.png)

- using **madge** takes **450ms**
![knex benchmark using madge](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hyuyyt1yzq4sfvlty8yj.png)

For building the entire graph of **knex.js** with even more metadata, **skott is 7.5 times faster!**

### [Fastify.js](https://github.com/fastify/fastify) (30 files)

> **fastify.js** is a fast and low overhead web framework, for Node.js

- using **skott** takes **50ms**

![fastify benchmark using skott](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7afdkja36c4qa6u5npm.png)

- using **madge** takes **350ms**

![fastify benchmark using madge](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibfj550falh5hnzdpum0.png)

In this case, **skott** is 7 times faster than **madge**.

### Skott is extensible

**skott** aims to offer features that could be extended to any language, given that specific parsers can be implemented along the way. I started from only JavaScript, incrementally brought TypeScript and TSX/JSX support along the way. Why not bringing other languages around the table?

### Stay tuned

Many more features will be implemented (**skott does not yet have a major version released**) to help you easily discover and demystify what's going on under the hood of your Node.js project! I'm also thinking about developing a _Web Application_ that will help you visualize graphs and every metadata related to each file (number of imports, file size, unused imports, etc).

### Sharing journey of building an open-source library

I'll also start a series about the journey of building **skott**, which notably includes:

- **[OUT] [What it takes to build a static analysis tool (parsers, ast, etc)](https://dev.to/antoinecoulon/what-it-takes-to-build-a-static-analysis-tool-4p40)**
- How to make all of that **fully testable by using dependency injection and Test-Driven Development**!

Don't hesitate to bring **stars ⭐️, issues, feedbacks** [directly on GitHub here](https://github.com/antoine-coulon/skott) as it will allow me to drive the project where it will bring the most value for each developer.

Thanks for reading this far, wish everyone a wonderful day ☀️