How to share scripts inside a monorepo

02/07/2022
Blog post image

Have you come across the pain of duplicating scripts across your monorepo?
Well, I have.


Whenever we added a new package to our monorepo we had to write the same scripts:

{
  "scripts": {
    "test": "jest",
    "format": "prettier ./src/**/*.{ts,tsx,css} --list-different",
    "check-types": "tsc",
    "lint": "eslint ./src --ext .js,.jsx,.ts,.tsx"
  }
}

If we had to change one of them, we would have had to change it for all packages.
What a tedious task.


However there are solutions for this problem which I'm about to share with you.

Solution 1: scripty

scripty is a package which solves this problem by storing all your scripts as bash or sh scripts in a folder.


The above snippet would then look like:

{
  "scripts": {
    "test": "scripty",
    "format": "scripty",
    "check-types": "scripty",
    "lint": "scripty"
  }
}

When executing a script, scripty resolves the key of the script for example test to the script with the same name inside that scripts folder.

This served me well for a long time and you should check it out if you're facing the same problem.


However I recently ran into problems when upgrading yarn to v2. Luckily I found another solution which I liked even more because it doesn't even need an extra dependency:

Solution 2: Yarn global scripts

I found it quite amusing that I hadn't heard of this small feature of yarn. Whenever you add a colon to a script it becomes globally available. You can read more about it on the website.


It's pretty straight forward. In your root package.json add scripts:

{
  "scripts": {
    "g:test": "cd $INIT_CWD && jest",
    "g:format": "cd $INIT_CWD && prettier ./src/**/*.{ts,tsx,css} --list-different",
    "g:check-types": "cd $INIT_CWD && tsc",
    "g:lint": "cd $INIT_CWD && eslint ./src --ext .js,.jsx,.ts,.tsx"
  }
}

And use them in your local package's package.json like so:

{
  "scripts": {
    "test": "g:test",
    "format": "g:format",
    "check-types": "g:check-types",
    "lint": "g:lint"
  }
}

That's it!

Conclusion

In the end it's up to you which solution you prefer:

If you like to write each script in a dedicated file and if you prefer bash scripting go for scripty.

If you don't want to add extra dependencies and if you like npm scripts go for yarn's solution.

Have fun.