Deno Projects: Linting + Formatting + Conventional Commits

- Suneet Misra
deno
code-quality
typescript
Thumbnail image showing the title for the article with the deno and git logos

This is the second of three articles illustrating how to set up a git automation for linting, and formatting files and for composing commit messages with conventional commits.

In the first article we implented the workflow within a node project. Here, we're going to recreate the same workflow but within a deno project.

The steps are pretty similar to those in the previous article, so we're going to wiz through, only drawing attention to the deno-specific differences.

Is there a video I can watch or a repo I can clone?

No video just yet, but here's a link to a demo repo that can be cloned.

What are we building?

We're going to create an automation that kicks in when we git commit. This automation will use deno to type-check, lint and format staged files, and then it will use gitmoji-cli to help format commits with emojis and conventional commit syntax. If you're allergic to emojis and still want conventional commits, try out commitizen which is a great alternative!

What are the steps?

We'll initialise a deno project with git. We'll install and configure lint-staged and git and that's pretty much all there is to it. Let's begin!

Step 1 - Initialise the project

terminal
deno init && git init

In your terminal, create a new directory for your project and cd into it. Use the deno init && git init command to initialise a new deno project with git in the current directory.

Step 2 - Install Dependencies

Deno's pretty awesome and it gives us the following out of the box:

All we need to do is install the missing parts of our workflow which is lint-staged.

terminal
deno add -D npm:lint-staged

The above command uses deno to install lint-staged from the npm package registry. We'll then see it listed in the imports section within the deno.json file. Read more about how deno handles 3rd party modules here.

Step 2 - Configure Lint-Staged

lint-staged.config.mjs
const config = {
"*.{cjs,mjs,js,ts,jsx,tsx}": (stagedFiles) => [
`deno lint ${stagedFiles.join(" ")}`,
`deno fmt ${stagedFiles.join(" ")}`,
],
"*.{css,md,mdx,json}": (stagedFiles) => [`deno fmt ${stagedFiles.join(" ")}`],
};
export default config;

We'll create our lint-staged configuration file as above at the root of our project. It's really similar to the node-based config file that we created in the previous article. The major difference here though is that we're executing the linting and formatting using the built-in deno commands.

We're using deno's default linting and formatting rules in this example which can be customised within the deno.json file by following the docs.

Step 3 - Configure Git

We're not using husky here as we did in the last article as it's is primarily designed with the structure of a node project in mind. Instead, we're going to use git's native core.hooksPath configuration property which can be used to redefine where hooks are stored. The core.hooksPath property was introduced with git v2.9.5 with the current release being v2.48.1. If a more husky-like experience is preferred, please take a look at the deno-hooks library which is inspired by husky (and also uses core.hooksPath under the hood).

First we'll create a directory to store our hooks:

terminal
mkdir git-hooks

Then we'll add a new pre-commit hook script into the directory:

.git-hooks/pre-commit
#!/usr/bin/env sh
deno check .
deno run -A npm:lint-staged

Next we'll add a new task to our deno.json:

deno.json
{
"tasks": {
"prepare": "git config --local core.hooksPath git-hooks && cd git-hooks && chmod +x *"
}
}

And finally, we'll run the prepare task to update our project's git configuration with the location of our git-hooks directory, and to make all files within the directory executable.

terminal
deno task prepare

We now have a pre-commit hook setup in the repo which will use deno to type-check the whole project, and lint-staged to initiate deno's linting and formatting commands on staged files prior to inputting the commit message.

Step 4 - Configure Gitmoji (optional)

Let's first install gitmoji-cli:

terminal
deno add -D npm:gitmoji-cli

Then, let's create our prepare-commit-msg hook:

./git-hooks/prepare-commit-msg
#!/usr/bin/env sh
exec < /dev/tty
deno run -A npm:gitmoji-cli --hook $1 $2

Finally let's run deno task prepare to make sure all the hook scripts are executable and git is configured correctly.

That's the last setup step completed!

Is That It? Are We Done?

Yes we're done! As with the node setup, we can go ahead and develop as normal and every time we commit our staged files, this automation will kick in!

Super Important - Read This or Everything Will Explode!

It's important to note that when we clone a project down which contains this configuration, we'll need to manually run the prepare task in order for the git directory to be configured to use our hooks. This can be done by chaining the task onto the install command:

terminal
deno install && deno task prepare

I hope this has helped and inspired you to learn more about deno and to share your enthusiasm for building with code!