Satisfying peerDependencies with devDependencies in npm3 - javascript

So NPM 3 has removed automatic resolving of peer dependencies which is great, however in the scenario of developing a plugin/library to be consumed by an application elsewhere if I make the underlying library use peerDependencies which is the correct notion here, it means if anyone wants to work on that library they need to manually resolve all dependencies.
So rather than having them do that it seems logical that I could put the same dependencies into devDependencies to satisfy the local development scenario, so anyone consuming it would need to explicitly satisfy the peers, anyone developing the library further would get the peer dependencies for free via the devDependencies.
So the question is, is there anything wrong with that? as I can find very little info on how to sensibly handle peerDependencies in NPM3 in any automatic fashion.
=== Update ===
As mentioned in the comments, when I tried doing things this way it is not compatible with earlier versions of npm, so npm >= 3.0 work fine with this approach and it satisfies the criteria automatically for a developer to check out npm install and be productive, however if you were to do this on an earlier version of NPM it blows up around peer dependencies not met and does not seem to work.
I post this as I hope this incompatibility with earlier versions is somehow down to my incompetence in some way so I can both support ease of development for people who just want to npm install on this package to develop for it, but also previous versions. So if you know a better way or a way around this or other issues this introduces please speak up.

I was asked to post this as the answer so here you go:
As mentioned in the comments, when I tried doing things this way it is not compatible with earlier versions of npm, so npm >= 3.0 work fine with this approach and it satisfies the criteria automatically for a developer to check out npm install and be productive, however if you were to do this on an earlier version of NPM it blows up around peer dependencies not met and does not seem to work.
I post this as I hope this incompatibility with earlier versions is somehow down to my incompetence in some way so I can both support ease of development for people who just want to npm install on this package to develop for it, but also previous versions. So if you know a better way or a way around this or other issues this introduces please speak up.

Related

Installing Node js manually vs with package managers

I installed Node.js on Mac last year by just downloading it from nodejs.org. However, i have noticed that it is usually installed via some package managers like Homebrew(bad way) and NVM(good way). Question 1: Should i uninstall current Node.js and install it via NVM(which i don't even have)? Question 2: Is switching between Node version common? And why would someone do that?
Using NVM is a good idea indeed!!. There may be different projects that use different versions of NodeJs. In that situation, a library like NVM would be pretty helpful else you have to uninstall the old version and install the new one. You know how hard it is to uninstall and reinstall a new one each time you want to have a new version. Moreover if you want to try some new feature that is shipped in a newer version of Nodejs, you have to go through the installation/uninstallation process again.
So using NVM would create a sandbox like environment where one version on Node won't mess with another one.
Long story short, NVM would be helpful.After you install NVM, it's just a matter of doing NVM install 'nodeversion' and NVM use 'nodeversion' to use a particular version of Node.
Chances are you could be working on different projects which are based on different versions of node. nvm could help in this case.
It’s also very helpful if you want to verify whether your application works on different versions of node or not.
In general it’s nothing different with python2/3, different version of JDK, etc. You can stick with your current installation and switch to nvm only if it’s necessary. You will know when you need it.

Caret, tilde, or fixed package.json for large production app?

I have a large react app in production and I'm wondering if its best to use fixed versions for my packages? I've heard that using the caret (^) is a good practice, but that seems to me that it would leave the application open to more bugs?
I've googled this issue quite a bit, and there seems to be a split between ^ and fixed versions. Is there a definitive answer somewhere in the (npm) docs on what approach to use?
During development you can choose whichever you're comfortable with, but I would recommend shrinkwrapping just before you begin testing the app, before going into production. Lock down the dependencies with:
npm shrinkwrap
This command repurposes package-lock.json into a publishable npm-shrinkwrap.json or simply creates a new one. The file created and updated by this command will then take precedence over any other existing or future package-lock.json files. For a detailed explanation of the design and purpose of package locks in npm, see npm-package-locks.
That way you can leave the dependencies declared in package.json as they are (tilde/caret), but the exact versions declared in npm-shrinkwrap.json will only ever be used when npm installing.
I've personally had a problem just before going into production, when a dependency declared with ~ (the stricter one) was updated and introduced a bug (which shouldn't happen for a patch/bug fix). It's only ever happened once, but I would't want to tempt fate.
You can always update your npm-shrinkwrap.json by first doing npm update <package_name> specifying the package that needs updating, then re-doing npm shrinkwrap to update the existing npm-shrinkwrap.json.
...and don't forget npm ci

