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&prettieragainst 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
.gitignoreas its ignore path for each command. Sincelint-stagedonly 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=.: Tellprettierto use plugins. We haveprettier-plugin-svelteinstalled in the SvelteKit project. -
prettier --write&prettier --checkruns sequentially;prettier&eslintruns 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
Top comments (0)