Add lint-staged To SvelteKit Project

Add lint-staged To SvelteKit Project

ยท

3 min read

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:

  1. Ignore files listed in .gitignore
  2. 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"
}
  1. Filtering Files: Which files do you want to lint or format? Ex: *.{js,ts,svelte}
  2. Ignoring Files: Project uses .gitignore as its ignore path for each command. Since lint-staged only runs against staged files, we don't need to ignore files that have been already ignored by .gitignore.
  3. Running multiple commands in a sequence: We can run multiple commands in a sequence, just put them in an array.
  4. --plugin-search-dir=.: Tell prettier to use plugins. We have prettier-plugin-svelte installed in the SvelteKit project.
  5. prettier --write & prettier --check runs sequentially; prettier & eslint runs against filtering files concurrently.

You can remove prettier --check, use eslint --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:

  1. Why is there no option to only check specific files (for example only staged files)?
  2. 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

ย