Sequence diagrams are a very useful way to communicate about how processes work, especially when there are multiple services (or other actors) at play. A typical component-oriented diagram starts to suffer when there are several calls back and forth between the same systems, for example.
In the past I’ve used PlantUML, websequencediagrams.com, and Sequence Diagram from the Mac App Store.
Recently, though, I’ve been really enjoying Mermaid.
- It has a nice, simple, syntax
- It generates
svg, and both can be styled using CSS
- You can render mermaid diagrams right in a browser (for example, in hugo, which I haven’t done yet)
- There’s an online live editor
- It can also run from the command line
Running mermaid from the command line
Yes, it’s inevitable. If I can run it from the command line, I will.
At this time, there’s a stated issue in the CLI’s README which suggests doing a local install.
This works fine; the automation steps listed here assume they’re based off of that. If you’re not doing the local install, just update the path to
mmdc to be wherever it is on your system.
make is a classic tool for a reason. For pretty much any application where some source files (and maybe other files, like configurations) end up being used to generate an output file –
make can help.
Here’s the file I’ve used to mostly automate working with mermaid.
all: $(addsuffix .png, $(basename $(wildcard *.mmd))) %.png: %.mmd style.css config.json ./node_modules/.bin/mmdc -C style.css -w 2048 -H 1536 -c config.json -t neutral -i $< -o $@ exiftool -Source"<=$<" $@ open $@
Which results in this process, helpfully illustrated by mermaid:
This is some
all: $(addsuffix .png, $(basename $(wildcard *.mmd)))
Because the target
all shows up first, it’s the default, so it runs if you just run
all uses a few
make builtins to say “for all the mmd files” (aka mermaid sources), remove the mmd (
basename), and add
So, if in the directory you have
all target will have
%.png: %.mmd style.css config.json
This section, with the
%, is a pattern rule.
It creates automatic rules for targets. So any (nonexistent, at least on the first run)
.png file names that got added to
all in the first stepwill get matched. They’ll automatically depend on both the matching
.mmd file, as well as getting rebuilt if the
style.css files get updated.
Inside the pattern rule block, there are 2 special variable names:
$< (the input file) and
$@ (the output file.)
./node_modules/.bin/mmdc -C style.css -w 2048 -H 1536 -c config.json -t neutral -i $< -o $@
To make a given png, it’ll run the mermaid CLI tool with a bunch of configuration, including
.mmd file) for input and
.png file) for output.
exiftool command – we’ll get to in a minute.
And the final line (
open $@) uses the OS’s open tool to show you the resulting image. (YMMV outside of MacOS, but I trust that if you’re generating images from text based markup, you can figure out how to view an image on the platform of your choice.)
And that’s it! A nice png file, delivered by mermaid.
A similar process can be done to generate svg files, which are generally preferable … except when inserting them inside Google Docs, which is what I tend to do with these sequences.
Dark trickery with
Mermaid files are plain text, which can be used to generate images as we’ve seen here.
But what if it’s time to update a diagram – the sequence diagram is there in the document, it’s almost right, but it needs some updating.
Hopefully, the original file is in git somewhere, helpfully version controlled … but a lot of times documentation flows don’t get the same kind of engineering toolchain love as something like source code would. So, maybe, it’s just an image. And yes, looking at the above, you could probably type this back in:
sequenceDiagram user ->> make: run make ->> files: any files changed? alt No Files Changed make -x user: nothing to make end make ->> mermaid: build png mermaid ->> make: return status make ->> exiftool: add mermaid source to image exiftool ->> make: return status make ->> open: Open file open ->> user: Check out this file make ->> user: Build complete
but there’s got to be a better way.
I am lucky enough to work with Sean Kilgore, aka
@log1kal, and he found this problem particularly troublesome.
Which explains the
exiftool line of the
Makefile, his truly excellent addition:
exiftool -Source"<=$<" $@
Using some creative syntax, it includes the entire source file being used to generate the image into the
Source tag of the
This is cool stuff, because it can be recovered. Using a simple shell script like
#!/usr/bin/env bash exiftool -s -j -Source $1 | jq -r ..Source
-s reads the tag value,
-j prints the structure as json,
jq then picks the source attribute from the resulting document, and it’s
-r argument means it actually prints whitespace and newlines for real, instead of as escape codes.
So, does it work?
Here is a Google Doc, with a mermaid image inserted via
Insert > Image.
Sadly, there’s not clear way to do a right-click “Save Image”, but
File > Download > Webpage will give a zip file with HTML and all the other assets.
$ unzip -l Test\ Mermaid.zip Archive: Test Mermaid.zip Length Date Time Name --------- ---------- ----- ---- 2676 08-13-2019 22:48 TestMermaid.html 36923 08-13-2019 22:48 images/image1.png --------- ------- 39599 2 files
and … sure enough, it works!
$ ~/work/mermaid/recover_source.sh image1.png sequenceDiagram user ->> make: run make ->> files: any files changed? alt No Files Changed make -x user: nothing to make end # ... rest cut because you've seen it already
It’s not perfect.
- it’s kind of a pain to download a zip file and extract the contents
- If someone copy-pasted the contents of the image (e.g. from Preview) it doesn’t preserve the metadata.
But, it’s still better than nothing, and folks that care about it working would know to avoid the copy/paste issue.
And yes, the images in this blog post come with source included, if you want to try it out.
Making it even more automatic
One final target can be added to the
Makefile for extra fun:
watch: fswatch -o . | xargs -n1 sh -c 'make all'
This uses the open source fswatch, a cross-platform file change watching tool, to automatically re-run Make when things in the directory change.
So, just run
make watch, leave that running in the background, and work with your editor of choice in the other. Creating new
.mmd files magically leads to new images popping up, as does editing existing ones, or changing styles.
And just for fun, here’s that process via mermaid:
and the source:
graph LR makewatch[$ make watch] make[$ make] filesystem((Filesystem)) makewatch --> fsevents fsevents-- watches --> filesystem fsevents-- runs --> make vim -- writes to --> filesystem