NPM Github Dependencies
A whole new kind of dependency hell
I like small modules. But if you don't have your own private NPM registry, how do you make sure they can be resolved?
The answer seems simple: just add a github dependency. And I agree. It sounds great.
1st Stab: Getting started
My tiny module that I wanted to include in another module lived inside a private github repository. Let's just say it lived in wspringer/tiny
. So why not add it as a dependency, since that's what NPM is expected to support:
"dependencies": {
"tiny": "wspringer/tiny"
…
}
The good news is: it does actually work, but whenever you run npm install
, you always need to enter your username and password.
2nd Stab: Get rid of authentication
And there is more good news. There is a way to prevent you from having to continously enter your username and password. Which is good news, since we're deploying to Heroku, and I have no way of entering my git username and password while I'm deploying to Heroku.
In order to prevent you from having to continuously pass your username and password, you need to generate an access token and add that to your dependency:
"dependencies": {
"tiny": "git+https://{token}:x-oauth-basic@github.com/wspringer/tiny.git"
…
}
3rd Stab: Get NPM to do the right thing
This is the trickiest bit. It turned out that my tiny module was actually getting included in the node_modules
folder, but then again it didn't have the index.js
where I expected it to be. In fact, it wasn't included at all.
I checked a couple of things, since I had been running into similar isssues before when publishing to the NPM registry:
Delete .npmignore
Delete my .npmignore
file; this is something that hurt me before. By including files in the .npmignore
file, my prepublish build script would never find any sources. So instead of using an .npmignore
file, I decided to use a files
section in my package.json
.
Set the files attribute
Instead of using .npmignore
, I decided to set the files
attribute explicitly:
"files": [
"lib/index.js",
…
]
Go nuts
Regardless of what I did, nothing worked. Eventually, I stumbled across this thread. It turns out that running things in prepublish doesn't work with github dependencies. That's weird. But it doesn't. So to make sure it does run with a github dependency, you need to explicitly force your prepublish to run in the postinstall phase:
"postinstall": "node -e \"require('fs').readdir('lib',function(e)\
{e&&require('child_process').exec('npm run prepublish')})\"",
Note quite there yet
I like my npm modules with sources. That might just be my Scala background: I also don't stick my sources in the jars I'm publishing. However, if that's what you do, even if you add the postinstall task, that postinstall task will not be able to find your sources. NPM has already hidden them for you.
So what you need to do is to make it work for real, is explicitly add your src
folder as well:
"files": [
"lib/index.js", "src"
…
]
Conclusion
Having the ability to add github dependencies sounds great. But the hoops you need to jump through to make it work are pretty counter-intuitive. Let's hope that NPM issue is getting solved soon.