Deleting `package-lock.json` to Resolve Conflicts quickly

In a team set up, usually, I have faced merge conflicts in package-lock.json and my quick fix has always been to delete the file and regenerate it with npm install. I have not seriously thought about the implication of this fix because it has not caused any perceivable problem before.
Is there a problem with deleting the file and having npm recreate it that way instead of resolving the conflicts manually?
Yes, it can and will affect all the project in really bad way.
if your team does not run npm install after each git pull you all are using different dependencies' versions. So it ends with "but it works for me!!" and "I don't understand why my code does not work for you"
even if all the team runs npm install it still does not mean everything is ok. at some moment you may find your project acts differently. in a part that you have not been changing for years. and after (probably, quite painful) debugging you will find it's because of 3rd level dependency has updated for next major version and this led some breaking changes.
Conclusion: don't ever delete package-lock.json.
Yes, for first level dependencies if we specify them without ranges (like "react": "16.12.0") we get the same versions each time we run npm install. But we cannot say the same about dependencies of 2+ level deep (dependencies that our dependencies are relying on), so package-lock.json is really important for stability.
In your case you better do next way:
fix conflicts in package.json
run npm install
As easy as it looks. The same to yarn - it fixes lockfile conflict on its own. The only requirement here to resolve all the conflicts in package.json beforehand if any.
Per docs npm will fix merge conflicts in package-lock.json for you.
[Upd from 2021] important! If you use some library already and npm/GitHub account of its maintainer is hacked. And new version with malicious code inside is released. And you have package-lock.json intact. You will be fine. If you drop it you are in trouble.
Yes it can have bad side effects, maybe not very often but for example you can have in package.json "moduleX": "^1.0.0" and you used to have "moduleX": "1.0.0" in package-lock.json.
By deleting package-lock.json and running npm install you could be updating to version 1.0.999 of moduleX without knowing about it and maybe they have created a bug or done a backwards breaking change (not following semantic versioning).
Anyway there is already a standard solution for it.
Fix the conflict inside package.json
Run: npm install --package-lock-only
Check out this link for more info:
https://docs.npmjs.com/cli/v6/configuring-npm/package-locks#resolving-lockfile-conflicts
I know it's an old question but for future seekers, you can also use npm-merge-driver which try to automatically resolve the npm related files' merge issues.
Just install it globally npx npm-merge-driver install --global. You can read more about it here npm-merge-driver
Edit: Just want to warn people, who are interested in using above package, that sometime it can behave erratically and difficult to remove. So although it is a useful tool, it still need some work.
Edit: This repository is now archived and read only.
npm i --force does the work for me

How did the unpublishing of npm left-pad break code?

