husky / lint-staged not running custom command or printing errors - npm

I am trying to upgrade from husky#4.8 and lint-staged#11.2 to husky#8.0 and lint-staged##13.1 for my Nx repo. It seems that the only configuration I used to need was the following in package.json:
"scripts: {
"lint:fix": "ng lint -- --fix && npm run prettier:fix",
}
"husky": {
"hooks": {
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.{ts,js,css,md,html}": "npm run lint:fix",
"relative": true
}
This no longer works with the new husky and lint-staged. I followed this tutorial and installed husky: npx husky-init && npm install, installed lint-staged: npm install --save-dev lint-staged, modified the .husky/pre-commit file:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
and added the .lintstagedrc.json file:
{
"*.ts": [
"prettier --write",
"eslint"
],
"*.html": [
"eslint",
"prettier --write"
],
"*.scss": "prettier --write"
}
When I make a new commit it seems to run. However it looks like this command either runs on every library or every staged file (I have a lot of libraries). When I change the file contents to:
{
"*.{js,ts,json,scss,md}": ["npm run lint:fix"]
}
it takes a while to run (though it seems to run and fix the linting) AND I don't get the output of my ng lint -- --fix command. If I go into the .husky/pre-commit file and change npx lint-staged to npm run lint:fix, it runs the ng lint -- --fix command, fixes what it can and prints out linting errors. However, the error doesn't prevent the commit and I have to commit any new changes that the linter fixed. With the old versions I didn't need to do this. Also I didn't need to commit a .husky/pre-commit file into my repo. (I see some workarounds that have a postinstall script that generates this file for the user).
How can I utilize lint-stage and husky newest versions to run my custom npm command so I can call ng lint like in the older versions and block commits on errors? Should I just use the older versions? Also what benefit do the newer versions provide?

Related

Lint-staged aborts check with the first failing file; "Error: Unknown argument"

With "lint-staged": "^13.0.3" and the following .lintstagedrc config:
{
"src/**/*.{ts,html}": [
"ng lint"
],
"src/**/*.scss": [
"npx stylelint **/*.scss"
]
}
I'm trying to run npx lint-staged -q on the following files (all of them have lint problems that would come up with the individual lint command):
Running ng lint and npx stylelint **/*.scss directly will bring up the problems (detailed) and would not fail on the first file:
ng lint
npx stylelint **/*.scss
I'd like lint-staged's output to show all of the problems from the individual lint commands. What's wrong here?
Thanks
Ok, after further investigation;
The partial output problems seem to be introduced to lint-staged on versions >= 12.2.0, see on github. I've downgraded to "lint-staged": "12.1.7" and the problem seems to be gone.
Regarding the Unknown argument thing, it resolves by calling eslint instead of ng lint on the configuration file.

Yarn script fails when invoking other Yarn-scripts

I've got an issue when invoking other Yarn scripts from a Yarn-script. What I want to achieve is having one yarn develop task that first invokes TypeScript and some other preprocessors before starting a couple of watchers and running my application. I'd like to use npm-run-all (or something similar) to invoke multiple targets as that would allow me to define separate targets that I can manually run as well without having duplicate script-entries in my package.json.
I've made a minimal reproduction case which has the following package.json:
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"task:one": "echo one",
"task:two": "echo two",
"run-all": "npm-run-all task:one task:two",
"run-all-yarn": "yarn task:one && yarn task:two"
},
"devDependencies": {
"npm-run-all": "^4.1.5"
}
}
Invoking yarn task:one results in an echo one as expected, as does yarn task:two. If I invoke yarn run-all though, I get an error:
$-> yarn run-all
yarn run v1.22.10
$ npm-run-all task:one task:two
$ echo one
error Couldn't find the binary echo one
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
ERROR: "task:one" exited with 1.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
yarn run-all-yarn fails with (almost exactly, sans the command being executed on the second line) the same error.
If instead of Yarn I use NPM (npm run run-all) it all works as expected:
$-> npm run run-all
> test#1.0.0 run-all /Users/basdalenoord/Projects/52DN/psyflix/test
> npm-run-all task:one task:two
> test#1.0.0 task:one /Users/basdalenoord/Projects/52DN/psyflix/test
> echo one
one
> test#1.0.0 task:two /Users/basdalenoord/Projects/52DN/psyflix/test
> echo two
two
I'm using Yarn version 1.22.17 provided by my node-version from nvm: ~/.nvm/versions/node/v14.18.1/bin/yarn
I'm a bit lost as to why running individual targets would be fine but combining them fails for yarn, whereas the same script works for npm.

trouble with npm preinstall script

I'm trying to make the jump to pnpm from npm. I found a helpful hint to keep from running "npm install" after I make the change as described here: https://pnpm.js.org/en/only-allow-pnpm
Unfortunately my preinstall lifecycle override doesn't get executed. Seems to simple enough but npm install still works when I run something like "npm install #types/jest"
package.json:
{
"name": "react-sandbox",
"version": "0.1.0",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}
npm version 6.14.2.
Any ideas?
Unfortunately, the preinstall script is executed only during argumentless installation. So when you run npm add #types/jest, that script will not be executed, thus npm won't be prevented from running.
But it will fail when running npm install.
As of now, there is no other way to prevent npm from execution.

Npm: Run postinstall script only when installed as dependency

