pacote icon indicating copy to clipboard operation
pacote copied to clipboard

How to make pacote respect .npmrc?

Open DanielSWolf opened this issue 5 years ago • 9 comments

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 uses https://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.

DanielSWolf avatar Jul 27 '18 11:07 DanielSWolf

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('[email protected]', opts);
  console.log(package);
}

main();

DanielSWolf avatar Jul 27 '18 11:07 DanielSWolf

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 :)

zkat avatar Jul 27 '18 18:07 zkat

see https://github.com/zkat/pacote/pull/146

zkat avatar Jul 27 '18 20:07 zkat

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.

DanielSWolf avatar Jul 30 '18 06:07 DanielSWolf

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.

zkat avatar Aug 01 '18 23:08 zkat

I notice that [email protected] 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?

DanielSWolf avatar Mar 18 '19 09:03 DanielSWolf

You should be able to use libnpmconfig

chbota avatar Mar 25 '19 20:03 chbota

Are the two directly compatible? That is, can I do this:

const config = require('libnpmconfig').read();
const package = await pacote.manifest('[email protected]', config);

Or do I have to transform the configuration first?

DanielSWolf avatar Mar 29 '19 13:03 DanielSWolf

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

chbota avatar Mar 29 '19 19:03 chbota