52

Is it possible to install npm package only if it has not been already installed?

I need this to speed up test on CircleCI, but when I run npm install protractor@2.1.0 etc. it always downloads things and installs them from scracth, however, node_modules folder with all modules is already present at the moment of running commands (cached from previous build) and protractor --version etc. shows the needed version of the package.

Its perfect to have some one-line command like this:

protractor --version || npm install -g protractor@2.1.0

but the one that will also check version of the package.

kovpack
  • 4,905
  • 8
  • 38
  • 55

5 Answers5

56

You could try npm list protractor || npm install protractor@2.1.0

Where npm list protractor is used to find protractor package.

If the package is not found, it will return npm ERR! code 1 and do npm install protractor@2.1.0 for installation

An Nguyen
  • 577
  • 1
  • 4
  • 4
  • 2
    Short and simple. Best one-liner here – Sanctus Oct 10 '19 at 18:04
  • 2
    I'm on npm v6.0.1 and it doesn't appear `npm list ` quits with an error, it just returns a list with "(empty)" in it. – MattTreichel Jan 12 '21 at 21:11
  • 1
    With the newer npm version, `npm list ` won't show `npm ERR! code 1` but it does exit with an error. Therefore, the whole command `npm list || npm install ` still works. – An Nguyen Jul 14 '21 at 15:49
23

with bash you can do

[ $(node -p "require('protractor/package.json').version") != "2.1.0" ] && npm install protractor@2.1.0
Jerome WAGNER
  • 21,986
  • 8
  • 62
  • 77
10

Function version of the excellent answer by @JeromeWAGNER:

function install_package_if_needed() {
    local p=${1:-Package required}
    local v=${2:-Version required}
    shift 2
    local i=$(node -p "require('$p/package.json').version" 2>/dev/null)
    [ "$i" == "$v" ] || npm "$@" install "$p@$v"
}

Use like:

$ install_package_if_needed protractor 2.1.0

To pass additional options to npm, specify them after the version, like so:

$ install_package_if_needed protractor 2.1.0 -g
bishop
  • 37,830
  • 11
  • 104
  • 139
  • Yeap, thanx. I did something like this, but called multiple system commands from ruby. But exactly this version is not applicable for my task. – kovpack Jun 05 '15 at 21:45
  • Thanks for this. But needed to remove >/dev/null else $i will always be empty. – Daryl Teo Dec 13 '15 at 04:35
  • @DarylTeo Thanks! You're right. Not sure what I was thinking. Fixed! – bishop Dec 14 '15 at 14:35
  • How can this be generalized to install a package globally, if missing? At the moment it clearly does not accept `-g` flag. Thanks. – nirvana-msu Sep 13 '17 at 10:37
2
[ $(node -p "try{require('protractor/package.json').version}catch(e){}") != "2.1.0" ]  && npm install grunt
John Weisz
  • 30,137
  • 13
  • 89
  • 132
theJC
  • 325
  • 2
  • 6
0

I had this same issue together with wanting to install global dependencies from any "package.json" file requiring them.

This is for a Windows development environment.

Here is my solution.

Community
  • 1
  • 1
sthames42
  • 888
  • 8
  • 19