commander.js: Commander incorrectly assumes that process.argv[0] is 'nodejs' and argv[1] is script name

Command assumes that the first value in process.argv is the name of the nodejs executable being used, and the the second value is the name of the script which was passed to nodejs.

This is mostly fine except in the situation where a packaged electron app is used. For a packaged app a custom binary is used (typically with the name of the app) and it automatically calls the main.js script at start up. It’s process.argv starts with the name of the exe and immediately the first of the user supplied arguments.

A possible solution may be to add an extra method which only takes the list of arguments. The calling application would then be responsible for extracting the real arguments from process.argv. (The method could also just return the parsed results and not modify the commander object. See #183 )

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 8
  • Comments: 15

Commits related to this issue

Most upvoted comments

What about this:

if (process.defaultApp != true) {
  process.argv.unshift(null)
}

It works for me using both electron and electron-packager generated executable, and it seems to be the “official” way to handle this.

Obviously implementing this on the library itself would break some existing workarounds, so I would keep the existing behaviour by default, and add a parameter to normalize the arguments. For example something like this:

/**
 * Parse `argv`, settings options and invoking commands when defined.
 *
 * @param {Array} argv
 * @param {Boolean} normalize
 * @return {Command} for chaining
 * @api public
 */
Command.prototype.parse = function(argv, normalize) {

For some reason the workarounds posted here didn’t really do it for me. So here is mine:

let exe = process.argv.shift()
if(!process.argv[0] || process.argv[0] && process.argv[0] !== '.') {
  process.argv.unshift('')
}
process.argv.unshift(exe)

commander.parse(process.argv)

It just forces your process.argv to always start with ['<yourelectronexe>', '.'], so commander can properly parse it. No matter the enviroment you’re in (dev or packaged).


Edit: You will run into problems when passing the current directory via ., e.g. meview .. As a temporary workaround pass ./ or precede the dot with other arguments.

Edit 2 Better workaround if you use electron-builder or similar, which renames the electron executable:


let execPath = process.execPath.toLowerCase()
if(execPath.endsWith(pkg.name) || execPath.endsWith(pkg.name + '.exe')) {
  let exe = process.argv.shift()
  process.argv.unshift('')
  process.argv.unshift(exe) 
}

In dev mode, your execPath will contain electron and in production the execPath will have the name of your app as the executable name.

it doesn’t work in all scenarios, but this worked when executing with electron app.js and executing the electron-builder generated binnary, in this case app:

if (process.argv.length > 2 ) opts.parse([""].concat(process.argv));

Possible API for an options parameter to .parse() to specify different conventions for the passed arguments:

// default node style process.argv, { format: 'node' }
.parse(['node', 'script.js', 'serve'])

// No script parameter, such as Electron when process.defaultApp==true
.parse(['electron.exe', 'serve'], { format: 'execPath' })

// No leading special arguments
.parse(['serve'],  { format: 'args' })

node references: