How to solve missing peer deps in npm? - npm

There are a number of questions here on SO, which deal with the problem of conflicting/missing peer dependency, but they all seem to be directed at a very specific library (or got no answer at all).
I would like to know how to solve this problem in general. When a dependency requires a specific version of another lib and I have a newer version installed (example: React 17.0.1 as project dependency, react#^15.3.0 || ^16.0.0-alpha, required by react-virtualized-auto-sizer#1.0.4), how can I fix this situation?
So far I ignored the warning and the application seems to work fine. But I don't want to rely only on the current appearance.
Somewhere I read that such "local" versions are resolved (by NPM) by placing the 4th party dep in a sub node_modules folder of the lib, which requires it, but I haven't seen this happening.

Related

Given an npm package, how do I know whether it will work in browser?

I've recently installed some npm package (recommended Kubernetes client) for my react app.
After writing code that uses the package and deploying the code for testing I got some weird errors about missing functions or packages. Then I've read the documentation and realized that the package was Node-only.
Is there any way to check that the npm package works in browser before writing code that uses the package?
Python packages specify compatible python versions. Do npm packages have something like this whether they indicate support for particular Node versions and the browsers?
Some packages/libraries contain .browserlistrc file which I've found to be a starting point to find out the browsers and platforms the devs intend to support or have their code compile for. While it may not always be true and the package might just be able to support a browser that isn't mentioned, it's a good starting point. It surely helps to find out if IE (the bane of front-end dev) is supported or not.
Then again many packages don't necessarily include a .browserlistrc. You can then check the package.json for a "browserslist" field.
If neither are found, you can always clone the repo and add your own .browserlistrc in the root with queries that will let you know if the package supports your intended browser or platform - little more work but yeah it can help. Not full proof but a decent enough way to find out.
Though the best answer is really to just ask the maintainers.

Is it possible to specify a runtime dependency of a code generator?

I am working on an npm package that is used as a CLI to generate code. It makes sense that this project should generally be used as a devDependency.
But the generated code will require a third-party library at runtime. Is there a way to manage this dependency via package.json? I have seen other libraries include a note in the README that defines this dependency, but there is no guarantee that the end user will read this README, so I would like to be able to enforce this.
One thought I had was to use a preinstall script to validate that this third-party library was already installed, otherwise throw an error and don't allow the user to install. But that feels like more of a hack than a solution.
I anticipate someone saying "but won't it be obvious when none of the generated code works?" which is absolutely correct, but ideally this process should fail well before runtime.
I am not sure the specifics really matter here, but my package generates boilerplate TypeScript code for an API project, from an OpenAPI spec, and depends on Express.js at runtime.
This sounds like a peer dependency. You can specify a peer dependency in package.json with the peerDependencies key.
In npm 6, missing peer dependencies will result in a warning.
In npm 7, missing peer dependencies are installed.

Managing dependencies while working on a react-native library locally

I'm trying to develop a modification to an existing react native library (the library in question is this one, although hopefully the answer to my question will be generally applicable to any library development work. I have an existing application that I would like to use with a modified version of this library. I'm not quite sure how I can set this up so that the library can coexist with the app and both build processes run correctly when the library is modified. I'm happy to run a command to update the app when the library changes, although I'd like to avoid that if possible. In case it's relevant, I'm working on a Mac.
Things I've tried:
Cloned the existing library into a parent directory of my app (so they're project/myapp and project/react-navigation-tabs)
Then used npm link ../react-navigation-tabs from the app directory, which appeared to succesfully set up the link, but when I tried to test the app, the react native packaging server complained that importing "react" was an ambiguous reference (because both project/myapp/node_modules/react and project/react-navigation-tabs/node_modules/react existed)
Removed the link produced in the last step and tried npm install ../react-navigation-tabs instead. This again apparently succeeded, but then the react native packaging server complained that it 'couldn't find preset "react-native" relative to directory "project/react-navigation-tabs"'. The preset in question is installed in the project/myapp/node_modules directory, but it seems that the packager expects it to be installed in both locations.
So:
Is there any way of persuading npm to only install the necessary libraries in one location and share them? Or alternatively install the development dependencies in both locations?
Is there another way of organising the project that will allow me to perform the updates I need without needing to install dependencies in two separate locations? This is complicated by the fact that the library in question will (presumably) need transpiling before it can be used.

How to make npm use the lowest version that matches all requirements

We're using NodeJS for some projects and are faced with an issue that must have a simple solution (seeing as nobody else seems to have the problem).
In the packages.json there are a bunch of dependencies mentioned with a minimum version, each of which may have overlapping dependencies of their own. The default way a dependency is added is using the ^ operator which seems to mean 'compatible with' or 'same major version, but minor versions may differ'.
The way I understand npm to work is on npm install to take the highest minor version available that matches. Unfortunately 'compatible with' is not quite as enforced as you'd hope.
The situation this puts us in is that for instance on a developer machine version 1.1.0 is installed, but between development and publishing a new version 1.2.0, that has a bug, is introduced. On our build machine a fresh build is made which ends up using 1.2.0 and we've introduced a bug that wasn't there in development.
We tried changing the ^ operator to = for instance, but this gives us trouble when dependencies have subdependencies that aren't compatible with the requested version.
All in all I'm a bit confused, but this thing keeps biting us anytime something changes since the development machines don't do anything on npm install if the package is already there, but the build machine always gets fresh copies.
I know from NuGet that it always takes the lowest version that matches all combined requirements. Since this is always the same for a given set of dependencies, I much prefer this approach. Is there a way to make npm work like this too?
To answer my own question:
npm has introduced a new command npm ci which does something similar to npm install but enforces that the specific versions are used that were also used when a package was initially added by using the package-lock file.
See https://docs.npmjs.com/cli/ci for more information

How do you deal with people removing npm package versions?

Today I found that an npm package version, Babel 6.0.15, that my application relies on had been removed from npm.
This caused compilation failure on a new pc, and I had to go manually find the closest available version for it, and all the cascading version changes it affected on related packages.
What is the best of way of dealing with npm packages, now that I know they can go missing at any time?
Do you check your node_modules folder into source control?
Is there a rule on npm about what versions (major, minor, etc) may be removed by the creator, and which are more 'long term support' and must be retained?
How do you get npm locally to inform you when 'npm update' fails on a new pc, rather than silently failing?
After thinking about this for a while I wrote a blog post summarising what I think is best practice. Reproduced below:
Summary
Specify exact versions of all npm modules, e.g. “alt”: “0.17.8”
Commit your node_modules folder into source control
Don’t use DefinitelyTyped or any other external library Typescript definition tools
Why?
Some of these principles might be controversial, so here’s my reasoning:
Specify exact versions of all npm modules
Semver (semantic versioning) says that breaking changes should occur only if the major version changes. So you should be able to say just “alt”: “0.17”
But I’ve found in practice that even patch changes (bugfixes) can break your application – because libraries that rely on these library often expect some tiny behaviour in a particular version not to change. So in order for all your particular versions of particular libraries to work, they need to rely on exact versions of other libraries.
Commit your node_modules folder into source control
I first assumed that all versions of famous npm libraries would remain there indefinitely. But I then discovered that creators often remove old versions of their software from npm – which then breaks the cascading chain of exact version number dependencies you’ve configured for your app.
Yes, committing all your npm libraries will take up space in your repository, but they’re text files after all, not .DLLs, so they’ll get compressed really small. And the alternative is one day not being able to compile your app at all on a new computer because a library has been completely removed from npm.
Don’t use DefinitelyTyped or any other external library Typescript definition tools
It’s wonderful to be given compile errors for external tools you use. But I’ve found it’s not worth the effort because:
there’s no way to match the definition file version number and npm library version number, so you get definitions that are out of sync with the library you are using
they often have bugs
the type bugs you catch at compile time are probably going to occur in your own app, not in how you call external libraries
Instead of using .d.ts files for external libraries, just say:
declare module 'lodash'
{
let x: any;
export = x;
}
Or use the –allowJS flag in Typescript 1.8 onwards.