Optional pre-commit checks with husky
on Dragoș Străinu's blogIf you are working on a JavaScript project, you probably are using husky to check your commit messages, maybe do some Prettier, Eslint formatting, or TypeScript checks.
Checking commit messages is fast, but running formatting and type checking takes more time as your project grows.
You can use lint-staged for prettier and eslint, but using it for TypeScript check makes no sense because if you change types in a git staged file it may break typing in another file.
All engineers have different workflows. To fix an issue from the TypeScript compiler, you could run a tsc --watch
process and make sure nothing is broken.
I don't want to run tsc --watch
because constantly running it slows the laptop. I don't mind if this check will be done at pre-commit stage even if the commit will take 10,20,30+ seconds.
But how to make this pre-commit optional? So the teammates that do manually formatting and type checking will not be frustrated.
husky version 7 enables pre-commit configuration using a bash script. So why not do checking before running tsc
or lint-staged
?!
This will be the beginning of the .husky/pre-commit
file
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
APP_PRE_COMMIT_OPTIONS="$(dirname "$0")/_/pre-commit.options"
So we can put our options in a file named pre-commit.options
inside the .husky/_/
folder.
.husky/_/
should have a.gitingore
file that will ignore our option file.
Next, let's print some message if the options files do not exist
YELLOW="\033[1;33m"
GREEN="\033[1;32m"
RESET="\033[0m"
if ! [ -f "$APP_PRE_COMMIT_OPTIONS" ]; then
echo "${YELLOW}\nSkipping pre-commit hook."
echo "If you want to use pre-commit for TypeScript check and lint-staged, run:\n"
echo " ${GREEN}echo -e 'APP_TS=true;\\\nAPP_LINT=true;' > $P_APP_PRE_COMMIT_OPTIONS${RESET}"
echo ${YELLOW}\nIt will add some delay before committing!\n${RESET}"
exit 0
fi
Now, let's source the options file and check if the user enabled the linting:
source $APP_PRE_COMMIT_OPTIONS
if [ -n "${APP_LINT}" ] && [ "${APP_LINT}" == "true" ]; then
echo "${GREEN}[husky] [pre-commit] [lint-staged]${RESET}"
npx lint-staged
fi
You can add more options and checks if needed!
Final result
The .husky/pre-commit
file should look similar to this:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
APP_PRE_COMMIT_OPTIONS="$(dirname "$0")/_/pre-commit.options"
YELLOW="\033[1;33m"
GREEN="\033[1;32m"
RESET="\033[0m"
if ! [ -f "$APP_PRE_COMMIT_OPTIONS" ]; then
echo "${YELLOW}\nSkipping pre-commit hook."
echo "If you want to use pre-commit for TypeScript check and lint-staged, run:\n"
echo " ${GREEN}echo -e 'APP_TS=true;\\\nAPP_LINT=true;' > $P_APP_PRE_COMMIT_OPTIONS${RESET}"
echo ${YELLOW}\nIt will add some delay before committing!\n${RESET}"
exit 0
fi
source $APP_PRE_COMMIT_OPTIONS
if [ -n "${APP_TS}" ] && [ "${APP_TS}" == "true" ]; then
echo "${GREEN}[husky] [pre-commit] [tsc]${RESET}"
npx tsc
fi
if [ -n "${APP_LINT}" ] && [ "${APP_LINT}" == "true" ]; then
echo "${GREEN}[husky] [pre-commit] [lint-staged]${RESET}"
npx lint-staged
fi