As of lately design systems have been all the rage and the benefits of producing one seem to be clear. Buying into a system might seem like a straight forward decision, but keeping everyone in the loop of changes is exponentially more complicated. If you work on the development end of any type of component library you know the silent difficulties of building and publishing processes.

The boring parts are a crucial part of the process. If you maintain projects that rely on versioning you’ll probably find yourself repeatedly doing the same task. And while semver as general practise is great, it’s difficult to enforce and to not decide on versions arbitrarily. When the times comes to inform stakeholder of choices and implementation details one month has gone by, and you’ve forgotten about most of the features and fixes implemented. And what good is a system that no one remembers?

“What’s the status on this component? Did we ship this already? When did we start getting this Type Error?”

This article covers a small part of that process, giving you a few practical tips on how to maintain a clear log and automatically build changes. This method can be applied to anything, from UI Kits, to packages and apps.

In order to create this flow we’ll go through a few steps:

Creating good commit messages. Using conventional commits. Enforcing good practises. With pre-commit hooks. Creating releases. Our release cookbook.

This article has some companion gists. 🛠

The automated result of what we’ll be working on.

Creating good commit messages

The first step is to follow a commit convention so you can generate your changelog without any manual work. Your contributions will be grouped by commit type and will look a bit like this type(scope): short description for commit with the type ranging from FEAT to TEST , determining what type of changes went into your code. To generate a template for commit messages we‘ll be using commitizen’s CLI.

Since we’re going to want this to be used on all of your projects right out of the gate we’re going to do some global installation with npm install -g commitizen .

Every project requires different things, and commit messages are part of that. So depending on the format you need you can install one of several adapters. From emoji filled commit messages to JIRA integrations. For the purposes of this guide, we’ll use cz-conventional-changelog. We’ll now initiate the adapter.

commitizen init cz-conventional-changelog --save-dev --save-exact

Then create a .czrc on your root folder (~) with the following content:

{ "path": "cz-conventional-changelog" }

Now, every time you’re in a git repository if you use the command git cz the CLI will show up, asking you to catalogue your commit according to the type of changes you made.

The cz-cli and some git aliases at work.

Enforcing good practises

This is all great, but it won’t add up to much if you write DID_STUFF as the scope of your change. That’s certainly invalid and won’t help much when generating your logs. To solve this problem we’ll put into place a commit validator and a pre-commit hook which will validate our commit messages before they go through. To create the hook we’ll use commitlint and husky.

Add the extra layer of security to be run on pre-commit with npm install -g @commitlint/cli @commitlint/config-conventional . And now your pre-commit checker with npm install husky --save-dev .

Create a .huksyrc file with the commitlint reference on "commit-msg" .

And create a configuration file to hold your preferred tests, in any of the following formats commitlint.config.js .commitlintrc.js .commitlintrc.json .commitlintrc.yml .

Then add a reference to the adapter you chose on the first step:

This will result in a verification triggering the husky > commit-msg validation, which might either pass or return a message with the problem at fault. Bear in mind that if you use flags such as --no-verify this validation won’t occur.

The pre-commit hook catching the “WILL_THROW_ERR” invalid scope.

Creating releases

With the message formatting sorted we can now focus on the actual bundling and releasing of your UI. We’ll now create a script to be executed on your CI (or locally with (dry-mode) environment), that’ll look at your commit history and do all the magic. We’re gonna create script with the dependency on you package.json:

Now we’ll create our recipe for releases. These will vary depending on the project, technologies and implementation details but our core recipe revolves around these plugins:

Why all the @semantic-release/plugin?

/COMMIT-ANALYZER: This is what powers all of the release, and this is why our commits must be formatted exactly as specified by the chosen convention. This will ensure that certain types will be associated with a patch, minor or major release. This will be visible in your terminal or the virtual environment you’re running. You can see what each type of commit triggers.

Release being executed on CI Environment and checking commit types.

/RELEASE-NOTES-GENERATOR: What generates your changelog based on the conventional commit standard defined above. Which will result in a release log similar to the one below.

Latest release posted automatically.