Use latest major version - node.js

In my JavaScript applications I may be declaring a few dozen dependencies in my package.json file.
It would take a while to go through each one of those dependencies and see which version they are on.
I just want to say: use the latest major version, but not the bleeding edge.
As an example, with a tool like Git I don't usually care about taking changes at the patch-level but if a new major release comes out I will want it.
Is there a similar concept when specifying the version of a npm module?

NPM packages (theoretically) use SemVer.
In SemVer, packages get a version number of X.Y.Z.
Z indicates bug fixes. Y indicates new features without changing existing ones. X indicates a major version that breaks backwards-compatibility.
Doing npm install --save <package> will result in a version string in your package.json like ^2.3.9, which means "anything in the 2.* range greater than or equal to 2.3.9". This'll mean you get bug fixes and non-breaking new features, but you won't unexpectedly be updated to a version 3.0.0 that breaks your application.
Note: I say "theoretically" because not everyone sticks to SemVer's ideal. You may find a 2.3.9 -> 2.3.10 upgrade that breaks stuff at times. Tests are handy here.

Using npm i -S <pkg> should normally do the right thing.
A few caveats:
The above assumes if you are taking a runtime dependency on <pkg>. In installing a developer tool (like grunt) use -D or -G instead of -S.
Semantic versioning rule 9 says that publishers MAY identify pre-release versions using a suffix like -beta. Npm depends on it, so if package publisher FAILS to do it, you might take a dependency on a pre-release package without knowing it. Sophisticated npm publishers should know better, and sophisticated npm consumers should check the documentation.
A major version is '0' indicates the package is still in initial development, and the package SHOULD NOT be considered stable. (Semantic versioning rule 4.)
Consider using npm dist-tag ls <pkg> to see if there is some package-specific tag that identifies your intent better than latest. If so, use npm I -S <pkg>#<tag> to track that tag.
You can always use npm outdated to check if you dependend directly on a package with a new major release might want to consider upgrading to. It is by-design that major version upgrades do not happen automatically.
npm-installnpm-dist-tagsemantic-versioning

Related

How do I exclude insecure package.json transient dependencies?

I have a package.json that gives a load of security warnings. Looking at the first critical item I see its open#0.0.5 which hasn't been updated for five years. Looking at npm ll it is included by npm#6.5.0 where I am using the latest that was updated about two weeks ago.
I would like to remove the insecure dependencies. In the Java world the maven package manager lets you put exclude certain transitive dependencies. Ideally, with npm or another node package manager, I should be able to exclude dependencies with vulnerabilities. Then I can retest that my app works and not see any security errors. Is there a way to quickly exclude anything that has a security vulnerability from my package.json? If there isn't a way to do this what approaches can a take to ensure that no insecure packages are used by my application?
Update: Although "npm": "^6.5.0" is specified in the package.json I was building it with an older npm which was picking up the critical issue mentioned above. I fixed all the issues with ./node_modules/.bin/npm audit fix --force
By definition, you can't exclude a package that a dependency you are using relies on. In other words, if you require package A, and package A claims it is dependent on package B, then removing package B will cause A to either stop working altogether or begin behaving erratically.
Unfortunately this does happen, and your options include:
Ignoring the security warning.
Replacing package A with something else (applies in some cases and not others).
Asking the maintainer of package A to upgrade the version of package B they rely on, possibly opening a pull request yourself.
In your case, though, I'm not sure if your investigation is complete yet - I don't see open in npm's dependency list. Might be worth scrapping your node_modules and re-running npm install, then check again to see who is using open.
This specific warning is targeting at your lockfile, and can be easily fixed by removing the yarn.lock or package-lock.json and reinstall dependencies.
Tarn package manager has feature resulution by which you can set fixed libraries to insecure thirdparties.
See
How do I override nested dependencies with `yarn`?
NPM has something similar.

Installing an npm module as a devDependency of itself

