Locking in Dependencies Versions

Another thing that could really, really hurt your project is not locking the dependencies. By default, npm uses the caret sign. It's also possible to see and use with npm's package.json an asterisk or a tilde in addition to the caret sign. All of those notations, they're very bad because they allow for different versions to be used in your project. So every time you run npm install, the version could be different. It could be higher than what you tested, what you developed with. It's not a great idea.

Typically, you would see those notations in open source project. They're not safe for your applications. Maybe for open source project they're okay. But for your project, for your application, that's a bad idea. And the reason why they might be okay for the open source project is because they don't want to lock the version and then no one basically, going to update that open source project.

People are busy and the new version might have some good changes. It might patch some vulnerability. It might fix a bug, so they just leave it loose. But when you're working on applications, not on open source modules, you want to lock the versions and not just the first level dependencies such as express but also dependencies of dependencies such as mime-db, negotiator, accepts, etc. So lock all the versions. And how you can do that? First of all, there is a Shrinkwrap which is a solution in the npm itself.

Another approach is to use a version control, such as GitHub, GitLabs, Gitbucket, etc. So you just commit your node modules. We did exactly the same thing at DocuSign and it's not scary. It's actually very good. It gives you sense of control and predictability. The only drawback is that when you add or modify a package, you would see a really huge git diff. You would see all those files that are coming from the package and the dependencies of that package in your git diff.

Then, you can write a shell script that will put your packages in a zip archive and push it to a three or some other cloud storage such as Azure storage. And then, during the deploy, you would pull your artifacts, dependencies or artifacts. So you would pull those artifacts from some type of a repository.

You can also use yarn. I haven't used it myself yet. There would probably be a new course on yarn at Node University, at least a webinar. But you can follow a link that I have in the footnote which says, "Avoid yarn for packages for now." Just an opinion but check it out.

And the last option is to just completely create your own private registry. You can host it using cloud solutions. So this is kind of the most extreme solution. You get a lot of control but then you have to maintain that private registry. You can use some of the open source solutions or paid solutions, enterprise solutions such as Nexus and jFrog Artifactory. They're not just for npm. They also have registries for other packages and package managers. But, obviously, they're harder to set up and they're more for enterprises. That's what we use at Capital One right now. We used to have Nexus. So when you do npm install on our Capital One VPN, our internal network, npm install will not go to the npmjs.org. It would go to the Nexus. But now we switched to jFrog Artifactory and it's also working good. Our experts, they have full control over what versions. Our security people, they can review those versions and manage or, basically, there is nothing that could be updated so we're pretty much safe. So you have full spectrum.

Let's take a look at some of the easy solutions such as npm shrinkwrap. So when you type npm shrinkwrap in your project route, in your project folder, that will create npm-shrinkwrap.js and then later, anyone can execute npm install which will read from that file, npm-shrinkwrap.json, instead of package.json. Here's an example of the shrinkwrap.json file. So, it will have all the dependencies even dependencies of dependencies. And it will have versions and the links to the..in this case, it's a public registry. But again, if you are using your own private registry, that link would be different. And the last option, this is the option that we use at DocuSign, to a great success. We were able to just deploy very easily all the modules for our version controlled. And in our Jenkins continuous integration environment, we're running npm rebuild. Why do you need npm rebuild?

Some modules have just JavaScript and Node.js. In this case, it's totally cool, it's just code. You get the source code from your version control like anywhere else. No problems at all. Other modules typically some database drivers, crypto libraries as well. So those libraries, they might require either C, C++ or Python compilation. So they have some source code and they would need to compile. But because you're not deploying in the macOS environment, you're deploying mostly in Amazon Linux, CentOS, DBM, Ubuntu. So you need to recompile those binaries and that's what npm rebuild is doing. So you have the source code, you don't need to install anything, but npm rebuild will rebuild for all those binaries according to whatever target you're using. And JenkinsCI would use exactly the same, at least it should be exactly the same as your production environment. So add the modules, do "git pull" in your CI and then run npm rebuild.