Closed ext closed 2 years ago
adding --ignore-scripts worked for me
RUN npm ci --only=production --ignore-scripts
Thank you for the tips, maybe it could be added to the docs in case others face the same issue?
Yes, good suggestion. PR welcome.
I had a similar issue and the problem with using a blanket --ignore-scripts
is it affects all packages being installed. So for example, I had a project that needed scripts to run for installing a binary (like imagemin-jpegtran) because a package using it appeared in dependencies
.
I don't know what the solution is, but it'll be difficult to consider husky
as an option if using --production
will only work if no other dependencies do need scripts to run on install, which is often out of my hands.
I just hit this problem found this issue, and discovered that there is an official recommended approach, using the is-ci
module: https://typicode.github.io/husky/#/?id=disable-husky-in-cidocker
I just hit this problem found this issue, and discovered that there is an official recommended approach, using the
is-ci
module: https://typicode.github.io/husky/#/?id=disable-husky-in-cidocker
Most of the linked approaches wont help, --ignore-scripts
is the best (only?) option so far.
HUSKY=0
wont help as prepare
/postinstall
will still try to execute husky install
(causing command not found).[ -n "$CI" ]
(or similar) in the scripts assume husky
is a production dependency, if it is a devDependency it still causes command isn't found.is-ci
would only work if is-ci
is a production dependency or it will also fail because is-ci
isn't found instead.Additionally building docker images locally will not trigger CI
or is-ci
as it is not running in a CI environment.
I guess another hack that might work would be:
# install all dependencies, get past prepare/postinstall
npm install --production=false
# remove all non-production dependencies
npm prune --production
But that would be really wasteful and inefficient.
For now i am using this solution RUN npm set-script prepare "" && npm ci --only=production
in my Docker file
- Using
is-ci
would only work ifis-ci
is a production dependency or it will also fail becauseis-ci
isn't found instead.
is-ci
contributes 84 KiB to node_modules
, so this is not too bad.
"scripts": {
"prepare": "is-ci || husky install"
}
works for me with one caveat: is-ci
doesn't seem to detect npm ci --production
as being "CI"...
At least CI=1 npm ci --production
can complete successfully now.
[..] so this is not too bad
I have to disagree with you there.
ci-info
being pulled as well.I still value your suggestion thought. Maybe it will help someone else?
I think this is related: https://github.com/typicode/husky/issues/981. Core topic seems that the lifecycle hooks are sometimes triggering in circumstances where we don't want them to run (ci, installation as a dependency (production install)). I can see the appeal of having husky be agnostic to what enviroment it's being installed in, but the recommendations currently in the docs don't seem to cover all potential scenarios.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Valid issue IMO and the workarounds above are just workarounds.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I still consider this to be an issue.
The way the package works after v4 is problematic as evident by this and other related issues reported in this repo. I wonder why author doesn't want to acknowledge that the new way of handling hooks is just too problematic (even if intentions were good) and probably should be reverted.
I'm running into this out of the blue on one two of my apps w/ husky 7.0.4.
I've deleted node_modules
, package-lock.json
and ran npm install
to rebuild them w/ no success.
I've edited my deploy job to npm ci --only=production --ignore-scripts
w/ no success.
Big sad.
I solved my occurance of this with @pinalbhatt 's suggestion of npm set-script prepare "" && npm ci --only=production
.
The "custom script" option listed in the husky docs worked best for me while deploying a small hobby project to Heroku, which is not supported by the is-ci
tool. The fact that it's a node script adds the flexibility to check for production environment:
// prepare.js
const isProduction = process.env.NODE_ENV === 'production';
const isCi = process.env.CI !== undefined;
if (!isCi && !isProduction) {
require('husky').install();
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Not stale. I suggest we increase the grace period so avoid spamming everyone in issues like this one.
Hey,
I don't think there's a one-size-fits-all solution to this problem. It's a chicken/egg issue.
Ideally, if there was a devPostInstall
hook supported by package managers that would solve the issue completely. Since that's not case, we can only come up with solutions that aren't perfect.
Also reverting to husky 4 way of doing would bring back another array of issues. Package managers don't treat postinstall
hook the same way as before.
Accounting for every cases, environments, type of deployment isn't possible, instead the recommended way is to pick the approach that works best for the particular use case. That could be npm set-script prepare
, node prepare.js
, some env variable checking, etc... it depends on the user and which options are available to them.
I'll add the following also to the list of possible solutions:
// package.json
{
"scripts": {
"prepare": "node -e \"try { require('husky').install() } catch (e) {if (e.code !== 'MODULE_NOT_FOUND') throw e}\""
}
}
If husky is not found/installed, which is the case with --prod
, prepare
script will fail silently.
Sorry to not be able to come with a definitive answer.
We're seeing this with Google App Engine (node flex environment), where it's Google doing the npm install
that's somehow kicking this off. Can't reproduce it locally :shrug:
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
My 2 cents to this issue that make our CI pipelines fail too. Using the prepare npm script is IMHO not a good idea at all. the prepare script is called not only on install but also on publish and perhaps i'm missing something but I don't want it to be executed on publish at all. Also it will make stuffs more complicated if you intend to use that prepare script for yourself as you will have to deal with including "husky install" somewhere in your prepare script.
Finally I think best options so far are:
npm set-script prepare ""
before running install or publish during you CI jobs."prepare": "if [[ -x \"$(command -v husky)\" ]]; then husky install; fi"
I can't recommend the --ignore-scripts as it will avoid all other legitimate script to be run, it can't be a good solution.
My 2 cents to this issue that make our CI pipelines fail too. Using the prepare npm script is IMHO not a good idea at all. the prepare script is called not only on install but also on publish and perhaps i'm missing something but I don't want it to be executed on publish at all. Also it will make stuffs more complicated if you intend to use that prepare script for yourself as you will have to deal with including "husky install" somewhere in your prepare script.
Finally I think best options so far are:
npm set-scripts prepare ""
before running install or publish during you CI jobs.- replace your prepare script with:
"prepare": "if [[ -x \"$(command -v husky)\" ]]; then husky install; fi"
I can't recommend the --ignore-scripts as it will avoid all other legitimate script to be run, it can't be a good solution.
Just a nit pick, the npm command actually is set-script
in singular.
I have solved the same problem by usage of an own tiny CLI:
"prepare": "check NODE_ENV=production || husky install"
where check is installed by:
npm install check-env-cli
The only point - this module has to be then production dependency then . Meanwhile why I see is a good way
Alternative usage. If you wish not to have this module as a global dependency - you can also use npx:
"prepare": "npm run is-prod || husky install",
"is-prod": "npx -y check-env-cli NODE_ENV=production"
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I still consider this to be an issue.
I have tried alternative approaches instead of using prepare
script:
is-ci
to dev dependencies"postinstall": "is-ci || husky install || echo Skipped husky setup"
this will just show error when binary is not available. but using this script is a problem while prepare
is ran at local dependencies install then "postinstall" is also executed when package is used as dependency. echo
was chosen for windows compatibility, as constructs like || :
or || true
don't work there.
also, while the most problematic place is CI invocation, the check should be really is-dev
to account for scenarios where you run yarn install --production
locally
Updated version of the popular workaround for this given above from @pinalbhatt - since later npm versions give warnings that set-script
and --prod
are both deprecated:
npm pkg delete scripts.prepare && npm install --omit=dev
(Note the single space rather than empty string - have raised a SO question in case some further light can be thrown on this: https://stackoverflow.com/questions/73896448. UPDATE - got a good answer to this and have now updated this one accordingly.)
I wanted to say just use npm pkg delete scripts.prepare
, but you already got it :)
The "custom script" option listed in the husky docs worked best for me while deploying a small hobby project to Heroku, which is not supported by the
is-ci
tool. The fact that it's a node script adds the flexibility to check for production environment:// prepare.js const isProduction = process.env.NODE_ENV === 'production'; const isCi = process.env.CI !== undefined; if (!isCi && !isProduction) { require('husky').install(); }
Yes - I like this the best as then I can document in that script why I have to do all these workarounds. With all other solutions they will just be undocumented workarounds buried in CI tools or package.json.
There are a large variety of approaches, and not one is satisfying
I personally prefer
{
"prepare": "test -d node_modules/husky && husky install || echo \"husky is not installed\"",
}
IMO, it's evidence that many projects are getting deployed with dev dependencies, which is sad to realize
If you use command like npm ci --omit=dev
you can access those property via $npm_config_omit
.
According to value of $npm_config_omit
you can decide to run husky install command or not.
{
"postinstall": "if [ \"$npm_config_omit\" = \"dev\" ]; then echo \"Skip husky installation\"; else husky install; fi"
}
If you use command like
npm ci --omit=dev
you can access those property via$npm_config_omit
. According to value of$npm_config_omit
you can decide to run husky install command or not.{ "postinstall": "if [ \"$npm_config_omit\" = \"dev\" ]; then echo \"Skip husky installation\"; else husky install; fi" }
Best solution by far. Doesn't require extra packages, or modifying the run script.
"prepare": "if [[ -x \"$(command -v husky)\" ]]; then husky install; fi"
@malko Thanks for the tip, this actually did the job for me. 🙏
UPD: Had to adjust it a bit to make it also work in my local env:
"prepare": "sh -c 'if [[ -x \"$(command -v husky)\" ]]; then husky install; fi'",
My take:
{
"prepare": "command -v husky &>/dev/null && husky install || true"
}
Don't know how cross-env it is, but works just fine for me on linux.
adding --ignore-scripts worked for me
RUN npm ci --only=production --ignore-scripts
In version 8.x and above use --omit=dev flag to install only regular dependencies:
RUN npm ci --omit=dev --ignore-scripts
This will install only dependencies, and not devDependencies, regardless of the value of the NODE_ENV environment variable.
If you use 6.x or an earlier version, you need to use the --only=prod flag instead.
For now i am using this solution
RUN npm set-script prepare "" && npm ci --only=production
in my Docker file
As we're using yarn this is my Dockerfile hack to effectively disable just the prepare lifecycle script and not use the blanket --ignore-scripts argument, by using sed to delete the line.
RUN \
if [ -f yarn.lock ]; then \
sed -i '/prepare/d' package.json; \
yarn --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
I solved it by adding true, this way the process returns success even though husky doesn't exists
"scripts": {
"prepare": "husky || true"
}
thought maybe someone need to see this.
// .husky/install.mjs
// Skip Husky install in production and CI
if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') {
process.exit(0)
}
const husky = (await import('husky')).default
console.log(husky())
"prepare": "node .husky/install.mjs"
source doc: https://typicode.github.io/husky/how-to.html#ci-server-and-docker
this still gave me error though just to let you know
> prepare
> node .husky/install.mjs
node:internal/modules/esm/resolve:854
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
better to use this: https://github.com/typicode/husky/issues/914#issuecomment-2145063108 at least it worked.
I have a
package.json
similar to:Running
npm install --prod
(orNODE_ENV=production
) will only install production dependencies and thusnode_modules/.bin/husky
will not be present. In my case this happens when trying to build a docker container where I want to install only the production dependencies.What is the suggested way to handle this scenario?
With husky 4 it worked properly as
husky install
wasn't needed.