How can I tell node to use a particular installed package version? - node.js

If I have versions 1.1 and 1.2 of package foo installed on my system, and bar.js requires package foo, is there a way to invoke node bar.js so that node uses version 1.1 of foo?

NPM packages that are local to the project stay in node_modules and don't update unless you explicitly update them yourself. You can use NPM's semantic versioning to manage the granularity of your dependencies on a per-project basis. Here's a semver cheat sheet: https://semver.npmjs.com/
With that in mind, where this breaks down is if you're installing modules globally (which you should not be doing unless the package owner tells you to, e.g. Grunt or Angular-CLI). If you are using global modules and you don't need to be, you should fix that ;)
If you find that semantic versioning is causing conflicts for dependencies within your project (e.g. foo requires bar 1.0 and faa requires bar 1.1) OR you are concerned about the risk of breaking dependency changes, take a look at Yarn.

Related

Use latest major version

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

Can npm symlink node modules to a master directory instead of redownloading?

With npm, when a package requires other packages it creates a tree structure of dependencies. Sometimes a lot of these dependencies depend on the same packages from other packages.
I was wondering, would it be possible to make npm so all packages are stores in the global node_modules and any dependency is just symlinked back to the top of the global node_modules. I understand the version issue, and that can just be handled by storing the package with the version name appended, then symlinking to the proper version.
I feel this would speed up installs and reduce disk usage for duplicate files.
(Is this what npm3 is supposed to do?)
Yes, what you propose would be possible (at least on Linux the symlinks are resolved as expected).
npm (in none of its versions) however does not benefit from symlinks. To gain some of the benefits you proposed, newer versions of npm work as follows: if some package is needed multiple times, npm installs the package as high as possible in the dependency tree. This enables using the same dependency by multiple packages.
For example, no matter how many (sub-)dependencies depend on somedep v. ^1.x.x you got only one copy of somedep. This will probably be placed directly in the root node_modules, so that any sub-dependency can require it.
Older versions of npm do not do this automatically, however, you can invoke the similar effect by running 'npm dedupe'.
Note however, that this approach is weaker than proposed in the question: If 3 of your dependencies depend on somedep v. ^1.x.x and 3 other dependencies depend on somedep v. ^2.x.x, npm obviously cannot put both of these somedeps to the parent node_modules.
Also, check out ied project: https://github.com/alexanderGugel/ied . It does something similar to what you propose, but sadly, it installs only one version of each dependency, which is quite limiting.

Why having the same NPM package declared in regular and dev dependency is considered bad?

NPM triggers a warning message: Dependency '...' exists in both dependencies and devDependencies when my package.json explicitly declares the same module in both dependencies and devDependencies. It suggests that the NPM's developers think it is a wrong way of using NPM.
This is surprising to me since I've always considered it a good practice Doing so means I can change (add / remove / update) my "app dependencies" without breaking my build scripts etc.
Do you know the rational behind this view or do you have examples where it could introduce problems?
dependencies and devDependencies are both installed into the node_modules directory at the top level. If you declare it in both sections, you might declare it at different versions (or conflicting version ranges), which would it impossible for npm to meet both requirements at the same time.
In practice, if you declare it in both sections, npm will pick the version declared in dependencies, even if it is older, since this is usually what you meant to happen.
As a corollary: if you update your app dependencies to a version that would break your build scripts, it will break your build scripts, and declaring it twice won't help.

Dependencies versions conflicts on node.js

I'm new to the node.js world and I was asking how I could handle dependencies versions conflics (which often appears with transitive dependencies): on the internet found only this article useful for me http://nodejs.org/api/modules.html#modules_addenda_package_manager_tips.
So it seems that i don't have to worry about conflicts because of how the packages are managed in node.js. Am I wrong, am I missing something? This seems strange (but still makes sense) to me, I'm used to handle dependencies with maven, setting the transitive dependencies that don't have to be downloaded.
Any help is appreciated, thank you.
npm and the node require system will take care of this for you automatically. For example, your program can depend on dep1 and dep2. dep1 can require subdep version 1.0 and dep2 can require subdep version 2.0, and npm will install multiple versions so each module gets the dependency versions it needs.
your-module/
node_modules/
dep1/
node_modules/
subdep/ (1.0)
dep2/
node_modules/
sudbep/ (2.0)

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.

Resources