Puis-je installer un package NPM à partir d'un fichier javascript exécuté dans Node.js? Par exemple, j'aimerais avoir un script, appelons-le "script.js" qui installe en quelque sorte (... avec NPM ou non ...) un paquet généralement disponible via NPM. Dans cet exemple, j'aimerais installer "FFI". (npm install ffi)
Il est en effet possible d'utiliser npm par programmation, et cela a été décrit dans les versions précédentes de la documentation. Depuis, il a été supprimé de la documentation officielle, mais existe toujours sur le contrôle de source avec la déclaration suivante:
Bien que npm puisse être utilisé par programme, son API est destinée à être utilisée par la CLI uniquement, et aucune garantie n’est donnée concernant son adéquation à une quelconque autre but. Si vous souhaitez utiliser npm pour effectuer des tâches de manière fiable, la solution la plus sûre consiste à appeler la commande npm souhaitée avec arguments appropriés.
La version sémantique de npm fait référence à la CLI elle-même plutôt qu'à la API sous-jacente. Il n'est pas garanti que l'API interne reste stable même lorsque la version de npm indique qu’aucune modification radicale n’a été apportée selon semver.
Dans la documentation d'origine, voici l'exemple de code fourni:
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)
// command succeeded, and data might have some info
})
npm.registry.log.on('log', function (message) { ... })
})
Comme npm existe dans le dossier node_modules
, vous pouvez utiliser require('npm')
pour le charger comme n'importe quel autre module. Pour installer un module, vous voudrez utiliser npm.commands.install()
.
Si vous avez besoin de chercher dans la source, c'est aussi sur GitHub . Voici un exemple de travail complet du code, qui équivaut à exécuter npm install
sans aucun argument de ligne de commande:
var npm = require('npm');
npm.load(function(err) {
// handle errors
// install module ffi
npm.commands.install(['ffi'], function(er, data) {
// log errors or data
});
npm.on('log', function(message) {
// log installation progress
console.log(message);
});
});
Notez que le premier argument de la fonction install est un tableau. Chaque élément du tableau est un module que npm tentera d’installer.
Une utilisation plus avancée se trouve dans le fichier npm-cli.js
sur le contrôle de source.
oui. vous pouvez utiliser child_process pour exécuter une commande système
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);
}
});
si vous voulez aussi une sortie, vous pouvez utiliser:
var child_process = require('child_process');
child_process.execSync("npm install ffi",{stdio:[0,1,2]});
de cette façon, vous pouvez regarder l'installation comme vous le faites sous la main et éviter les mauvaises surprises (mémoire tampon pleine, etc.)
ça peut être un peu facile
var exec = require('child_process').exec;
child = exec('npm install ffi').stderr.pipe(process.stderr);
J'ai eu une sacrée occasion de faire en sorte que le premier exemple fonctionne dans un répertoire de projet, en publiant ici au cas où quelqu'un d'autre le trouverait. Autant que je sache, NPM fonctionne toujours bien chargé directement, mais comme il suppose CLI, nous devons nous répéter un peu les réglages:
// 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);
});
});
Je suis l'auteur d'un module qui permet de faire exactement ce que vous avez en tête ... Voir live-plugin-manager .
Vous pouvez installer et exécuter pratiquement n'importe quel package à partir de NPM, Github ou d'un dossier.
Voici un exemple:
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();
Dans le code ci-dessus, j'installe le package moment
au moment de l'exécution, le charge et l'exécute. À la fin, je le désinstalle.
En interne, je n'exécute pas npm
cli mais je télécharge des packages et je l'exécute dans un sandbox de noeud VM.
pacote est le paquet que npm utilise pour récupérer les métadonnées et les archives de paquets Il possède une API publique stable.
Une excellente solution de @hexacyanide, mais il s'est avéré que NPM n'émet plus d'événement "log" (au moins à partir de la version 6.4.1). Au lieu de cela, ils s'appuient sur un module autonome https://github.com/npm/npmlog . Heureusement, il s’agit d’un singleton. Nous pouvons donc atteindre la même instance que NPM pour les journaux et s’abonner aux événements de journal:
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" );
});
});
Comme vous pouvez le constater d'après le code, NPM émet également des métriques de performance sur la variable process
, afin que nous puissions également l'utiliser pour surveiller les progrès.