How to prevent an unused npm dependency to be installed? - node.js

So in my project, I require multiple packages, including "dep1".
"dep1" requires another dependency, "dep2".
And "dep2" requires multiple packages, including "dep3".
The problem is, "dep3" is not compatible with the licence I want to use (well actually, with the licence my boss wants to use).
Fortunatly, only one function of "dep2" uses "dep3", and "dep1" does not use this function. So if I remove "dep3" from node_modules, all will go smoothly.
The problem I have is, how to modify package.json to take this into account when doing npm install, and not install this package ?
I am aware I could branch "dep2" to supress the function, and then "dep1" to use the modifies "dep2", but this seems overkill, and I would be dependant of the owner of the packages to accept my branch. I am looking for a solution like 'well, just add the line ignore : "dep3" into package.json', but can't find any.
Thanks for your help !

The obvious way is to remove unwanted dependency from node_modules in NPM postinstall hook.
Alternatively, a stub can be provided instead of dep3. A stub should contain package.json that will identify it as a substitute with matching version:
{
"name": "dep3",
"version": "VERSION THAT MATCHES DEP2 CONSTRAINT"
}
It can be specified as local dependency in dep:
...
"dependencies": {
"dep3": "./dep3-stub",
...
Or as Git dependency:
...
"dependencies": {
"dep3": "github-user-name/dep3-stub",
...
If version constraint matches, dep3 stub will be installed and used instead of real package, otherwise dep2 may install its own copy of dep3.
I am aware I could branch "dep2" to supress the function, and then "dep1" to use the modifies "dep2", but this seems overkill, and I would be dependant of the owner of the packages to accept my branch.
This is a reasonable approach. This is no concern to the owner. dep2 fork can be used instead of dep2 NPM package in the same way as shown for dep3.

Related

NPM how to install package as it was another

want to install package com.cordova.plugin.cache and its content i need it to be also as cordova-plugin-cache..
Example package.json was like this:
"dependencies": {
// Note these two are the same but with different name
"cordova-plugin-cache": "git+git#gitlab.com:dev/library/org.git",
"com.cordova.plugin.cache": "git+git#gitlab.com:dev/library/org.git"
}
But i published a modified version both of it on a private npm repository to remove the dependency as a repository.
"dependencies": {
// Note these two are the same but with different package name
"cordova-plugin-cache": "git+git#gitlab.com:dev/library/org.git",
"com.cordova.plugin.cache": "git+git#gitlab.com:dev/library/org.git"
}
Is this even possible? do i have to save both packages as they were two different?
Actually i have one package in a private npm registry, but don't want to duplicate the project.
Any hint is appretiated.
NPM itself has no such feature, it was discussed on their GitHub repository here and it was decided not to implement such a feature.
The solution outlined in this article may prove to solve your problem:
You can utilise the link-module-alias module, add a _moduleAliases section to your package.json that describes the alias you wish to establish and then add a postinstall script that executes the aforementioned module.

Can I override the url npm pulls a package from?

I have a legacy project which depends on a specific version of an npm package which through a dependency chain depends on a specific npm package of phantomjs, the binaries of which are no longer online at the registered location. This breaks the project's build.
Updating package versions is not an option.
I can fool npm by manually fetching the required version of phantomjs and dropping it into my system's download folder, but this is a workaround, I want a cleaner fix, ideally something that sits in a config script.
Can I, in my project's package.json or .npmrc files, force npm to use another url for a package # some version, every time "npm install" is run for that project?
A possible solution is uploading the package to github and proceed as in NPM docs https://docs.npmjs.com/files/package.json#urls-as-dependencies
I figured out that this is possible using npm-shrinkwrap (https://docs.npmjs.com/files/package-locks). Basically, you add an npm-shrinkwrap.json file to your project, alongside package.json. In the shrinkwrap file, you can override any specific package listed in package.json - anywhere in that package's dependency chain, you specify a URL to fetch a dependency package from.
{
"name": "MyProject",
"dependencies": {
"A" : {
"version" :"1.2.1",
"dependencies": {
"B": {
"version": "https://myBForkUrl.git"
}
}
}
}
If MyProject depeneds on package A, which in turn depends on B, but B is unmaintained and has a critical bug, I can roll my own fork of B, fix the bug and host it at https://myBForkUrl.git, without also having to fork A. Based on NPM's documentation it looks like this overriding can be nested as deep as necessary.

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.

Node.js - Are package.json dependencies necessary when installing modules locally?

I know that doing something like this in package.json :
....
...
"dependencies" : {
"some-node-module" : "*"
}
is a bad idea since you're basically telling node to always update this module to its latest version, even though your code might not be able to handle any other version other than the current one for this particular module.
So I should instead do something like this :
....
...
"dependencies" : {
"some-node-module" : "3.4.1"
}
Which basically tells node to always use the version of the module that my code was built around.
Question
I have an app which I've first tested locally. The app has now been built, and using the package.json dependencies, npm has installed all of the appropriate node modules locally under my app's root folder (as opposed to globally, in some obscure folder I don't have immediate access to and which is irrelevant to this app - I simply don't like global installations of node modules - I find them to.. "abstract").
Given that all of the node modules are now installed locally isn't the node modules dependencies part in my package.json now redundant ?
I mean, what if something happens and npm is not available or the specific version of a module can't be found?
Isn't it best to be independent of dynamic node module installations and just have everything installed locally the first time without having to use the package.json dependencies ?
npm install & update
"you're basically telling node to always update this module to its latest version"
Packages won't be automatically updated. The only time the "*" will be an issue is when you are installing the project for the first time via npm install or when you manually run an update via npm update.
I personally prefer to pick a specific version of a module rather than use any wildcards, but even then there are some gotchas...which is why npm shrinkwrap exists.
npm shrinkwrap
Next gotcha:
basically tells node to always use the version of the module that my
code was built around
Sorta true. Let's say you use version 1.2.3 of your favorite module and package.json reflects that, but in the module itself is a package.json dependency on another module and that uses "*"...so when you install, the new internal dependency and the wildcard can wind up breaking the module you thought was 'locked down'.
See the gotcha? Hard coding a version controls for the top level versions but does not enforce anything beneath that...and if a module author you depend upon (or a module they depend upon) uses wildcards, you can't be 100% sure things will be copacetic.
To strictly enforce a version, you'll want to use npm shrinkwrap. (The link there to the docs provides more background, which is good to understand if your project uses more than a few very simple modules.)
And now...your question.
You say:
I mean, what if something happens and npm is not available or the
specific version of a module can't be found?
Based on the first two parts of this answer, it should now be clear that it doesn't hurt to have the dependencies explicitly listed in the package.json because node isn't checking things every time the app runs. npm uses package.json when specific actions (install, update, etc) are called but even then, it is a manual trigger.
While situations vary, there are very few that I can imagine where omitting dependencies in package.json is a good idea. If you ever wind up having to rebuild the project, you'll be in trouble. If the project is so good you want to share it, you'll be in trouble. Heck, if this is something for work and you want to go on vacation and need to install it on another machine...you'll be in trouble.
So given the fact that after the initial install, dependencies have no negative impact...use --save or add the dependencies to your package.json. Your future self will thank you. :)

npm: Where do the children dependencies come from?

I read on github that:
grunt-mocha-test uses npm's Peer Dependencies functionality
I was unsure what "Peer Dependencies" were so I checked the npm docs and found:
npm is awesome as a package manager. In particular, it handles
sub-dependencies very well: if my package depends on request version 2
and some-other-library
Which I take to mean:
Having 'peer dependencies' mean that a dependency could need other
dependencies in order to function correctly.
npm creates a tree like structure, where the dependency is the root,
and the root dependency has children dependencies
The questions I am left with are:
Where do the children dependencies come from? Are they copies? Or are they
references to other dependencies already present in package.json?
Each of them will have a copy of the package. For example, if you have a project with those dependencies:
"dependencies": {
"node-handlebars": "*",
"less-file": "*",
"async-ls": "*",
"promise": "4.0.0"
}
and run npm install, you would have 4 copies of promise (the one you declared as a dependency and 3 others needed from each of the other dependencies)
$ find . -name promise
./node_modules/async-ls/node_modules/promise
./node_modules/promise
./node_modules/node-handlebars/node_modules/promise
./node_modules/less-file/node_modules/promise
Note that this would happen even if every one depends on a specific version of promises package (ex 4.0.0).
Despite looking a little redundant I guess this makes dependency management a lot easier, and nowadays the extra space used in general should be negligible.

Resources