Bun powered git hooks

Bun is a JS runtime and a package manager written in Zig by Jarred Sumner. Bun is way faster than NodeJS and package managers like npm & pnpm. Deno is another solid alternative but I lean towards Bun for a lot of reasons.

Bun install benchmark

Bun Shell Scripting API

Bun has more to offer than being just a runtime or a package manager. One of those offerings is their shell scripting API which can be used with a simple dollar sign syntax. It allows me to write my shell scripts and not having to look back at Bash ever again.

import { $ } from "bun";

const response = await fetch("https://example.com");

// Use Response as stdin.
await $`cat < ${response} | wc -c`; // 1256

Git hooks with Bun

I’ll assume you know what git hooks are. I will be showcasing 2 hooks that I actually use for this website. In the past I’ve used Lefthook for setting up hooks but it uses .yaml for configuration and I’ve come across more such tools that make a lot of effort to simplify and abstract things away at the cost of flexibility. But Lefthook was neat nonetheless. With bun I can use all the JS/TS syntax I want.

Pre Commit Hook

Before I commit my code I like to make sure that it is formatted(often ignored at my company) and does not have any errors that can be caught by the compiler/linter. My pre-commit hook addresses both of those problems. Also note that if any of the shell commands fail to execute, bun will discontinue the further execution of code.

#!/usr/bin/env bun

import { $ } from "bun";

// Sub-commands `lint` & `check` are defined in my project's package.json
await $`bun run lint`; // Runs `prettier --check . && eslint .`
await $`bun run check`;

Pre Push Hook

This is my favorite one. Since I have moved away from Github and now using Codeberg, which is not a supported Git provider by both Vercel and Cloudflare, I ended up using Cloudflare’s Wrangler CLI to deploy my site. The pre-push hook deploys the dev branch to the dev environment and the master branch to the production environment. And the job is done!

#!/usr/bin/env bun

import { $ } from "bun";

await $`bun run build`;

const branch = (await $`git rev-parse --abbrev-ref HEAD`.text()).trim();

if (branch === "dev") {
  await $`wrangler pages deploy build --project-name='textyash' --branch="dev"`;
} else if (branch === "master") {
  await $`wrangler pages deploy build --project-name='textyash'`;
} else {
  console.error(`pre-push hook not configured for branch ${branch}`);
}