Standardise your npm scripts

Imagine this, your team decides to split a monolith application into smaller packages, either in a monorepo or multi-repo, how do you promote standard scripts and ease of use when creating new packages?

Having a standard set of scripts for all the packages has its benefits:

  1. In multi-repo projects, CI/CD pipelines become very easy to create with templates; you can rely on them and use templates instead of hardcoding scripts/jobs.
  2. For Monorepos using Lerna, for example, you can safely run a standard script and know that every package is following that structure.
  3. It's easy to create a new package, either copy-paste from another one, or create a package creator script. If this is easy to do, people will eventually do it more often.
  4. Scripts can be long and prone to error when copying.

Example:

{
  "format:all": "prettier '**/*.{js,jsx,ts,tsx,json,md,css}' --write",
  "format:check": "prettier '**/*.{js,jsx,ts,tsx,json,md,css}' --check"
}

This works well for one project, but when you start creating multiple packages, it becomes very cluttered. Imagine having lint, stylelint, test, and build/dev steps in there too.

Solution

Here’s how I’ve solved this in the past, first create a new prettier package:

  1. package.json
{
  "name": "@company/prettier-config",
  "version": "1.0.0",
  "main": "index.js",
  "prettier": "./index.js",
  "bin": {
    "company-format-check": "bin/format-check.sh",
    "company-format-all": "bin/format-all.sh"
  },
  "dependencies": {
    "prettier": "1.19.1"
  }
}
  1. index.js
module.exports = {
  useTabs: false,
  tabWidth: 2,
  printWidth: 80,
  semi: false,
  trailingComma: 'all',
  bracketSpacing: true,
  arrowParens: 'avoid',
  singleQuote: true,
}
  1. bin/format-check.sh
prettier '**/*.{js,jsx,ts,tsx,json,md,css,yaml}' --check
  1. bin/format-all.sh
prettier '**/*.{js,jsx,ts,tsx,json,md,css,yaml}' --write

Next step is to include it:

yarn add @company/prettier-config -D

package.json

{
  "prettier": "@company/prettier-config",
  "scripts": {
    "format:check": "company-format-check",
    "format:all": "company-format-all"
  },
  "devDependencies": {
    "@company/prettier-config": "1.0.0"
  }
}

Conclusion

This is much more manageable if you move from prettier to something else, it’s easy to do, all the dependencies are in one place and promotes creating new packages with less room for error. I usually use this approach for formatting/lint/stylelint/test/build-lib.

What do you think of this approach?

© 2024