Let's say I've made a TDD tool called foo, and I want to use foo v1 to help me develop foo v2.
But when I npm install --save-dev foo#^1.0.0, npm says "Refusing to install foo as a dependency of itself".
Why does npm refuse to do this?
What can I do instead?
Workarounds I've got so far (and why they're not good enough):
Workaround 1: just require the relevant script directly using a relative require, e.g. require('../lib') (this is how mocha does it, and it's how I've been doing it so far).
but if you're working on a new version of your module, adding features, perhaps even removing old features, then you're constantly having to alter not just the content of your tests but also their format, because you're actually using the thing you're working on to test the thing you're working on. If it breaks, you have to fix it in the dark with no tests to guide you. It would be much better to use the settled v1 API for tdd-ing the new v2 API.
Workaround 2: publish a duplicate of your module to npm under a different name, like "foo-clone". (Then you can just install foo-clone as a devDependency of foo.)
but that seems messy and a misuse of npm. Anyway, if installing an exact clone would work, then what would be the harm in npm allowing me to install [an old version of] foo as a devDependency of foo?
Here is a better alternative to your Workaround 2.
Let's assume that you'll only need this dependency on early stage of development. So, before publishing first production-ready version you'll get rid of it, e.g. by adopting mocha solution (using current stable version to test itself).
In this case, instead of publishing duplicate package you could temporary rename your package (i.e. postfix it with -dev).
To guarantee that this renamed package will not be published, you could also add private flag.
So, your dev package.json will look something like:
{
"name": "mytdd-dev",
"version": "2.0.0-dev",
"private": true,
...
"devDependencies": {
"mytdd": "1.x.x",
...
},
...
}
Then, when your package will be ready for the first release, you'll remove all -dev postfixes, private flag and dev dependency on previous version.
The only problem with this solution is that you won't be able to publish early dev versions of your TDD tool to npm (as long as you'll depend on previous version).
if installing an exact clone would work, then what would be the harm in npm allowing me to install [an old version of] foo as a devDependency of foo
I think it's a safety precautions against circular dependencies.
If you believe that npm should make an exception for devDependencies here, which sounds reasonable to me, then you should post your suggestion to npm issues tracker.

nvm vs nave vs n | packages processing comparsion

Node.js is sometimes confusing when it comes to version management...
I am trying to arrange various projects as i am doing with ruby projects. For example:
With ruby i can create file such as .rvmrc and fill with something like rvm --create use 1.9.3#my-app
This thing creates and uses all gems specifically to configured gemset. Which allows to have various options for any kind of project, and switch easily among them. So ruby does this in one place.
I want to achieve this for node.js projects.
Node works differently. I want to know the details about that, and especially of each node version management tool.
The point is to know which version management tool for which goal...
And why there are so many.
More accurately: i want npm install <package-name> to chosen node version. And after switching to other versions, this installed package to be missing, or have different version installed before (or certain one). Just like gemset is working.
I've been looking for clarification too:
Both allow switching & installing between node versions.
nvm will symlink the different versions to /usr/local/bin/node, and n will move your node installs to the path (/usr/local/bin/node).
n downloads and installs binary files, and nvm downloads, compiles, installs from the source.
I don't fully understand the latter part of your question, but in regards having control with node projects/apps, you can use npm install [package_name] --save-dev to save your npms within your 'project'.
These npm module versions (^semver) get detailed in your package.json file, for example "gulp": "^3.8.5" is different from "gulp": "3.8.5" (the later being specific to v3.8.5, and the ^3.8.5 means allowing any future version of 3, but not 4.0.0)
The differences between npm and gem is that npm installs the specified packages in the local node_modules folder (the current working directory using the --save-dev), so you have less worries with cross project module versions.
Important note: Running --save (instead of --save-dev) installs any missing dependencies.
I hope that helps a little :o)
Just tried to install nvm and it works for switching from one version to another. In header of nave.sh it says "# This program contains parts of narwhal's "sea" program, as well as bits borrowed from Tim Caswell's "nvm"", so you might try both and see the tiniest difference. Also check the "popularity" of each and contributors to get some insight). There is also a nodeenv which uses python, but I don't any reason why use python here. So, my answer would be no big difference.

Advantages of bundledDependencies over normal dependencies in npm

