Действительно, можно использовать npm программно, и это было описано в более старых версиях документации. С тех пор он был удален из официальной документации, но все еще существует в системе контроля версий со следующим утверждением:
Хотя npm можно использовать программно, его API предназначен для использования только с помощью интерфейса командной строки, и не дается никаких гарантий относительно его пригодности для каких-либо других целей. Если вы хотите использовать npm для надежного выполнения некоторой задачи, самое безопасное, что можно сделать, - это вызвать нужную команду npm с соответствующими аргументами.
Семантическая версия npm относится к самому CLI, а не к базовому API. Не гарантируется, что внутренний API останется стабильным, даже если версия npm указывает на отсутствие критических изменений в соответствии с semver .
В исходной документации предоставлен следующий образец кода:
var npm = require('npm')
npm.load(myConfigObject, function (er) {
if (er) return handlError(er)
npm.commands.install(['some', 'args'], function (er, data) {
if (er) return commandFailed(er)
})
npm.registry.log.on('log', function (message) { ... })
})
Поскольку npm существует в node_modules
папке, вы можете использовать require('npm')
его, как любой другой модуль. Чтобы установить модуль, вы захотите использовать npm.commands.install()
.
Если вам нужно заглянуть в исходник, то он также есть на GitHub . Вот полный рабочий пример кода, который эквивалентен запуску npm install
без каких-либо аргументов командной строки:
var npm = require('npm');
npm.load(function(err) {
npm.commands.install(['ffi'], function(er, data) {
});
npm.on('log', function(message) {
console.log(message);
});
});
Обратите внимание, что первым аргументом функции установки является массив. Каждый элемент массива - это модуль, который npm попытается установить.
Более сложные способы использования можно найти в npm-cli.js
файле системы управления версиями.
npm install npm --save
. Пример отлично работает :)npm
имеет множество зависимостей, поэтому добавление его в свой модуль, скорее всего, приведет к тому, что загрузка займет НАМНОГО больше времени. Ознакомьтесь с одним изchild_process
ответов, чтобы использовать глобальный npm, уже установленный на компьютерах ваших пользователей.npm.config
наnpm.load
! Даже @isaacs не знает, какие странные вещи тогда произойдут! См. Github.com/npm/npm/issues/4861#issuecomment-40533836 Вместо этого вы можете просто пропустить первый аргумент.process.cwd()
)npm install npm --save
Вы можете использовать child_process . exec или execSync, чтобы создать оболочку, затем выполнить нужную команду в этой оболочке, буферизуя любой сгенерированный вывод:
var child_process = require('child_process'); child_process.execSync('npm install ffi',{stdio:[0,1,2]});
Если предоставляется функция обратного вызова, она вызывается с аргументами (error, stdout, stderr). Таким образом, вы можете запустить установку, как вы делаете это вручную, и увидеть полный результат.
Метод child_process.execSync () обычно идентичен child_process.exec () за исключением того, что метод не вернется, пока дочерний процесс не будет полностью закрыт.
источник
stdio: [0,1,2]
делать?да. вы можете использовать child_process для выполнения системной команды
var exec = require('child_process').exec, child; child = exec('npm install ffi', function (error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } });
источник
npm.cmd
Вместо этого вы должны позвонить .на самом деле это может быть немного легко
var exec = require('child_process').exec; child = exec('npm install ffi').stderr.pipe(process.stderr);
источник
Я чертовски потратил время, пытаясь заставить первый пример работать в каталоге проекта, размещая здесь сообщения на случай, если кто-то еще найдет это. Насколько я могу судить, NPM по-прежнему отлично работает при прямой загрузке, но поскольку он предполагает использование интерфейса командной строки, мы должны немного повторить настройку:
// this must come before load to set your project directory var previous = process.cwd(); process.chdir(project); // this is the part missing from the example above var conf = {'bin-links': false, verbose: true, prefix: project} // this is all mostly the same var cli = require('npm'); cli.load(conf, (err) => { // handle errors if(err) { return reject(err); } // install module cli.commands.install(['ffi'], (er, data) => { process.chdir(previous); if(err) { reject(err); } // log errors or data resolve(data); }); cli.on('log', (message) => { // log installation progress console.log(message); }); });
источник
pacote - это пакет, который npm использует для получения метаданных пакета и архивов. У него стабильный общедоступный API.
источник
Я автор модуля, который позволяет делать именно то, что вы задумали. См. Live-plugin-manager .
Вы можете установить и запустить практически любой пакет из NPM, Github или из папки.
Вот пример:
import {PluginManager} from "live-plugin-manager"; const manager = new PluginManager(); async function run() { await manager.install("moment"); const moment = manager.require("moment"); console.log(moment().format()); await manager.uninstall("moment"); } run();
В приведенном выше коде я устанавливаю
moment
пакет во время выполнения, загружаю и выполняю его. В конце удаляю.Внутри я не запускаю
npm
cli, а на самом деле загружаю пакеты и запускаю их в изолированной программной среде виртуальной машины узла.источник
Отличное решение от @hexacyanide, но оказалось, что NPM больше не генерирует событие «журнал» (по крайней мере, с версии 6.4.1). Вместо этого они полагаются на отдельный модуль https://github.com/npm/npmlog . К счастью, это синглтон, поэтому мы можем получить тот же самый экземпляр, который NPM использует для журналов, и подписаться на события журнала:
const npmlog = require( "npm/node_modules/npmlog" ), npm = require( "npm" ); npmlog.on( "log", msg => { console.log({ msg }); }); process.on("time", milestone => { console.log({ milestone }); }); process.on("timeEnd", milestone => { console.log({ milestone }); }); npm.load({ loaded: false, progress: false, "no-audit": true }, ( err ) => { npm.commands.install( installDirectory, [ "cross-env@^5.2.0", "shelljs@^0.8.2" ], ( err, data ) => { console.log( "done" ); }); });
Как видно из кода, NPM также генерирует метрики производительности в файле
process
, поэтому мы также можем использовать его для отслеживания прогресса.источник
Другой вариант, о котором здесь не упоминалось, - выполнить форк и запустить CLI прямо из
./node_modules/npm/bin/npm-cli.js
Например, вы хотите иметь возможность устанавливать модули узлов из запущенного сценария на машине, на которой не установлен NPM. И вы действительно хотите сделать это с помощью CLI. В этом случае просто установите NPM в свои node_modules локально при сборке вашей программы (
npm i npm
).Затем используйте это так:
// Require child_process module const { fork } = require('child_process'); // Working directory for subprocess of installer const cwd = './path-where-to-run-npm-command'; // CLI path FROM cwd path! Pay attention // here - path should be FROM your cwd directory // to your locally installed npm module const cli = '../node_modules/npm/bin/npm-cli.js'; // NPM arguments to run with // If your working directory already contains // package.json file, then just install it! const args = ['install']; // Or, i.e ['audit', 'fix'] // Run installer const installer = fork(cli, args, { silent: true, cwd: cwd }); // Monitor your installer STDOUT and STDERR installer.stdout.on('data', (data) => { console.log(data); }); installer.stderr.on('data', (data) => { console.log(data); }); // Do something on installer exit installer.on('exit', (code) => { console.log(`Installer process finished with code ${code}`); });
Тогда ваша программа может быть даже запакована в двоичный файл, например с помощью пакета PKG . В этом случае вам нужно использовать
--ignore-scripts
опцию npm, потому что node-gyp требуется для запуска сценариев предустановки.источник