Install npm package on postinstall

1.1k views Asked by At

I have an npm package that has a peer dependency. I wrote a short postinstall script that will prompt the user to install the peer dependency, but it doesn't work.

As you will see from the output below, it looks like npm is downloading the package, but it's not appearing anywhere in the project, not on package.json and not in node_modules.

I'm running on ubuntu 16.04 btw

Here's what happens when I install the npm package:

➜  codeMentorTutorial npm i ../react-native-gradle-config

> [email protected] postinstall /home/adam/apps/codeMentorTutorial/node_modules/react-native-gradle-config
> node lib/addScriptsToPackageJson && node lib/installPeerDependencies
...
This package has a peer dependency "replace", which is not installed in your project.
would u like to install it now? [Y/n]
installReplace
installReplace err, res null [email protected] /home/adam/apps/codeMentorTutorial
└─┬ [email protected] 
  ├── [email protected] 
  ├─┬ [email protected] 
  │ ├── [email protected] 
  │ └── [email protected] 
  └─┬ [email protected] 
    ├── [email protected] 
    └── [email protected] 


closing rl!
closing rl!
[email protected] /home/adam/apps/codeMentorTutorial
├── [email protected] 
└── UNMET PEER DEPENDENCY replace@*

npm WARN [email protected] requires a peer of replace@* but none was installed.

And here's the script:

// this script install the peer dependency "replace" at the 
// consumer project of this package on postinstall
const fs = require('fs')
const path = require('path')
const readline = require('readline');
const packageJsonPath = path.resolve(getRootPath(), 'package.json')
const { exec } = require('child_process')

const package = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))

if (doesReplaceExists()) {
  return
}

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

promptUser()
  .then(parseAnswer)
  .then(userAgrees => userAgrees && installReplace())
  .then(rlClose)
  .catch(console.error)
  .then(rlClose)

function promptUser () {
  return new Promise((resolve, reject) => {
    rl.question('This package has a peer dependency "replace", which is not installed in your project.\n' +
      'would u like to install it now? [Y/n]', resolve);    
  })
}

function parseAnswer (answer) {
  return answer.match(/^y(es)?$/i) || answer === ''
}

function installReplace () {
  console.log('installReplace')
  return new Promise((resolve, reject) => {
  // also tried without the cd command
    exec(`cd ${getRootPath()} && npm install --save-dev replace`, (err, res) => {
      console.log('installReplace err, res', err, res)
      if (err) {
        reject('error installing replace: ' + err)
        return
      }
      resolve()
    })
  })
}

function rlClose () {
  console.log('closing rl!')
  rl.close()
}

function doesReplaceExists () {
  return package.dependencies && package.dependencies.replace ||
    package.peerDependencies && package.peerDependencies.replace ||
    package.devDependencies && package.devDependencies.replace
}

function getRootPath () {
  return path.resolve(__dirname, '..', '..', '..')
}

I want to have this postinstall script on its own repo, so other npm authors could use easily copy it to their own projects.

Any ideas? Is this even possible?

0

There are 0 answers