Is it possible to call out to retrieve a key from yargs when using as a npm script argument?
User types in the OSX terminal:
npm run scaffold --name=blah
which executes in package.json:
"scaffold" : "node ./scaffold/index.js -- "
This results in
const yargs = require('yargs').argv
if (yargs) {
console.log(yargs);
console.log(yargs.name);
process.exit(1)
}
...
result:
{ _: [], '$0': 'scaffold/index.js' }
undefined
This only works if I hard code in package.json "scaffold" : "node scaffold/index.js --name=blah", but I need this to be configurable.
As I stated I am using args, as it appears to make it easy to retrieve keys by name ( as opposed to an array ). Open to suggestions.
What am I missing?
update 11-07-2017
Related: Sending command line arguments to npm script
However, passing in the commandline 1: npm run scaffold name=hello
OR 2: npm run scaffold --name=hello yields:
1: { _: [], '$0': 'scaffold/index.js' }
2: { _: [ 'name=hello' ], '$0': 'scaffold/index.js' }
Still can't see a way to retrieve the yargs.name property. Still undefined.
Update 13-07-2017
For the time being, I have given up. It just seem impossible. I run the script manually in the terminal.
E.g.
node ./scaffold/index.js --name=blah
Image below shows executing of a node script directly as opposed to running through npm scripts. I have added https://www.npmjs.com/package/nopt node module to see if it helps ( it doesn't ). process.argv.name is still undefined when running through npm scripts.
Update 18-07-2017
Added github example: https://github.com/sidouglas/stackoverflow-node-arguments
Update 24-07-2017
Adding the variables before the start of the command works
myvar="hello npm run scaffold as opposed to npm run scaffold myvar="hello world"
As of npm#2.0.0, you can use custom arguments when executing scripts. The special option -- is used by getopt to delimit the end of the options. npm will pass all the arguments after the -- directly to your script:
npm run test -- --grep="pattern"
https://docs.npmjs.com/cli/run-script
I'm not sure that it matters where the variables are added on the command line, and if this is of no concern to you, then this works:
//package.json
{
"name": "npm-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {},
"devDependencies": {},
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "ISC"
}
Your JS file:
//index.js
console.log('myvar', process.env.myvar);
And your command line command:
myvar="hello world" npm run start
So in the end, just prefix your npm script command with your argument list.
For me the following works on Node 10, 12, 14
npm run yourscript -- -- --name=bla
I do need to use -- --
and
"yourscript": "node bla.js"
Related
I want to reference my package version in a npm script so I can show current version in the app.
Something like
{
"name": "bla",
"version": "1.0.0",
"author": "bla bla",
"scripts": {
"build": "node VERSION=<<package.version>> build/build.js"
}
}
Is there a way to do this?
1) Referencing package version in npm-scripts.
In npm-script's you can reference the version using the variable npm_package_version. For example:
Using a bash shell (E.g. Linux, macOS):
{
...
"version": "1.0.0",
"scripts": {
"build": "echo $npm_package_version"
}
}
Note the $ prefix
Using Windows (E.g. cmd.exe, Powershell):
{
...
"version": "1.0.0",
"scripts": {
"build": "echo %npm_package_version%"
}
}
Note the % prefix and suffix
Cross platform
To utilize one syntax cross-platform check out the package cross-var
2) Referencing package version in node script.
The package version can also be referenced in your a app/node script (i.e. build.js) as follows:
const VERSION = process.env.npm_package_version;
console.log(VERSION); // --> 1.0.0
3) Replacing a placeholder string in a .js file with package version.
Another way to achieve this is to specify a placeholder text string within your JavaScript file. Lets say we have a file named build.js and within that file we have a variable named VERSION declared as follows:
// build.js
const VERSION = '#VERSION#'
As you can see, the placeholder text string is #VERSION#.
You can then install and utilize the package called replace in an npm-script as follows:
{
...
"version": "1.0.0",
"scripts": {
"add-version": "replace -s \"#VERSION#\" $npm_package_version build/build.js"
}
}
Running npm run add-version will replace the instance of #VERSION# with the package version (i.e. 1.0.0), in the file named build.js. This solution will hard-code the npm package version into the resultant file.
Note: The to string in the add-version script (above) currently uses the $ prefix (i.e. $npm_package_version) to access the variable, so this will only run successfully on a bash shell. However, for cross-platform usage you'll need to use cross-var as explained in section one (above). In which case the add-version script can be defined as follows:
{
...
"version": "1.0.0",
"scripts": {
"add-version": "cross-var replace -s \"#VERSION#\" $npm_package_version build/build.js"
}
}
I have experimented with adding environment variables to my Gatsby project using .env.development and .env.production files and it's working great.
I would like to have my builds fail if one of the environment variables is missing, however I can't seem to see how to enable this functionality.
I have read through the Gatsby environment variables documentation, but can't seem to see how this would work? is this possible?
I believe it uses dotenv/webpack define plugin under the hood.
I’m sure there are other ways to do this, but with some quick tests, this approach seems to be working well for me.
In your gatsby-config.js file, you can choose to explicitly require the dotenv, so you can use those environment variables in your config.
I added the following, and now the Gatsby build will fail unless the specified environment variables are present.
// Load the environment variables, per
// https://www.gatsbyjs.org/docs/environment-variables/#server-side-nodejs
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
})
function checkEnv(envName) {
if (typeof process.env[envName] === 'undefined' || process.env[envName] === '') {
throw `Missing required environment variables: ${envName}`
}
}
try {
checkEnv('NODE_ENV')
checkEnv('EXAMPLE_MISSING_ENV')
checkEnv('EXAMPLE_API_KEY')
} catch (e) {
throw new Error(e)
}
// The rest of the config file
I could imagine customizing this further, ex. logging a warning for a variable with a fallback versus throwing an error for one that is required by your content sourcing plugin or theme. Hope this is helpful as a starting point!
I couldn't find built-in solution for this on Gatsby neither. You may do it manually, but still not too easy.
First problem: If you wanna load your environment from file while running npm script; it can not be loaded right away. But you may trigger a script file, and it can load this environment variables before your check.
lets say build.sh on root directory of project :
source ./.env.development # this line will set env variables
if [ "$API_KEY" = 927349872349798 ] ; then
npm run build
fi
Another problem rises; some developers might want to run it on windows maybe. So better use famous cross-env package.
npm i cross-env
Then everything is ready, add your secure-build :
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1",
"secure-build": "cross-env-shell \"./build.sh\""
},
And run it :
npm run secure-build
This solution looks too much for me as we created a build.sh and install a new package. Maybe there is cleaner solution. I am not Gatsby Guru after all.
I added env checking to the onPreInit life cycle hook in gatsby-node.ts:
const envVariablesList = [
"ENV1",
"ENV2",
"ENV3",
];
function envVarChecker(vars: string[]): string | undefined {
return vars.find(
(item) => process.env[item] === undefined || process.env[item] === ""
);
}
export const onPreInit: GatsbyNode["onPreInit"] = ({ actions }) => {
const emptyEnv = envVarChecker(envVariablesList);
if (emptyEnv !== undefined) {
throw new Error(`Env variable: ${emptyEnv} is empty!`);
}
};
It fails build almost at the very beginning (during pre-bootstrap phase) if any of the declared variables is missing
How do i use the nodejs_binary rule to do a standard npm run start. I am able to run a typical node project using this rule. However i want to run a the start script in package.json. So far i have the following below in my build file
load("#build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
nodejs_binary(
name = "app",
data = [":app_files"],
node="#nodejs//:bin/npm",
entry_point = "workspace_name/src/server.js",
node_modules = "#npm_deps//:node_modules",
args=["start"]
)
This does not start the server..somehow npm command is not running properly. it indicates usage of the command in incomplete.
I am currently able to do this within the WORKSPACE
bazel run #nodejs//:bin/yarn (runs yarn install and installs all node-modulse)
bazel run #nodejs//:bin/npm start (this starts the server)
In my package.json i have
{
"scripts": {
"start": "babel-node src/server.js",
...
}
...
}
I do i get this to work with nodejs_binary rule and subsequently node_image
I changed from using npm to using yarn..workspace_name/src/server.js.. is called now but Then i had different set of problems, babel-node was not found.
I modified the rule a bit. After careful study...I realise that there is a dependency on babel-node that is not satisfied at the time yarn run start is called. The following worked after i had run bazel run #nodejs//:bin/yarn before running the rule.
nodejs_binary(
name = "app",
args = ["start"],
data = [
":app_files",
"#//:node_modules",
],
entry_point = "workspace_name/src/server.js",
node = "#nodejs//:bin/yarn",
node_modules = "#npm_deps//:node_modules",
)
It appears that "#//:node_modules" solves the babel-node dependency issue. So the rule above does not work on its own...it needs me to do bazel run #nodejs//:bin/yarn (more like npm/yarn install to make the node_modules, which contain babel-node dependecy available when npm/yarn start is run)
So my problem is that I do not want to have to manually run bazel run #nodejs//:bin/yarn before executing my rule. how do i do this.
I suppose it would work if i stopped depending on babel-node...but then i would have to change my code to not use es6 syntax (that is a hustle). Is there a way i can do this with a genrule? or something...
What I ended up doing was that i made a babel nodejs_binary rule. Then used that to compile my source files in a gen rule
# Make babel binary
nodejs_binary(
name = "babel",
entry_point = "npm_deps/node_modules/babel-cli/bin/babel",
install_source_map_support = False,
node_modules = "#npm_deps//:node_modules",
)
# Compile source files with babel
genrule(
name = "compiled_src",
srcs = [
":src_files",
],
outs = ["src"],
cmd = "$(location babel) src --out-dir $#",
tools = [":babel"],
)
Note that in this case src in cmd = "$(location babel) src --out-dir $#" is a folder in the :src_files filegroup.
filegroup(
name = "src_files",
srcs = glob([
"src/**/*",
...
]),
)
After this it was unnecessary to use npm start, just used default node. I could just do
nodejs_binary(
name = "app",
data = [":compiled_src"],
entry_point = "workspace_name/src/server.js",
node_modules = "#npm_deps//:node_modules",
)
I have many js scripts in one folder (scripts/*.js).
How to execute them all from the gulp task (instead of using 'node script.js' many times)?
something like
gulp.task('exec_all_scripts', function () {
gulp.src(path.join(__dirname, './scripts/*.js'))
})
Gulp is a task runner, meaning it's meant to automate sequences of commands; not run entire scripts. Instead, you can use NPM for that. I don't think there's a way to glob scripts and run them all at once, but you can set each file as its own npm script and use npm-run-all to run them:
{
"name": "sample",
"version": "0.0.1",
"scripts": {
"script:foo": "node foo.js",
"script:bar": "node bar.js",
"script:baz": "node baz.js",
"start": "npm-run-all --parallel script:*",
},
"dependencies": {
"npm-run-all": "^4.0.2"
}
}
Then you can use npm start to run all your scripts at once.
If you really need to use gulp to run the scripts, you can use the same strategy, and then use gulp-run to run the npm script with gulp.
var run = require('gulp-run');
// use gulp-run to start a pipeline
gulp.task('exec_all_scripts', function() {
return run('npm start').exec() // run "npm start".
.pipe(gulp.dest('output')); // writes results to output/echo.
})
you can export functions in your scripts/*.js and import them in gulpfile.js and call the functions in 'exec_all_scripts' task, it's easy
You could concatinate all of the scripts into a single script and then execute it from the same task, a different task, or using a different process. See the following NPM package: https://www.npmjs.com/package/gulp-concat
Here is an example:
var concat = require('gulp-concat'); // include package
gulp.task('exec_all_scripts', function() {
return gulp.src(path.join(__dirname, './scripts/*.js')
.pipe(concat('all_scripts.js'))
.pipe(gulp.dest('./dist/')); // assuming you had a dist folder but this could be anything
});
I am working with commander.js for my project and I am facing a weird issue when giving an alias for a command. I referred to examples mentioned here: Commander.JS Example
I am looking for creating a git like command so I started with the .command() method. When I clone the above repo and run it locally for the given example of pm, the help option works as expected. Note that in usage section there is only 'pm' and the command 'install' has alias 'i' separated by '|' symbol
Usage: pm [options] [command]
Commands:
install|i [name] install one or more packages
other options ...
But when I run my own test application, my alias of command gets appended with the test application name itself and I get an output like this:
Usage: index|r [options] [command]
Commands:
random random command
Please notice that the alias 'r' is showing with index command instead of 'random' command. If I add more commands to my index.js file, the last alias gets appended to Usage: index|<new alias> instead of actually getting appended with the right command.
I am not able to understand what am I doing wrong. Can somebody please help here? How can I get the correct output when using the -h or --help option ?
index.js
#!/usr/bin/env node
'use strict';
var program = require('commander');
program
.version('1.0.0')
.command('random', 'random command')
.alias('r')
.parse(process.argv);
index-random.js
#!/usr/bin/env node
'use strict';
var program = require('commander');
program
.option('-r, --random <random>', 'Random command option')
.parse(process.argv);
Package.json
{
"name": "commander-test",
"version": "1.0.0",
"description": "Testing commander",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Raghuveer",
"license": "UNLICENSED",
"dependencies": {
"commander": "^2.9.0",
"graceful-readlink": "1.0.0"
}
}
Steps to reproduce:
node index -h
Please let me know if you need more information.
Add alias of the sub command to the corresponding sub command file. In your case you have to add it to index-random.js file like this.
#!/usr/bin/env node
'use strict';
var program = require('commander');
program
.option('-r, --random <random>', 'Random command option')
.alias('r')
.parse(process.argv);
Then when you invoke; node index.js help random
the help will show Usage: index-random|r
However, the issue I am also facing is that if I call the index command only with alias, nothing will happen. (for ex: if I call node index r no output will return).
Let me know if you are successful in calling aliases instead of full command.
Updated: Below are the outputs of two commands.
>node index.js help
Usage: index [options] [command]
Commands:
random random command
help [cmd] display help for [cmd]
Options:
-h, --help output usage information
-V, --version output the version number
>node index.js help random
Usage: index-random|r [options]
Options:
-h, --help output usage information
-r, --random <random> Random command option