I've been reading up on the npm left-pad fiasco, but I'm somewhat confused by how it happened. I think I have a misunderstanding of how npm actually works. If the developer of left-pad unpublished the package, I assume npm install left-pad wouldn't work anymore. However, for users who had already installed it, won't left-pad still be in the node_modules folder? Wouldn't the developers of say, Babel, have to remove and reinstall left-pad for npm to realize that the package has disappeared? I am clearly missing something, but I'm not sure what.
When I run npm install babel, left-pad is not bundled in babel but rather is expressed as dependency in it's package.json file. So npm then has to go find left-pad and download it as well. So if you were installing left-pad or anything using left-pad for the first time, you wouldn't be able to. While this means you're safe if it already exists in your local directory, the project would fail to build properly as soon as it is built somewhere else. For example, a CI server that does a clean build from scratch for each new changeset would fail to build any project that relies on left-pad. Or if you were checking out a project for the first time, or deploying it to a new server, you wouldn't be able to build.
This is simple to fix if you were relying on left-pad directly. Just write a replacement and update your code to use the replacement. But when it's required deep in your dependency tree, say by Babel, it's unlikely you can refactor Babel or other modules on your own to use a left-pad replacement. You'd have to wait for all of the various node module developers to update their modules with something else and republish.
It's not as apocalyptic as news articles made it sounds, but it is a huge inconvenience and throws a wrench in many systems outside of developer workspaces where left-pad was already cached.
As #Lazar said, you understood correctly.
The problem come in that, if Babel is relying on left-pad, and am trying to install Babel, it will fail.
Well, I could always rewrite it myself as a workaround.
But if it is a module used by a module used by a module used by... used by Babel, or more module, you face a real nightmare, because Babel can't do anything, nor can you, and you are forced to wait that every single module develloper relying on left-pad update their code.

Node / npm: How to manage globally installed devDependencies

I'm building a Node module with devDependencies that should be globally installed, such as jasmine-node and jshint. What I essentially need is to be able to reference their binaries in my makefile / npm scripts section to run tests, lint, etc. In other words I do not wish to require() them programmatically.
After digging around I'm still confused on how to handle this:
1) My first approach was to assume that these modules would be globally installed, clarify this in my module's documentation and reference their binaries as globals - i.e. expect them to be globally available. This conflicts with this piece of advice
Make sure you avoid referencing globally installed binaries. Instead, point it to the local node_modules, which installs the binaries in a hidden .bin directory. Make sure the module (in this case "mocha") is in your package.json under devDependencies, so that the binary is placed there when you run npm install.
(taken from this post)
This generally sounds right, as the aforementioned setup is rather fragile.
2) My next approach was explicitly including those modules in devDependencies (although they are still globally installed on my system (and most probably on users' & contributors' systems as well)). This ensures that appropriate versions of the binaries are there when needed and I can now reference them through node_modules/.bin/.
However I'm now in conflict with this piece of advice
Install it locally if you're going to require() it.
(taken from npm docs)
Regardless of that, I do notice that npm install will now actually fetch nothing (display no network activity) for the globally installed modules.
My questions:
Are the local versions of globally installed modules (that are mentioned in devDependencies) just snapshots (copies) of the global ones, taken during npm install?
Is 2) the correct way to go about doing this? or is there some other practice I'm missing?
Here's my personal take on this, which is decidedly divergent from node.js common practice, but I believe it is an overall superior approach. It is detailed in my own blog post (disclaimer about self-promotion, yada yada) Managing Per-Project Interpreters and the PATH.
It basically boils down to:
Never use npm -g. Never install global modules.
Instead, adjust your PATH to include projectDir/node_modules/.bin instead
Revisiting my own question a couple of years after it was originally written, I feel I can now safely say that the quoted 'advice'
Install it locally if you're going to require() it.
does not stand anymore. (It was part of the npm docs but the posted 2-year old link gives me a 404 at the time of this writing.)
Nowadays, npm run is a fine way to do task management / automation and it'll automatically export modules which are installed locally, into the path before executing. Thus, it makes perfect sense to locally install modules that are not to be require()d such as linters and test-runners. (By the way, this is completely in line with the answer that Peter Lyons provided a couple of years ago - it may have been 'decidedly divergent from node.js common practice' back then, but it's pretty much widely accepted today :))
As for my second question
Are the local versions of globally installed modules (that are mentioned in devDependencies) just snapshots (copies) of the global ones, taken during npm install?
I am pretty confident that the answer is No. (Perhaps the lack of network activity that I was observing back then, during the installation of local modules which were also globally installed was due to caching..?)
Note, Nov 12 2016
The relevant npm docs to which the original question linked have moved here.

Categories

Resources