I developed a npm package ("node_commons") which is included in my other project like this:
package.json (other project)
"node-commons": "git+ssh://git#stash.custom.domain.net:7999/npm/libs/node_commons.git"
The node_commons package is written in ES6 but this version is not supported later, therefore I use a postinstall script to transpile it with babel.
package.json (node_commons)
"postinstall": "babel src -d src"
This works fine. When the package is included as dependency in my project, the files are transpiled.
My problem: When I develop the node_commons package I use npm install to install the internal dependencies. But then I do not want to transpile it. I only want to transpile, when the package is installed as dependency (e.g. in my other project). Is there a way to do this?
Something like this:
package.json (node_commons)
"postinstall-as-dependency": "babel src -d src"
Create .no-postinstall file in module root.
Mac & Linux: Add following to package.json: "postinstall": "if [ ! -e .no-postinstall ]; then babel src -d src; fi"
Windows: Add following to package.json: "postinstall": if exist .no-postinstall () else (babel src -d src)"
Cross Platform (more work):
You can create a node script (i.e. ./my-script.js) and using fs module, check existence of .no-postinstall and execute babel src -d src using child_process.exec() as described in official doc here. Add your script to package.json: "postinstall": node my-script.js
Please note that I use Mac, so I can't verify Windows version.
Explanation
if [ ! -e .no-postinstall ] checks non-existence (with negation operator !) of given file. If file does not exist, it executes your script. Since you add .no-postinstall file to your module root, script does not get executed when you install your internal modules. On the other hand, modules installing your module as a dependency do not have .no-postinstall file in their root and your script get executed.
.no-postinstall is not a special name, you can use whatever name you choose.
In my case, I had a postinstall script that I only wanted to run when the package was NOT installed as a dependency.
Here is the package.json script I used:
{
[...]
"scripts": {
"#comment_postinstall": "Behavior of the node-js subscript below: if '.git' doesn't exist under my-lib, it's installed as a dep, so do nothing -- else, return error-code 1, causing patch-package to run.",
"postinstall": "node -e \"let myLibAsDep = !require('fs').existsSync('.git'); if (!myLibAsDep) process.exit(1);\" || patch-package"
},
[...]
}
You can of course just reverse the if (!myLibAsDep) if you want your script to run only when installed as a dependency.
If I understand correctly, you want your package to run a postinstall script only if user install it as a dependency (npm install node-common)?
When your postinstall script runs, it has the npm_config_save_dev available to it, which is 'true' when users install the package with the --save-dev flag:
"postinstall": "! [ $npm_config_save_dev ] && echo \"Installed as a dependency\" || \"Installed as a dev dependency\""
I had the same issue, I had a postinstall script which I wanted to run only when the package is installed as a dependency.
At the top of my postinstall script I added:
if (!process.cwd().includes('node_modules')) {
return;
}
and then it only ran when the module existed under a node_modules dir.
This should do the trick:
if (process.env.INIT_CWD === process.cwd())
process.exit()
Works with npm and pnpm. Don't know about yarn
https://docs.npmjs.com/cli/v8/using-npm/scripts#best-practices
I created a package to solve this problem, inspired by the answer from #venryx.
https://github.com/douglasjunior/ignore-dependency-scripts
Usage
Replace this:
// package.json
"name": "my-library",
"scripts:" {
// "start", "test", "build", etc
"postinstall/preinstall/prepare/etc": "your && scripts && here"
},
With this:
// package.json
"name": "my-library",
"scripts:" {
// "start", "test", "build", etc
"postinstall/preinstall/prepare/etc": "npx --yes ignore-dependency-scripts \"your && scripts && here\""
},
Replace your && scripts && here by any post/pre install script that you want, like husky install, npx pod-install or both.
Now, when you run yarn install or npm install in ./my-library the your && scripts && here will run normally.
But, when you install my-library as a dependency (aka yarn add url/to/my-library.git) in another repository, the your && scripts && here will be ignored.

npm install dependencies of local modules

I'm having trouble using npm with a local module. My project's structure looks like:
package.json
local_module/
- package.json
- gulpfile.json
gulpfile.js
The main project's package.json is essentially:
{
"dependencies": {
"local_module": "file:local_module"
},
"devDependencies": {
"gulp": "..."
}
}
The local module's package.json is essentially:
{
"scripts": {
"prepublish": "gulp release"
},
"devDependencies": {
"gulp": "..."
}
}
My intention is keep my project modular by keeping local_module as its own package that is used as a dependency for the main project. I want to run npm install in the main project and use local_module from node_modules. However, local_module needs gulp installed to run the prepublish step, and when running npm install from the main project, it does not install the dependencies for local_module, and so gulp isn't installed, so it can't do the prepublish step.
Several questions like this have been asked, like NPM doesn't install module dependencies, but many are old and there are so many versions of npm that I can't get a clear solution.
How can I get npm to install local_module's dependencies before the prepublish step? I tried adding a preinstall step for the main project, e.g.
"preinstall": "cd local_module && npm install"
But it seems npm tries to run the prepublish step of local_module before running the preinstall for the main project. I want a solution that will do this in one npm install step rather than having a separate step before this to do npm install in the local module.
I have found a solution that will work for me in the immediate future. I changed local_module's package.json to:
{
"scripts": {
"prepublish": "npm install --ignore-scripts && gulp release"
},
"devDependencies": {
"gulp": "..."
}
}
When npm install is run from the main project, the prepublish step is run first in local_module, so I force prepublish to also do an install so that gulp is available to do the actual prepublish step. This is hardly ideal however.