Distribute command-line arguments using npm as a build tool - node.js

I have an npm package that manages my github repository and has scripts that build my publishable npm package. Due to the nature of the package, the published npm package (the distribution) cannot match my repository's package (the source). I am moving closer to test-driven development and continuous integration, but am learning it step-by-step. Here is the current flow and it works flawlessly, so far:
From the command line:
> npm run patch
runs npm version patch
This invokes source's preversion,
cleans the distro: npm run clean
runs the tests: npm test
This invokes pretest,
npm run build
Runs distro's tests
Failure: Errors and process ends
Success: Branch complete,
invokes the source's postversion:
git push all commits and tags
runs distro's npm version patch
invokes distro's postversion
npm publish
(Source) package.json
{
...,
"scripts": {
"patch": "npm version patch && cd dist && npm version patch",
"minor": "npm version minor && cd dist && npm version minor",
"major": "npm version major && cd dist && npm version major",
"preversion": "npm run clean && npm test",
"clean": /* clean commands */,
"pretest": "npm run build",
"test": "cd dist && npm test",
"postversion": "git push origin --all && git push origin --tags"
},
...
}
(Distro) package.json
{
...,
"scripts": {
"test": /* test commands */,
"postversion": "npm publish"
},
...
}
I would like to have a simpler interface. As you can see, I have to npm run <major|minor|patch>. I would instead like to npm run dist with a commandline arg passed to both npm versions.
Example:
> npm run dist patch
--------------------
<<< npm version patch
<<< cd dist && npm version patch
> npm run dist major
--------------------
<<< npm version major
<<< cd dist && npm version major
Is it possible to pass commandline args down the tree? Or, better yet, can I distribute a commandline arg across commands in a single scripts entry? I can easily add an entry to scripts that accepts a commandline argument, but cannot seem to figure out how to share that argument more than once with writing a separate .js script.

Related

sh: husky: command not found

I've setup a node project with husky but when my collegue tries to run npm install on his Mac he gets the following error :
noa-be#1.0.0 prepare
husky install
sh: husky: command not found
npm ERR! code 127
npm ERR! path /Users/X/Desktop/Workspace/project
npm ERR! command failed
npm ERR! command sh -c husky install
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/X/.npm/_logs/2021-04-12T13_07_25_842Z-debug.log
These are the relevant package.json parts:
{
"scripts": {
"prepare": "husky install"
},
"devDependencies": {
"husky": "^5.2.0",
}
}
I thought this would be enough for husky to be installed when running npm install, but it's not. What am I missing?
If you are using nvm, you might want to create a file called .huskyrc in your home directory and add the following lines of code to it:
~/.huskyrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
I was struggling with the same exact problem for hours. Finally, I could install dependencies and start working on my project by doing this:
Temporarily remove the "prepare": "husky install" script from the package.json file.
Run npm i (npm install). Dependencies installed successfuly.
Add again the "prepare" script that you removed in step 1.
Run again npm i to install the husky git hooks, so husky can do its job from now on.
This error is also thrown by npm ci if the NODE_ENV is set to "production" pre-install
I've been able to solve the problem by upgrading to latest Husky version (7.0.1, from 5.2.0).
Git was also helpful, and told me that the files weren't executables. (Git V 2.24.1)
So I give them executable rights :
chmod +x PATH_TO_HUSKY_FILE
You'll need to execute this command for every hooks
I believe it could be version specific issue. Install version 6, npm i husky#6.0.0 --save-dev, and it should work as the husky doc says.
Apparently, when I did npm i husky --save-dev, it was installing "husky": "^0.8.1" for me for some strange reason, giving me the exact same error: sh: husky: command not found.
Method 1:
Update manually, in your package.json:
{
"scripts": {
"prepare": "husky install",
"create-hook": "husky add .husky/pre-commit \"npm test\"",
}
}
Then, run npm run prepare && npm run create-hook.
It should create .husky directory with .pre-commit file in it.
Method 2:
npx husky install
npm set-script prepare "husky install"
npx husky add .husky/pre-commit "npm test"
It worked in my terminal but not in VSCode version control. So had to force quite the vscode app and restarting it worked.
Faced this issue in Github Desktop.
solved it by quit Github Desktop and re-open it.
I was able to fix this by providing an explicit location for husky
"scripts": {
"prepare": "node_modules/.bin/husky-run install"
},
Using Lerna
When I upgraded husky from version 4 to 8 there was information todo first pre commit manually. For this purpose pre-commit bash script was generated in .husky directory.
What I had todo was simply run the command included in this file:
lerna run precommit --concurrency 2 --stream

