Skip to content
This repository has been archived by the owner on Jul 6, 2019. It is now read-only.

Commit

Permalink
feat(perf): run node-based commands in the current process
Browse files Browse the repository at this point in the history
  • Loading branch information
zkat committed Jun 21, 2017
1 parent aa40a34 commit 6efcde4
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 11 deletions.
61 changes: 51 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#!/usr/bin/env node
'use strict'

const Buffer = require('safe-buffer').Buffer

const child = require('./child')
const fs = require('fs')
const parseArgs = require('./parse-args.js')
const path = require('path')
const which = promisify(require('which'))
Expand Down Expand Up @@ -74,16 +77,7 @@ function main (argv) {
return existing
}
}).then(existing => {
return child.runCommand(existing, argv).catch(err => {
if (err.isOperational && err.exitCode) {
// At this point, we want to treat errors from the child as if
// we were just running the command. That means no extra msg logging
process.exitCode = err.exitCode
} else {
// But if it's not just a regular child-level error, blow up normally
throw err
}
})
return execCommand(existing, argv)
}).catch(err => {
!argv.q && console.error(err.message)
process.exitCode = err.exitCode || 1
Expand Down Expand Up @@ -182,6 +176,53 @@ function installPackages (specs, prefix, opts) {
})
}

function execCommand (existing, argv) {
return checkIfNode(existing).then(isNode => {
if (isNode && module.constructor.runMain) {
// let it take over the process. This means we can skip node startup!
process.argv = [
process.argv[0], // Current node binary
existing // node script path
].concat(argv.cmdOpts) // options for the cmd itself
if (!argv.noYargs) {
require('yargs').reset() // blow away built-up yargs crud
}
module.constructor.runMain() // ✨MAGIC✨. Sorry-not-sorry
} else {
return child.runCommand(existing, argv).catch(err => {
if (err.isOperational && err.exitCode) {
// At this point, we want to treat errors from the child as if
// we were just running the command. That means no extra msg logging
process.exitCode = err.exitCode
} else {
// But if it's not just a regular child-level error, blow up normally
throw err
}
})
}
})
}

function checkIfNode (existing) {
if (!existing || process.platform === 'win32') {
return Promise.resolve(false)
} else {
// NOTE: only *nix is supported for process-replacement juggling
const line = '#!/usr/bin/env node\n'
const bytecount = line.length
const buf = Buffer.alloc(bytecount)
return promisify(fs.open)(existing, 'r').then(fd => {
return promisify(fs.read)(fd, buf, 0, bytecount, 0).then(() => {
return promisify(fs.close)(fd)
}, err => {
return promisify(fs.close)(fd).then(() => { throw err })
})
}).then(() => {
return buf.toString('utf8') === line
})
}
}

function Y () {
return require('./y.js')
}
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"npm": "^5.0.3",
"npm-package-arg": "^5.1.2",
"rimraf": "^2.6.1",
"safe-buffer": "^5.1.0",
"update-notifier": "^2.2.0",
"which": "^1.2.14",
"y18n": "^3.2.1",
Expand All @@ -53,7 +54,8 @@
"which",
"yargs",
"dotenv",
"y18n"
"y18n",
"safe-buffer"
],
"devDependencies": {
"cross-env": "^5.0.1",
Expand Down
1 change: 1 addition & 0 deletions parse-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ function fastPathArgs (argv) {
p: pkg,
shell: false,
install: true,
noYargs: true,
npm: DEFAULT_NPM
}
}
Expand Down

0 comments on commit 6efcde4

Please sign in to comment.