NPM pre,post scripts are just strange

by: Artur Dziedziczak

June 7, 2021

Introduction

This one will be quick and probably a lot of you know about it but I noticed that this can really cause problems especially when your package.json grows and your environments are called production and preproduction or prod and preprod

First a question

Find a bug in this package.json

Listing 1. Bugged package.json
{
  "name": "npmwhy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "preprod-release": "echo preprod-release",
    "prod-release": "echo prod-release"
  },
  "author": "",
  "license": "ISC"
}

Have you spot it? Let’s say we want to release production

Listing 2. Output after npm run prod-release
➜  npmwhy npm run prod-release

> npmwhy@1.0.0 preprod-release
> echo preprod-release

preprod-release

> npmwhy@1.0.0 prod-release
> echo prod-release

prod-release

So yes. It first invoke preprod-release and then prod-release. Maybe for you it does not sound strange but for me it’s pretty sick. npm has some sugar in it like npm start, npm stop, npm restart, npm test but I get that. People wanted to simplify their life with these

I find these pre and post prefixes to be over-engineering. So what problem do they really solve?

The thing that want to be achived is simplification of such constructs

Listing 3. Scripts that are depending on each other without pre and post
{
  "name": "npmwhy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "prod-release": "npm run start-pre-prod-release; echo prod-release;",
    "start-pre-prod-release": "echo run-pre-prod-release"
  },
  "author": "",
  "license": "ISC"
}

But is this a bad code? I don't think it is. It is more composable than pre and post prefixes. With this approach you can have more scripts invoked in between

It also does not put restriction on names of your scripts

Ok here is the last example…​

Listing 4. Who's That Pokemon?
{
  "name": "npmwhy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "prepreprepreprod-release": "echo prepreprepreprod-release",
    "preprepreprod-release": "echo preprepreprod-release",
    "prepreprod-release": "npm run preprepreprod-release; echo prepreprod-release;",
    "preprod-release": "echo preprod-release",
    "postpreprod-release": "echo postpreprod-release"
  },
  "author": "",
  "license": "ISC"
}
duck
Figure 1. Is this Haskell?
Listing 5. No! It's JavaScript!
➜  npmwhy npm run "preprod-release"

> npmwhy@1.0.0 prepreprod-release
> npm run preprepreprod-release; echo prepreprod-release;


> npmwhy@1.0.0 prepreprepreprod-release
> echo prepreprepreprod-release

prepreprepreprod-release

> npmwhy@1.0.0 preprepreprod-release
> echo preprepreprod-release

preprepreprod-release
prepreprod-release

> npmwhy@1.0.0 preprod-release
> echo preprod-release

preprod-release

> npmwhy@1.0.0 postpreprod-release
> echo postpreprod-release

postpreprod-release

Conclusion

If you want to read more about this particular npm feature you can do it on official npm documentation [1]

I'm done. Next weekend is full of exams

Sources

[1] “Scripts | Npm Docs.” https://docs.npmjs.com/cli/v7/using-npm/scripts