npm run build production does not distribute the production

I have a problem with my Angular project. Especially on the build of the project.
When I build my Angular poject with
ng build
it creates the dist-folder with the correct build. When I use the following command:
ng build --prod
it creates the production build (correct)
When I use NPM (used by build server) I use this:
run build
But I want the production build. Whatever I do, it doesn't work locally or on the buildserver. I used these:
npm run build --prod
npm run build --target=production
npm run build --environment=prod
npm run build --environment=production
npm run build --env=production
npm run build --env=prod
npm run build *projectname* --environment=production
npm run build *projectname* --env=production
npm run build *projectname* production
And probably a lot more. It just does not build the production!
I have a environment.prod.ts (production = true). It is set in the Angular.json. I have no clue what I am doing wrong.
You could also use -- to separate the params passed to npm command itself and params passed to your script.
So the correct syntax for your case would be:
npm run build -- --prod
npm run build should have the script in the package.json
have a look there and maybe add the line in the scripts
{
...
scripts: {
"build": "ng build --prod"
},
...
}
this should do the trick
What you can do is update the build script in the package.json as
scripts:{
"build": "npm run ng build --",
"ng": "ng"
}
-- allows you to pass arguments to a script.
Then you can pass the arguments to ng build like ng build --prod
Try this if your environment is production:
npm run build -- --configuration=production
or this if it's prod:
npm run build -- --configuration=prod
If you don't specify the "configuration" parameter name you may see this error:
npm run build -- --prod
Error: Unknown argument: prod
npm run build -- --production
Error: Unknown argument: production

package.json scripts that work with npm and yarn?

I am using npm as a build tool and so in my package.json, and some of my scripts depend on other scripts:
{
"test": "npm run lint && mocha"
}
This hardcodes the npm package manager into package.json. How can make this approach to expressing dependencies work with both npm and yarn?
The $npm_execpath environment variable refers to the build tool, so just replace npm with the $npm_execpath:
{
"test": "$npm_execpath run lint && mocha"
}
Both npm test and yarn test will work, and will use the appropriate build tool.
While mjs' answer is great, there's also a small package that is purported to work on all environments including Windows: https://www.npmjs.com/package/yarpm
To use in a project, run yarn add yarpm --dev / npm i -D yarpm and then just use yarpm in your scripts like this:
{
"test": "yarpm run lint && mocha"
}
As the package README notes, you just need to make sure your commands would be suitable for passing through to either yarn or npm: you cannot use arguments/flags that only work on one package manager.

gcloud deploy fails nodejs

