Let's say you have some JavaScript code you want to share among several projects, but you don't want to create a private NPM package yet. Maybe you are just experimenting, and setting things up takes effort. Why bother if it might not work out? Here is how you can quickly push code to a private GitHub repository yet make it available to other projects.
Private repo
I made a private repository bahmutov/private-module-example
on GitHub. It contains a small JavaScript export just for show.
1 | // src/index.js |
I can load this module locally from the project's root folder
1 | $ node |
The package.json
sets the private: true
to avoid accidentally publishing this package to the NPM registry.
1 | { |
I pushed the code to the remote origin
1 | $ git push |
Then I created a tag (same as version) and pushed it too
1 | $ git tag 1.0.0 |
Great, I have 1 release in my private GitHub repository.
Using GitHub repository
I have created another private GitHub repository bahmutov/private-module-example-user
- this repo will install the code from the first repository without going to NPM.
1 | { |
The install command looks almost the same as "standard" npm i <package name@version>
. Only instead of the package name, I can specify GitHub username and repository name, instead of the version, I can specify a commit SHA or a tag. I prefer tags.
1 | $ npm install -S bahmutov/private-module-example#1.0.0 |
My package.json
reflects the installed dependency
1 | { |
Great, but does it work? Let's open Node and load the dependency
1 | $ node |
It is working.
Continuous Integration setup
I will set up continuous integration (CI) server to run "tests" on CircleCI. Here is my .circleci/config.yml
file
1 | version: 2 |
And my test script will just load the private-module-example
module. If the module has not been installed, the npm test
would crash and burn.
1 | { |
1 | $ npm t |
Ok, push code to CircleCI and ... see if fail
1 | #!/bin/bash -eo pipefail |
When Circle connects the new project to the GitHub repository it created an SSH key restricted to that repository. Thus the same key cannot be used to clone another private repository. We need to change this. Go to the project's Settings / Checkout SSH keys
and click the button twice.
Then
Now the build should be able to access clone NPM package from the private repository into this project.
Iterate
Now you can iterate on your first module, and when there are new features or fixes, increment package.json
version (I suggest using next-ver to compute the next version based on commit messages), tag the commit and push the code and tag to GitHub. Then you can point the user project at the new tag, and you are good to go. This avoids private NPM registry, but of course this adds complexity to the CI with the user checkout key. On NPM you would need to use NPM_TOKEN
to authenticate and install your own private modules (and of course pay for private scope).
I use same approach if I need to fix 3rd party NPM module, read Fixing the Internet one NPM package at a time