Hi everyone ! This article will show you how you can setup a Yarn monorepo to work with Husky.
Source code 📦 : https://github.com/0x2A-git/husky-yarn-monorepo-tutorial/tree/main
Goal ⚽
We are going to take a common example where we'd like to automatically lint all of our staged changes (regardless of their workspace) when committing using ESLint & Prettier.
Project structure 🏗️
.
|-- apps/
| app/
| ...
| package.json
|-- packages/
| package/
| ...
| package.json
`-- package.json
Monorepo Setup 🚧
First, upgrade yarn to the latest stable version and add workspace-tools plugin :
$ yarn set version stable
$ yarn
$ yarn plugin import workspace-tools
Note : If you don't want to use PnP and stick with node_modules run yarn config set nodeLinker node-modules
Once it is done, install Husky as a dependency of your whole monorepo :
$ yarn add -D husky
$ yarn run husky install
Then open your monorepo's package.json and add the following scripts :
{
"name": "husky-yarn-monorepo",
"packageManager": "yarn@3.5.1",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": ["apps/*", "packages/*"],
"devDependencies": {
"husky": "^8.0.3"
},
"scripts": {
"postinstall": "husky install",
"pre-commit": "yarn workspaces foreach run pre-commit"
}
}
The pre-commit
script will run a script called pre-commit
script in every app & package package.json.
Now we are going to register the pre-commit
script to Husky :
$ yarn run husky add .husky/pre-commit "yarn run pre-commit"
Next stage the file :
$ git add .husky/pre-commit
App / Package Setup 🚧
For the tutorial convenience the app and the package will have the same architecture. This part assumes that you've already setup your workspaces (yarn init
, yarn
, ...). Let's cd
in one of the apps or the packages and follow these steps :
Setup Linting :
First install these dependencies :
$ yarn add -D eslint @typescript-eslint/eslint-plugin eslint-config-prettier eslint-config-standard-with-typescript eslint-plugin-import eslint-plugin-n eslint-plugin-prettier eslint-plugin-promise lint-staged prettier
Then create these files :
$ touch .eslintrc.js .lintstagedrc .prettierrc
Copy the following content in .eslintrc.js :
const path = require('path')
module.exports = {
env: {
es2021: true,
},
extends: ['standard-with-typescript', 'prettier'],
parserOptions: {
project: path.join(__dirname, '/tsconfig.json'),
ecmaVersion: 'latest',
sourceType: 'module',
},
overrides: [],
}
Configure lint-staged through the .lintstagedrc file :
{
"*.ts": ["eslint --fix", "prettier --write"]
}
In .prettierrc you can add this default configuration :
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true
}
Setup Typescript
Run these commands :
$ yarn add -D typescript
$ mkdir src
$ touch src/index.ts tsconfig.json
You can use this config in your tsconfig.json :
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": "./src",
"outDir": "./dist",
"declaration": true,
},
"include": ["./**/**.ts"]
}
Setup pre-commit 📜
Add the following script in your app's or package's package.json :
...
"scripts": {
"pre-commit": "lint-staged"
}
...
You can copy the following code in src/index.ts :
const myFunction = () => {
return "This my function !"
}
myFunction()
Now let's try to commit our files by running :
$ git add -A
$ git commit -m "My commit message"
Note : If you get Usage Error: Couldn't find a script named "pre-commit".
don't forget to implement pre-commit
script in every app / package package.json.
After running the command you should get this error :
1:20 error Missing return type on function @typescript-eslint/explicit-function-return-type
✖ 1 problem (1 error, 0 warnings)
Nice ! That's what we wanted, it means that ESLint successfully detect errors.
Let's edit our source code to fix this error :
const myFunction = (): string => {
Stage it & commit :
$ git add .
$ git commit -m "My commit message"
Great, the commit has been made ! If you look at :
return 'This my function !'
You should notice that both quotation marks have been replaced by apostrophes thanks to Prettier.
Conclusion 👏
Well done ! You've successfully setup a linting mechanism on your workspaces thanks to Husky 👌
If you have any question about this article, feel free to ask it in the comments.
Have a nice day :)
Top comments (0)