I'm trying to deploy to google app engine. When I do so, the initial information all seems correct, the docker build is successful, but after docker it tries the following and fails:
Beginning teardown of remote build environment (this may take a few seconds).
Updating module [default].../Deleted [https://www.googleapis.com/compute/v1/projects/jamsesh-1219/zones/us-central1-f/instances/gae-builder-vm-20160213t114355].
Updating module [default]...failed.
ERROR: (gcloud.preview.app.deploy) Error Response: [13] Timed out when starting VMs. It's possible that the application code is unhealthy. (0/2 ready, 2 still deploying).
I know that I'm running es6 code transpiled to run on node 4.1.2 which is the version I'm told I can use here - I just have to run nvm install v4.1.2 which will switch me over, so I include that in my scripts. Here are my scripts in package.json:
"scripts": {
"test": "test",
"clean": "rm -rf lib",
"watch-js": "./node_modules/.bin/babel --plugins transform-es2015-classes src --presets react -d lib",
"dev-server": "./node_modules/.bin/webpack lib/client/entry.js",
"lint": "./node_modules/.bin/eslint ./src",
"server": "node lib/server/server",
"start-dev": "npm run lint && npm run build && npm run dev-server && npm run server",
"start": "nvm install v4.1.2 && node lib/server/server",
"styles": "./node_modules/.bin/lessc ./public/less/bundle.less ./public/css/bundle.css",
"build": "npm run clean && ./node_modules/.bin/babel --plugins transform-es2015-classes src --presets react -d lib && npm run styles"
},
and my docker file:
# Dockerfile extending the generic Node image with application files for a
# single application.
FROM gcr.io/google_appengine/nodejs
COPY . /app/
# You have to specify "--unsafe-perm" with npm install
# when running as root. Failing to do this can cause
# install to appear to succeed even if a preinstall
# script fails, and may have other adverse consequences
# as well.
# This command will also cat the npm-debug.log file after the
# build, if it exists.
RUN npm install --unsafe-perm || \
((if [ -f npm-debug.log ]; then \
cat npm-debug.log; \
fi) && false)
CMD npm start
So yeah, I've got no clue why the deployment failing. I could definitely benefit from some more thorough documentation on deploying node on GAE. It works on a test repo. Is there something else I need to be doing to run node on GAE with my babel6 transpiled code? Or should something be different in my scripts? In the Google Shell I can run locally fine once I switch to node v4.1.2

How to detect when `prepublish` script is executed as a result of running `npm install`

https://docs.npmjs.com/misc/scripts
prepublish: Run BEFORE the package is published. (Also run on local npm install without any arguments.)
I want my script to execute only in case of user executing npm publish. However, NPM will execute "prepublish" script if user runs "npm install".
The only way I have figured out is using NPM internal ENV variables:
// NPM will run prepublish script after `npm install` (https://docs.npmjs.com/misc/scripts)
// This ensures that when script is executed using `npm *` it is run only when the command is `npm publish`.
if (process.env.npm_config_argv) {
let npmConfigArgv;
npmConfigArgv = JSON.parse(process.env.npm_config_argv);
if (npmConfigArgv.original[0] !== 'publish') {
console.log('`bundle-dependencies prepublish` will not execute. It appears that `prepublish` script has been run by `npm install`.');
return;
}
}
It appears that NPM stores the original command in process.env.npm_config_argv variable.
In case you are wondering, each NPM script is being run in different process. Therefore, something like setting a custom ENV variable in preinstall script does not work.
Another solution that's also worked for me (again from this thread) is using a prepublish.sh script like the following:
get_json_val() {
python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}
get_npm_command() {
local temp=$(echo $npm_config_argv | get_json_val "['original'][0]")
echo "$temp" | tr -dc "[:alnum:]"
}
if [ $(get_npm_command) != "publish" ]; then
echo "Skipping prepublish script"
exit 0
fi
# else
echo "prepublish called"
# prepublish logic follows:
# ...
So if your package.json file is:
{
"name": "foo",
"version": "0.0.1",
"description": "",
"main": "lib/foo.js",
"scripts": {
"prepublish": "./prepublish.sh"
},
"dependencies": {
"lodash": "^4.10.0"
}
}
… then running npm install will only install the dependencies and the prepublish target will only be called when user types npm run publish.
Yet another way is to use the in-publish package (again mentioned in this thread). Place it in your development dependencies and then in your package.json have something like:
"prepublish": "(in-publish && npm run clean && flow check && npm run test && npm run build) || not-in-publish"
As of npm#4.0.0, the prepublish script is now deprecated. To run a script on both npm publish, and npm install without arguments (the bahaviour of prepublish), you should use prepare instead.
To run a script only on npm publish, you should use prepublishOnly.

Resources