Open DanielSWolf opened 6 years ago
I figured it out myself. 😃
NPM already contains code that locates its config files, parses them, and creates an options object specifically for use with pacote. The only downside to using this code is that it's deep within the NPM package and isn't part of the "official" NPM API. So any new NPM release may contain a breaking change.
Here's a working example:
const npm = require('npm');
const pacoteOpts = require('npm/lib/config/pacote');
const pacote = require('pacote');
async function main() {
await new Promise((resolve, reject) => {
npm.load(error => { if (error) reject(error); else resolve(); });
});
const opts = pacoteOpts();
const package = await pacote.manifest('lodash@1.0.0', opts);
console.log(package);
}
main();
The project to extract npm's config library is very very big, very complicated, and full of landmines. We're in the middle of chipping away at that monstrosity, and I definitely hope we have a standalone npm config reader/parser/manager at some point. In the meantime, your hack will work with the current version of pacote.
Word of warning: as part of that refactor, I'm going to be changing the API for pacote's opts
MASSIVELY, and the code you're using for this will break with pacote@9
once that's released. But it should make it much, much easier to integrate pacote with npm's config. Stay tuned, and be warned :)
Thanks for your explanations! So I'll stick with my hack for the time being.
If possible, it would be great if you could update this issue once there is a clean solution for reading the NPM configuration.
I probably won't be able to do that. Tracking all the issues I get pinged on is a bit tricky as-is, so I'll almost certainly fail to do this.
I notice that npm@6.6.0 replaced /lib/config/pacote
with /lib/config/figgy-config.js
, so my original hack doesn't work any more. What's the recommended way of reading the NPM configuration for pacote now?
You should be able to use libnpmconfig
Are the two directly compatible? That is, can I do this:
const config = require('libnpmconfig').read();
const package = await pacote.manifest('lodash@1.0.0', config);
Or do I have to transform the configuration first?
require('libnpmconfig').read()
will return an object with the fields defined here: https://docs.npmjs.com/misc/config#config-settings
pacote.manifest
expects the options defined here (+ other pacote-specific opts): https://www.npmjs.com/package/npm-registry-fetch#fetch-options
For most of these options, they're directly compatible (e.g., registry
, cert
, ca
), while others (at first glance) don't appear to be named the same (e.g., scope
vs project-scope
), so you may need to do the mapping yourself if you care about those options
I need to download NPM packages and get the exact same results a local NPM installation would. However, there seems to be one major difference: NPM looks for an
.npmrc
file. If it exists, settings such as the NPM registry and authentication information are taken from this file.Pacote, on the other hand, seems to ignore
.npmrc
files. Unless explicitly given different options, it always useshttps://registry.npmjs.org
as registry and doesn't perform any authentication.Is there a way to make pacote behave identical to NPM? I could of course locate
.npmrc
myself, parse it, and pass the results to pacote. But I feel that this code must already exist somewhere.