In my previous post: Add Commitint, Commitizen, Standard Version, and Husky to SvelteKit Project, I'd introduced how to add Conventional Commits and SemVer to your SvelteKit Project.
We added a pre-commit
hook to format and lint our code before committing:
# Add pre-commit hook
npx husky add .husky/pre-commit 'pnpm format && pnpm lint && git add .'
While there is a problem that we format and lint our entire codebase every time, it's not ideal if we make a small commit.
Can we ONLY format and lint files we've changed? ๐
The answer is "Yes", and this is where lint-staged
comes into play.
What is ๐ซ๐ฉ lint-staged?
Run linters against staged git files, and don't let ๐ฉ slip into your codebase!
As the name suggests, lint-staged
enables us to lint staged files. But we can leverage it to do more like formatting (prettier
), type checking (tsc
), ... etc.
Let's see how to add lint-staged
and improve the workflow.
Install
Please refer to my previous post before we start or directly check the final repo.
# Install lint-staged
pnpm add -D lint-staged
Setup
Create a new file called .lintstagedrc
under the project root folder:
{
"*.{js,ts,svelte,css,scss,postcss,md,json}": [
"prettier --write --plugin-search-dir=.",
"prettier --check --plugin-search-dir=."
],
"*.{js,ts,svelte}": "eslint"
}
Update .husky/pre-commit
:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# npm
# npx lint-staged
# pnpm
pnpm exec lint-staged
You might be curious "Why not just use pnpm format
, pnpm lint
directly?". To explain that, let's take a look at our script
tag in package.json
:
// package.json
// Default SvelteKit skeleton project with TypeScript, ESLint, Prettier
{
...
"script": {
...
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .",
}
}
Put simply, these two scripts would:
- Ignore files listed in
.gitignore
- Run
eslint
&prettier
against the whole project because we had.
at the end of the each script
Remember we ONLY want to lint and format files that changed?
We need to customize the script so lint-staged
can perform correctly.
Anatomy of the .lintstagedrc
{
"*.{js,ts,svelte,css,scss,postcss,md,json}": [
"prettier --write --plugin-search-dir=.",
"prettier --check --plugin-search-dir=."
],
"*.{js,ts,svelte}": "eslint"
}
- Filtering Files: Which files do you want to lint or format? Ex:
*.{js,ts,svelte}
- Ignoring Files: Project uses
.gitignore
as its ignore path for each command. Sincelint-staged
only runs against staged files, we don't need to ignore files that have been already ignored by.gitignore
. - Running multiple commands in a sequence: We can run multiple commands in a sequence, just put them in an array.
--plugin-search-dir=.
: Tellprettier
to use plugins. We haveprettier-plugin-svelte
installed in the SvelteKit project.prettier --write
&prettier --check
runs sequentially;prettier
&eslint
runs against filtering files concurrently.
You can remove
prettier --check
, useeslint --fix
, or customize it depending on your need.
What about svelte-check
?
In my previous post, I put svelte-check
in my pre-push
but not pre-commit
hook.
The reason is that svelte-check
needs to know the whole project to do valid checks.
Refs:
- Why is there no option to only check specific files (for example only staged files)?
- svelte-check: check only files mentioned as arguments #353
Wrapping Up
I have been experimenting with different configurations and toolings to optimize our workflow in the last few days.
Conventional Commits & SemVer help us forge a better code review process, but we also want to ensure the workflow is robust enough when the project scales.
Using lint-staged
in pre-commit
is one of the improvements to reduce the time and improve our DX.
That's all. Thank you for your reading! ๐
Please leave a comment if you have any questions or share your experience. Love to connect with you and learn from you.
You can find me on Twitter: @davipon