How to build node package without internet

A way to vendor NPM dependencies

George Shuklin
OpsOps
2 min readApr 12, 2019

--

If you have your CI/CD pipeline for anything made in your company, it must satisfy following properties to keep everyone sane:

  1. The same commit should build into the same binary
  2. There should be a process of building a binary from a source code on local infrastructure only (no internet access at all).

If your build process uses internet at a build time, you can not have neither #1 nor #2. Just imagine NPMJS company been sold to some malicious red company with ferocious lawyers. Use NPM Enterprise! Buy subscription! No access for those without money.

Or, imagine a less onerous scenario: a small quarrel between NPMJS with CDN provider for better prices, with outage of npm repository for …let’s say four days. Do you need to make a new release ASAP? No access to packages? No internet?

So, if you want to have autonomy, you need to have all dependencies locally. Here I describe how to do it with minimal struggle (and at a half price of node_packages size).

How to have offline npm cache

  1. For example purposes we use /work/my_web as a project directory. There is a /work/my_web/.git, /work/my_web/src etc.
  2. Set up a project-local configuration. If you you already have it, update it, if not, create a file /work/my_web/.npmrc:

3. add node_packages into .gitignore file. Commit both changes into git.

4. Run npm ci, or, if you’re using older version:

You will have a hefty download, but that’s ok.

5. Commit .npm_cache into your repository.

That’s all.

If you clone this repository, disable network access, you still be able to build your package:

Moreover (this is linux specific), you can check if you can do this in offline:

This simple trick allow you to have you repository to contain everything you need for offline build.

How to update

If you decide to change something in your dependencies, you need to do this:

It’s very important to save package-lock.json in the same commit as .npm_cache. This is guaranteed you can checkout this commit at any time in the future and to have exact match between lock and it’s cache.

rm for .nmp_cache just help to keep it smaller.

Afterword

Vendoring is bad. Just look at the size of your .npm_cache. Evenso, it’s better to have vendored bloat, then slim ‘something new from internets on each build’.

Leftpad story forced Npmjs to forbid version change and package removal. Nevertheless, this does not fix the problem of ‘internet dependency at build time’. If you have transient internet at build time, you have transient builds, which are mostly ok, except when not.

Next step

I do deb/dpkg packaging of front-ends. I know Dorker fans are appalled, but I knew what I do, and why.

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.