Node: Feature Request: CLI to run package.json scripts

Created on 27 Mar 2017  路  20Comments  路  Source: nodejs/node

Currently many people use npm run in order to start up applications. In environments without npm this functionality would be very useful I recommend we pull this functionality into core itself.

This has a few things to note/bikeshed:

Wrapper process when running a node child process:

  • extra pid, may cause oddities if trying to get the PID of the application

    • in *nix we can exec() in C to replace current process even if the child is not node

    • in WIN32 we cannot use the current process if the child is not node

  • mostly wasted CPU/mem
  • wraps stdio

Env variables:

  • npm sets up many environment variables.

    • PATH is mutated for the process to include a vendored node-gyp, I am unclear to what extent we want this.

Argv:

  • some things like --inspect are not properly propagated to child processes

I am not seeking to introduce a standards node --run-script build etc. that would run a compile toolchain, not am I seeking to introduce a standard node --run-script install. I would like those to completely delegate to the package.json.

This can somewhat be related to https://github.com/nodejs/node/issues/11903 which would have some entry point with a package.json presumably. It also relates to https://github.com/nodejs/node/issues/11997 which has an idea of process argv delegation.

cli feature request module

Most helpful comment

I very much want this to only look at "scripts", and not a new top level key - there should only be one place in my package.json where I define how to run my tests.

All 20 comments

Maybe node --pkg index like (without the .noderc stuff) in the additional section #11907

In a nutshell if package.json and instead of some .noderc config when passsing a flag run npm i (NODE_ENV !== 'production') or npm i --production (NODE_ENV === 'production')

@michael-ciniawsky can you clarify what index in node --pkg index means?

I've found myself many times wanting to have generic node --run and node --test commands that would address the same basic need as npm run and npm test. Not necessarily as a replacement for those, however, and not necessarily with the same semantics. In fact, we can (and likely should) implement it in a way that is fairly independent and isolated from the normal package.json lifecycle scripts.

For instance,

package.json

{
  "name": "foo",
  "main" "index.js",
  "test": "test.js",
  "scripts": {
     "test": "..."
  }
}

Calling node --run would look specifically at main (in this example index.js) as being the entry point. In other words, node --run is exactly equivalent to calling node index.

If I am in a directory that contains multiple modules in node_modules, and I want to select which one I run... e.g.

  |-- node_modules
          |-- moduleA
          |         |-- package.json
          |         |-- index.js
          |-- moduleB
                    |--package.json
                    |--index.js

(sorry, missed a level in the diagram initially)

Then I could do node --run moduleA. Essentially, the argument for --run is a module name that is resolved with the same semantics as require('...'), with the entry point defined by the main property in package.json. (note that if I were in node_modules, calling node moduleA would already just work, so we're really quite close already)

node --test would work the same, but using a top level test property instead of either main or scripts.test .

There would be no environment variables, no need to keep it semantically the same as npm lifecycle scripts, as the node --run and node --test would simply ignore anything under the scripts property in package.json.

@jasnell people use runners in node_modules/.bin I think that behavior needs to be preserved still.

ok. so perhaps ... node --run {name} would first try to resolve name as a runner in node_modules/.bin, and failing that, would treat it as a module looking for the appropriate package.json entry point? Would there even be a need for a separate node --test then? I could simply throw my test running into node_modules/.bin and have node --run test Just Work.

I really like the idea and few days before I wanted something like that. We already have a lot of forms to run a script in development systems. We've make, npm scripts, gulp, grunt and many others. Porting some of this to the node binary is not an unnecessary overhead?

The scripts would not necessarily need to be ported to the binary. Runner scripts located in node_modules/.bin would just end up being child processes spawned by node at startup, and could be written to use any tool. Essentially the flow would be:

$ node --run foo
  1. Look for ./node_modules/.bin/foo, if it exists, spawn it a a child process, and exit the node binary
  2. If it does not, resolve foo as a module, look for the package.json index entry point and load/run it.

I think we have differing ideas on what this should do, for example webpack, doesn't use main in this manner. Also, some people have bins with different names than their modules so routing could get weird. I am not sure I want foo to ever resolve to the foo package. Then again, I am not wanting to access node_modules/ except to get .bin setup.

Ok, that's fair. Perhaps describe a bit more about what you're looking for?

I was wanting to just run the package.json#scripts of the "current package" (core has not defined this term). In doing so, avoiding the double PID problem of the current npm behavior, setting up the PATH properly for node_modules/.bin, and properly passing argv if a child process is needed like https://github.com/nodejs/node/pull/12028 does.

of note: --require should be well defined for any behavior we think this should take. I think it should generally be loaded after starting up any target script.

@bmeck index is the entry :) index.js which has external dependencies and therefore requires node_modules to run. With a --pkg || --install flag node 'knows' that it needs to install deps/check if node_modules exists first, before it actually runs index.js. The goal is to make it easier to run node e.g in containers with a simple NODE_ENV='...' node --flag entry.js command and the rest is up to node. "Node Package Mode"

@michael-ciniawsky this is not intended to be used for any form of package management/installation. That was discussed in https://github.com/nodejs/node/issues/11835

Following the discussion node --run package => node start && node start package (index || node_module)

I very much want this to only look at "scripts", and not a new top level key - there should only be one place in my package.json where I define how to run my tests.

Discussion on this has gone quiet for a few months. Is there something resembling consensus on how this feature should work? Doesn't look like it to me, but if so, maybe we can add a help wanted label.

If there isn't consensus, maybe the thing to do is close. People can still submit pull requests with proof-of-concept implementations for any approach they feel strongly about.

Agreed. To consolidate the many ideas floating around, people could file an EP at https://github.com/nodejs/node-eps, which is what we usually do for a big feature like this.

For anyone who really wants this badly, there is a little cli app called ipt that creates a dropdown menu from any list you pipe to it.
so cat package.json | jq '.scripts' | ipt | xargs npm run would probably do the trick.

But it looks like there is even a 'workflow' to run npm scripts if you're not a fan of shell aliases.

Having to have jq installed, and an npm package, seems a lot heavier weight than just having npm itself installed and using npm run.

Since #11835 is undead... several people have remarked that the number 1 reason for broken node installs (observe nodejs/help) is in fact npm. Notably, doing an in-place upgrade or downgrade sometimes leaves npm in a broken state.

Node itself is immune to that because it's a single binary. node --pkg install would be immune for the same reason.

(FWIW, I was not in favor of this proposal back in 2017 but the more I think about it, the more it starts to make sense.)

Was this page helpful?
0 / 5 - 0 ratings