npm allows us to specify bundledDependencies, but what are the advantages of doing so? I guess if we want to make absolutely sure we get the right version even if the module we reference gets deleted, or perhaps there is a speed benefit with bundling?
Anyone know the advantages of bundledDependencies over normal dependencies?
For the quick reader : this QA is about the package.json bundledDependencies field, not about the package.
What bundledDependencies do
"bundledDependencies" are exactly what their name implies. Dependencies that should be inside your project. So the functionality is basically the same as normal dependencies. They will also be packed when running npm pack.
When to use them
Normal dependencies are usually installed from the npm registry.
Thus bundled dependencies are useful when:
you want to re-use a third party library that doesn't come from the npm registry or that was modified
you want to re-use your own projects as modules
you want to distribute some files with your module
This way, you don't have to create (and maintain) your own npm repository, but get the same benefits that you get from npm packages.
When not to use bundled dependencies
When developing, I don't think that the main point is to prevent accidental updates though. We have better tools for that, namely code repositories (git, mercurial, svn...) or now lock files.
To pin your package versions, you can use:
Option1: Use the newer NPM version 5 that comes with node 8. It uses a package-lock.json file (see the node blog and the node 8 release)
Option2: use yarn instead of npm.
It is a package manager from facebook, faster than npm and it uses a yarn.lock file. It uses the same package.json otherwise.
This is comparable to lockfiles in other package managers like Bundler
or Cargo. It’s similar to npm’s npm-shrinkwrap.json, however it’s not
lossy and it creates reproducible results.
npm actually copied that feature from yarn, amongst other things.
Option3: this was the previously recommended approach, which I do not recommend anymore. The idea was to use npm shrinkwrap most of the time, and sometimes put the whole thing, including the node_module folder, into your code repository. Or possibly use shrinkpack. The best practices at the time were discussed on the node.js blog and on the joyent developer websites.
See also
This is a bit outside the scope of the question, but I'd like to mention the last kind of dependencies (that I know of): peer dependencies. Also see this related SO question and possibly the docs of yarn on bundledDependencies.
One of the biggest problems right now with Node is how fast it is changing. This means that production systems can be very fragile and an npm update can easily break things.
Using bundledDependencies is a way to get round this issue by ensuring, as you correctly surmise, that you will always deliver the correct dependencies no matter what else may be changing.
You can also use this to bundle up your own, private bundles and deliver them with the install.
Other advantage is that you can put your internal dependencies (application components) there and then just require them in your app as if they were independent modules instead of cluttering your lib/ and publishing them to npm.
If/when they are matured to the point they could live as separate modules, you can put them on npm easily, without modifying your code.
I'm surprised I didn't see this here already, but when carefully selected, bundledDependencies can be used to produce a distributable package from npm pack that will run on a system where npm is not configured. This is helpful if you have e.g. a system that's not networked / not on the internet: bring your package over on a thumb drive (or whatever) and unpack the tarball, then npm run or node index.js and it Just Works.
Maybe there's a better way to bundle up your application to run "offline", but if there is I haven't found it.
Operationally, I look at bundledDependencies as a module's private module store, where dependencies is more public, resolved among your module and its dependencies (and sub-dependencies). Your module may rely on an older version of, say, react, but a dependency requires latest-and-greatest. Your package/install will result in your pinned version in node_modules/$yourmodule/node_modules/react, while your dependency will get their version in node_modules/react (or node_modules/$dependency/node_modules/react if they're so inclined).
A caveat: I recently ran into a dependency that did not properly configure its dependency on react, and having react in bundledDependencies caused that dependent module to fail at runtime.

NodeJS and NPM : problems following recommendation to check modules into git

I'm having problems following the 'official' recommendation to check in all external dependencies into git (article http://www.mikealrogers.com/posts/nodemodules-in-git.html linked fron FAQ)
How do you make sure that not only top-level dependencies are checked-in? Most npm modules do currently not follow the recommendation. They all have their node_modules in .gitignore . Just Deleting their .gitignore seems risky.
For compiled module the article recommends to check-in only the sources and run 'npm rebuild' and deploy time. Unfortunately 'npm rebuild' does not do a 'clean make' for all modules (despite bugfix https://github.com/isaacs/npm/issues/1872 being included in npm version 1.0.106 i'm using). This means that I have to prevent compile targets from being checked in (otherwise i would have object code compiled for the developer machine on the production machine without being overwritten by npm rebuild). But: how do i do this? Unfortunately the modules don't have a common compile output directory, so just git-ignoring "node_modules//build" and "/node_modules//out/" (as mentioned in this good article eng.yammer.com/blog/2012/1/4/managing-nodejs-dependencies-and-deployments-at-yammer.html won't help in every case.
Short version: how do you make sure that production servers use the exact same version of all dependent modules as you use during development?
UPDATE: there is now npm shrinkwrap which solves the problem of locking down exact dependency versions, even of dependencies' dependencies! More info here.
Checking in node_modules can be problematic, as the environment it's running on may differ from user to user - so what is compiled on some environment may not work on another. Plus it would fill up your changelogs and repositories with 3rd party code. Which I take it is the conslusion you've come to with your short version of the question, so let me address that.
Short version: how do you make sure that production servers use the exact same version of all dependent modules as you use during development?
Inside your package.json, there will be dependencies: {}, if it is not there, then add it. To accomplish what you want, add your dependencies as the key, and their exact versions as the value. E.g. dependencies: { docpad: '2.5.0', mocha: '1.1.0' }
However, generally (it depends on the author) upgrades to the revision number (the x.x.X number) are just bugfixes and safe. You can allow minor changes by doing dependencies: { docpad: '2.5.x', mocha: '1.1.x' } which saves you from having to update your package.json and do a release everytime there is a bugfix release. You can even do things like 2.x if you wish.
This is the solution I've come to use for all of my modules, as it ensures that even 6 months later or whatever the module will still work - whereas doing something like >= 2.0.0 means when v3 of a dependency comes out, your module will probably be unusable at that time. Ensuring you stick to specific versions "guarantees" stability over time.
For reference you can see how I've done it in my open-source node.js modules here
About the .gitignore of your dependencies (in "node_modules"), npm 1.1 ignores the .gitignore files, so that they are not installed;
npm 1.1 will exclude .gitignore files from the things it installs.
npm 1.0 did not have this feature, so you have to be careful about that.
Deleting them recursively is fine:
find node_modules -name .gitignore | xargs rm
But, in npm 1.1, you never have to do this, because it excludes them
from the install automatically.
That's coming from the chief himself (Isaac), and it's here and seems to cover pretty much everything. The "extraneous" problem I have must be something silly I've done, I'll try a clean setup.

Resources