Opinions & Insights
How to easily visualize a project's dependency graph with dependency-cruiser
Most documentation in open source is user facing. Whatever deficiencies we perceive in open source documentation (there isn't enough of it, for starters) is magnified 10x when it comes to documenting how it works for folks who want to contribute. Most CONTRIBUTING.md's read something like this:
1. Fork and clone the repo 2. Run `npm install` to install dependencies 3. Good luck!
Any time I see that I usually think of the after credits scene from Finding Nemo:
While time is of course scarce, I am always interested in simple ideas for making open source documentation easier, since it has a domino effect further down on whether people feel welcome to get involved.
I think visualizing projects is really important when you want to do some code spelunking — diving into large codebases you don't know anything about. If you're diving into a series of caves, wouldn't it be nice to have a map? This is what I call Visual Internal Documentation, and
dependency-cruiser is a great way to create and automate this!
Getting Started with
You can install
dependency-cruiser globally with
npm i -g dependency-cruiser. Then, in the folder of any project you care about, you can run:
depcruise --exclude "^node_modules" --output-type dot src | dot -T svg > dependencygraph.svg
assuming the core of your code lives in the
src sub folder and you have Graphviz dot installed (it comes installed in Netlify's buildbot so no fears about that).
dependency-cruiser run on the
reactive-react project I recently released at React Rally:
Here you can see that
index.js is the highest level file, followed by
swyxjs.js seems like one of those "utils" files that is imported by everybody without importing anything else (it is). Also,
updateProperties.js is never used.
Pretty handy for a first glance! But what does it look like for a non-trivial project?
Visual code spelunking
This is slightly messier, but can still be followed.
h are top level imports, and
vdom is an important submodule. The "terminal dependencies" like
vnode also stand out as items that are frequently imported which themselves have no dependencies.
That's great! As I get into contributing to Preact I can do a breadth first scan of the top level stuff while keeping track of those files I have visited/should visit!
The arrows also suggest potential opportunities for less confusing file structures.
dependency-cruiser highlights actual (invalid) circular dependencies, but some dependencies can be circular while importing completely independent pieces of code. Here, we see that:
This is valid code because
src/component only wants
src/vdom/component-recycler only wants
src/component. This can be fine especially since Preact places a high priority on filesize, but you can see how this might get confusing quickly for projects of even marginally higher complexity.
Visualizing massive projects
It is possible to go too far though. Here's the core React package (
I'd print that out and put it on my wall, but it's certainly not a very useful map! Here's where you run it with the max-depth flag:
depcruise --max-depth 2 --exclude "^(node_modules|forks|__tests__)" --output-type dot packages/react/src | dot -T svg > dependencygraph.svg
Isn't that gorgeous?! But more importantly, if I am contributing to the top level files for React, I can look ahead to see where all my dependencies are in relation to what I am working on. Tweak the command line accordingly for exploring further.
Continuous Visual Documentation
Being Netlify, we of course want to explore how we can make this visualization continuously updated. Fortunately, you can install
dependency-cruiser as a local dependency in your project, and then add an npm script to
"build:deptree": "depcruise --exclude '^node_modules' --output-type dot reactive-react | dot -T svg > dependencygraph.svg",
Now if you include
build:deptree in your final build script, your dependency graph updates every time!!! What? Documentation that doesn't go out of date!? Sign me up!
If you use a documentation system for your OSS project like docusaurus (your friendly neighborhood dinosaur that just happens to be very passionate about great docs!) for example:
dependency-cruiseras a local dependency:
yarn add -D dependency-cruiser
- In your
docusaurussite folder, add build script, something like
"build:deptree": "depcruise --exclude '(node_modules|__tests__|dist)' --output-type dot ../packages | dot -T svg > static/img/dependencygraph.svg"
../packages points to the source file for the OSS project which happens to sit next to the
docusaurus site in file structure
- Now that the svg is in your static files, you can refer to it in your docs like so:
## Internal stucture
Here is a chart of how the package is set up:
I do think this is only the start of a bigger discussion around how we can promote better internal documentation for open source projects, and ironically visual documentation can be easier than keeping swathes of text up to date when code always moves faster. The svg generated has direct links to the files they represent, and it would be interesting to explore a deeper integration with
docusaurus where you are able to click on any box and pull up the file right in the docs, or hover to see some top level comments.
There are a ton of possibilities with Visual Internal Documentation, and I hope this has given you an idea of how to get started!