In the package.json file, I have a line in the scripts object like this:
"scripts": {
// some commands..
"runpackage": "someNpmPackage -args"
}
This someNpmPackage is a package I have in my node_modules, but not in the command line. (i.e. I can run the command in the terminal).
This works fine. However, I want to be able to do in the scripts: "runPackage": "node scripts/runPackage.js"
I try something like
var exec = require('child_process').exec;
exec('someNpmPackage -args', function (err) {
if (err) {
console.log(err.message);
process.exit();
}
console.log('success');
});
But all I get is, /bin/sh: someNpmPackage: command not found.
How can I make the exec function know about this package?
Why don't you install the someNpmPackage globally in your system?
Try in the root project folder, on the command line: ./node_module/.bin/someNpmPackage. If this command works, then it should work with exec.
Related
I am working on my class project in which I want to demonstrate the use of mongoDB sharding. I am using mongoDB node.js native driver. I got to know there is no sharding functionality in this driver. So, I have to write shell script to do sharding. So, Is it possible to do this somehow like this:
node myfile.js (executes my shell script and run my code)
Given that you already have a shell script, why not execute that through the Child Process module. Just use the below function to run the script that you have.
child_process.execFileSync(file[, args][, options])
Note that the script should have run permissions(use chmod a+x script otherwise)
why don't you consider using npm run scripts?
if you want the script to run standalone, add scripts with test/start or both to your package json,
"scripts": {
"test": "node mytestfile.js",
"start": "node ./myfile --param1 --param2"
},
and run npm run test or npm run start which can execute the script file. this way you can even pass parameters to the script.
or the elegant child_process way,
const { exec } = require("child_process");
exec("node myfile.js", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
stderr and stdout will show the progress of the script as you build further.
hope this helps.
I'm trying to run node commands like npm install and node server.js using a bat file.
I'm planning to put the bat file in the application root folder.
So, the steps I want my bat file to do are:
Open command prompt in the same folder.
Run npm install
Run node server.js
You can create a .bat file and you can execute it with the following code
const { exec } = require('child_process');
exec('my.bat', (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});
EDIT
You just create my.bat and add the following commands
cd "Your project path"
npm install
node server.js
If I try to run my sequelize migrations and then run my Node server in the same command, I run into the issue of my server never starting up. If the migrations have already been run before, the sequelize db:migrate command doesn't go past the "No migrations were executed, database schema was already up to date." message, and my second command is never able to run. If the migration has not run before, everything runs properly in sequence.
This is my npm start command: sequelize db:migrate && node index.js
I assume that internally sequelize db:migrate is not resolving anything in the case where this log message is shown, so is there a way I can "terminate" this command after some time and proceed to my node command?
For anyone else running into this issue, this is how I ended up solving it.
1) Create a new file that you will run in your npm script.
2) I ended up wrapping the process call in a child_process exec, and then terminated the process when I received the above console.log message since the library itself does not resolve anything at this point.
// myRuntimeFile.js --> Make sure this file is in the same directory where your .sequelizerc file lives
(async()=> {
const { exec } = require('child_process');
await new Promise((resolve, reject) => {
const migrate = exec(
'sequelize db:migrate',
{ env: process.env },
(err, stdout, stderr) => {
resolve();
}
);
// Listen for the console.log message and kill the process to proceed to the next step in the npm script
migrate.stdout.on('data', (data) => {
console.log(data);
if (data.indexOf('No migrations were executed, database schema was already up to date.') !== -1) {
migrate.kill();
}
});
});
})();
Obviously the above code is not ideal, but hopefully this is just temporary until the internals of this edge case are resolved properly in a promise.
3) Update your npm script with the following:
"start": "node myRuntimeFile.js && node index.js"
Or if you are running on a Windows machine and cannot use &&, you can use the npm-run-all library.
I am building a CLI tool with node, and want to use the fs.promise API. However, when the app is launched, there's always an ExperimentalWarning, which is super annoying and messes up with the interaction prompts. How can I disable this warning/all warnings?
I'm testing this with the latest node v10 lts release on Windows 10.
To use the CLI tool globally, I have added this to my package.json file:
{
//...
"preferGlobal": true,
"bin": { "myapp" : "./index.js" }
//...
}
And have run npm link to link the ./index.js script. Then I am able to run the app globally simply with myapp.
After some research I noticed that there are generally 2 ways to disable the warnings:
set environmental variable NODE_NO_WARNINGS=1
call the script with node --no-warnings ./index.js
Although I was able to disable the warnings with the 2 methods above, there seems to be no way to do that while directly running myapp command.
The shebang I placed in the entrance script ./index.js is:
#!/usr/bin/env node
// my code...
I have also read other discussions on modifying the shebang, but haven't found a universal/cross-platform way to do this - to either pass argument to node itself, or set the env variable.
If I publish this npm package, it would be great if there's a way to make sure the warnings of this single package are disabled in advance, instead of having each individual user tweak their environment themselves. Is there any hidden npm package.json configs that allow this?
Any help would be greatly appreciated!
I am now using a launcher script to spawn a child_process to work around this limitation. Ugly, but it works with npm link, global installs and whatnot.
#!/usr/bin/env node
const { spawnSync } = require("child_process");
const { resolve } = require("path");
// Say our original entrance script is `app.js`
const cmd = "node --no-warnings " + resolve(__dirname, "app.js");
spawnSync(cmd, { stdio: "inherit", shell: true });
As it's kind of like a hack, I won't be using this method next time, and will instead be wrapping the original APIs in a promise manually, sticking to util.promisify, or using the blocking/sync version of the APIs.
I configured my test script like this:
"scripts": {
"test": "tsc && cross-env NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest"
},
Notice the NODE_NO_WARNINGS=1 part. It disables the warnings I was getting from setting NODE_OPTIONS=--experimental-vm-modules
Here's what I'm using to run node with a command line flag:
#!/bin/sh
_=0// "exec" "/usr/bin/env" "node" "--experimental-repl-await" "$0" "$#"
// Your normal Javascript here
The first line tells the shell to use /bin/sh to run the script. The second line is a bit magical. To the shell it's a variable assignment _=0// followed by "exec" ....
Node sees it as a variable assignment followed by a comment - so it's almost a nop apart from the side effect of assigning 0 to _.
The result is that when the shell reaches line 2 it will exec node (via env) with any command line options you need.
New answer: You can also catch emitted warnings in your script and choose which ones to prevent from being logged
const originalEmit = process.emit;
process.emit = function (name, data, ...args) {
if (
name === `warning` &&
typeof data === `object` &&
data.name === `ExperimentalWarning`
//if you want to only stop certain messages, test for the message here:
//&& data.message.includes(`Fetch API`)
) {
return false;
}
return originalEmit.apply(process, arguments);
};
Inspired by this patch to yarn
I am creating a script in npm package.json.
The script will run yeoman to scaffold my template and then I want to run a gulp task to do some more stuff to a specific file (inject using gulp-inject)
The npm task looks like this:
"scaffolt": "scaffolt -g scaffolt/generators template && gulp inject"
Now, i need to be able to call the command from the command line giving a name to my template.
The command I need to run is the following:
npm run scaffolt {templateName}
but if I do this, then I try to run a gulp task called the same as the typed {templateName}.
A quick example: If I run npm run scaffolt myTemplate then the second part of this will try to run a task called gulp myTemplate, failing.
Is there any way to pass the {myTemplate} name as an argument to the second part of the script so that it can be used in the gulptask?
The gulp task currently only console.log the process.argv.
You can pass arguments to the npm run-script. Here is the documentation.
Make gulp tasks for these operations.
//gulpfile.js
const gulp = require('gulp');
const commandLineArgs = require('command-line-args');
const spawn = require('child_process').spawn;
gulp.task('inject', ['scaffolt'], () => {
console.log('scaffolt complete!');
});
gulp.task('scaffolt', (cb) => {
const options = commandLineArgs([{ name: 'templateName' }]);
//use scaffolt.cmd on Windows!
spawn('scaffolt', ['-g', 'scaffolt/generators', options.templateName])
.on('close', cb);
});
And in your package
//package.json
"scripts": {
"scaffolt": "gulp inject "
}
And to run it npm run scaffolt -- --templateName=something
Tip: npm run-script appends node_modules/.bin directory in the PATH so we can spawn executables just like they are on the same folder!
You can use magical $npm_config_<exampleVarName> in script definition and then pass the value of it either from env variable named match exampleVarName or pass it in command line you add --exampleVarName=ValueHere
in your case
//package.json
"scripts": {
"scaffolt": "scaffolt -g scaffolt/generators $npm_config_templateName && gulp inject"
}
then run it as
npm run scaffolt --templateName=whatever