Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

npm script hook on multiple scripts

I've got a reasonably easy question about pre-script hooks.

In my package.json, I've got a couple of commands that all should run the same pre-script. I already have a way to do it, but I'm wondering if there's a more efficient way of doing this.

Current implementation

{
    "scripts": {
        "myproject:run": "npm run custom.prescript && ng serve ...",
        "myproject:prod": "npm run custom.prescript && ng serve -env=prod ...",
        "myproject:build.devserver": "npm run custom.prescript && ng build -env=dev ...",
        ...
        "myproject:build.prodserver": "npm run custom.prescript && ng build -env=prod ...",
        "custom.prescript": "..."
    }
}

This works all fine and dandy, but I hope there's a cleaner way to implement this as I have about 20 of these scripts that need that same pre-script. When I have to change the command for some reason, I will have to do that 20 times for every project in the repo (about 5 projects).

I know that there's a way to add pre-scripts by creating a script with the same name and the prefix 'pre' to make sure it runs before that specific script, but that doesn't work for multiple scripts, as far as I know.

Example of my goal

{
    "scripts": {
        "myproject:run": "ng serve ...",
        "myproject:prod": "ng serve -env=prod ...",
        ...
        "secondproject:run": "ng serve ...",
        "secondproject:prod": "ng serve -env=prod ...",
        ...
        "premyproject:*": "...",  // Runs before all 'myproject:*' scripts
        "presecondproject:*": "..."  // Runs before all 'secondproject:*' scripts
    }
}

Is there a more efficient way to accomplish this, or do I HAVE to do it like I'm doing it already?

Thanks for your time! :)

like image 827
M Zeinstra Avatar asked May 03 '26 20:05

M Zeinstra


1 Answers

I want to expand on the comment from @pqnet above:

package.json scripts are not really good for doing complex things...

Read that sentence several times if you have to. Tools like grunt and gulp are good, but I have found that those add a lot of unnecessary complexity to what should be a rather simple process. What you are currently doing is not bad because it's very clear what is going on. I totally understand your sentiment:

When I have to change the command for some reason, I will have to do that 20 times for every project in the repo (about 5 projects).

However, updating a bunch of scripts can be a simple find/replace which only happens a couple times a year. In general, I can pretty definitively say that you don't want to introduce any "magic" in the way npm scripts are run. Even the built-in pre/post hooks are a bad idea for several reasons:

  • It creates a lot of confusion when you have scripts that call other scripts which call other scripts and some of them have pre/post hooks - it's difficult to see the entire picture of what's going on and you spend a lot of time trying to figure out the correct order of things. Once you have it all figured out, then another person on your team comes and messes it up while you are out of town and nobody can figure out how to fix it (this happened to me before... it sucked).
  • Sometimes you don't want the hooks to run... how do you go about that? More CLI options? Yuk, no thank you!
  • Some words actually start with the letters "pre" or "post"... and things get really confusing when you have scripts such as "prepoulate" or "postfix", etc... and then someone later defines a script named "populate" or "fix" without realizing that they are activating some unwanted "magic" (this has also happened to me before - it sucked).
  • There are other reasons to avoid the "magic"... I suggest you google about it. I stopped using pre/post hooks years ago and never regretted it.

In virtually every app I've ever developed, I eventually needed to run lots of scripts similar to what you are doing... especially as I started using monorepos and managing complex projects with complex builds. In such cases I create actual JS/TS files and manage the complexity with code - it's much easier to read and it's much easier to compose complex pipelines. I know this is not what you want to hear... and I'm sure I'll get some downvotes, but I highly recommend you don't fall into the hooks trap.

If you decide to take my advice, there are some tools that I use on a regular basis to make my life easier:

  • tsx - write scripts in TS and execute them with npx tsx <path_to_file>.
  • zx - execute bash commands from JS/TS
  • commander - turn your script into a respectable CLI tool with options and subcommands
  • prompts - enhance your CLI by prompting users for additional information

Hope that helps.

like image 119
Ryan Wheale Avatar answered May 05 '26 10:05

Ryan Wheale