Skip to content

cli: implement node --run <script-in-package-json>

Rodrigo Muino Tomonari requested to merge github/fork/joyeecheung/node-run into main

This stemmed from a twitter thread: https://twitter.com/matteocollina/status/1622514656878161920. I was just curious to find out how slow/fast a JSON.parse() and execSync would be compared to npm run, and whether the difference is significant enough that a pure C++ implementation (like what deno task does) would make sense. On my server, with this:

{
  "scripts": {
    "hello": "echo \"hello\""
  }
}

npm run hello runs for ~330ms, out/Release/node --run hello runs for ~35ms (~3-4ms overhead over starting up a no-op process), and a similar deno.json + deno task hello runs for ~5ms (that just does everything in native, no JS involved).

I don't feel very strongly about this patch (I personally feel it's more of the package managers'/user-land CLIs' job to simplify their workflow to reach this speed for this type of commands). So there are no tests and no proper error handling here (yet), and it probably needs a bunch more work to be closer to what people expect from these commands (e.g. handling env var or cross-platform support for shells). But since I already wrote this to find out about the numbers anyway, and it feels wrong to just ignore that 330ms -> 35ms difference and pretend that nothing happened, might as well open a PR even just as food for thought ;) A fully C++ implementation is possible too, though I am not sure a 35ms vs 5ms difference is really worth the effort. This is just trying to see what difference can be made with minimum effort.

EDIT: After more discussions I realized that this actually also makes sense even not for the sake of performance. To quote myself below:

If the user uses yarn to manage their package.json, it's best to use yarn run. If they use npm to manage their package.json, it's best to use npm run. But what if they don't use any package managers (yet?) and just have a hand-written package.json? node --run would be a natural choice.

And in this case, supporting any features that's not commonly shared by most package managers would be a non-goal. It would make sense to ensure that upgrading from node --run to npm run, yarn run, et.al results in as fewer breakages as possible (or do not incur breakages that would not happen when switching between package managers), but not the other way around. Just like switching from Node.js built-in modules (e.g. fs) to the "enhanced" third-party versions of them (e.g. fs-extra) would usually be non-breaking, but it definitely does not happen the other way around.

Merge request reports

Loading