fix: only run husky in a git checkout so npm consumers don't break#1764
Merged
Conversation
`postinstall` ran `husky` unconditionally. npm executes a dependency's `postinstall` for every consumer, but `husky` is a devDependency and isn't installed in a consumer's tree, so `npm install stream-chat` failed with `code 127 / husky: command not found`. Yarn Berry runs the root workspace's `postinstall` (not `prepare`) on `yarn install`, so husky setup must stay in `postinstall` for contributors. Instead of executing husky unconditionally, postinstall now invokes a dev-only `scripts/install-husky.mjs` only when it is present — and that file is intentionally not in `package.json#files`, so consumers never receive it and the guard short-circuits to a no-op. The invocation uses `node` rather than a shell guard so it is cross-platform (npm runs consumer postinstall via cmd.exe on Windows, where `||`/`true` are invalid). The script runs husky only inside a git checkout and lets genuine setup errors surface rather than swallowing them. `prepare: yarn run build` is unchanged (npm git-ref installs still build). Closes #1763
Contributor
|
Size Change: 0 B Total Size: 407 kB ℹ️ View Unchanged
|
isekovanic
approved these changes
Jun 5, 2026
github-actions Bot
pushed a commit
that referenced
this pull request
Jun 5, 2026
## [9.45.1](v9.45.0...v9.45.1) (2026-06-05) ### Bug Fixes * only run husky in a git checkout so npm consumers don't break ([#1764](#1764)) ([88dbdb6](88dbdb6))
|
🎉 This PR is included in version 9.45.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
oliverlaz
added a commit
to GetStream/stream-chat-react
that referenced
this pull request
Jun 5, 2026
…3211) ### 🎯 Goal `postinstall` ran `husky` unconditionally. npm executes a dependency's `postinstall` for every consumer, but `husky` is a `devDependency` and isn't installed in a consumer's tree, so `npm install stream-chat-react` failed: ``` npm error code 127 npm error sh: husky: command not found ``` This ports the same fix already merged for the JS SDK in [GetStream/stream-chat-js#1764](GetStream/stream-chat-js#1764) — `stream-chat-react` had the identical `"postinstall": "husky"`. ### 🛠 Implementation details **Why husky has to stay in `postinstall`:** Yarn Berry (this repo's package manager) runs the **root workspace's `postinstall`** on `yarn install` but **not** its `prepare`. Moving husky to `prepare` would silently stop installing contributors' git hooks. husky must stay in `postinstall`; the fix is to stop *running* it for consumers. - `postinstall` now invokes a dev-only `scripts/install-husky.mjs` **only when it is present** — and that file is intentionally **not** in `package.json#files` (which publishes only `dist`, `package.json`, `README.md`, `AI.md`), so consumers never receive it and the guard short-circuits to a no-op. - The invocation runs via `node` (not a shell `|| true`) so it's cross-platform — npm runs consumer postinstalls through `cmd.exe` on Windows, where `||`/`true` aren't valid. - `scripts/install-husky.mjs` runs husky only inside a git checkout, and lets genuine husky setup errors **surface** (not swallowed) so contributors learn if hook installation actually fails. > Note: unlike the JS SDK PR (which left `prepare: yarn run build` untouched), this repo uses `prepack: yarn build` and has no `prepare` script, so nothing there needed changing — the husky fix is independent of it. **Verified locally:** | Scenario | Result | | --- | --- | | Consumer (no `scripts/install-husky.mjs`) | exit 0 · husky never executed | | Contributor (`.git` + script present) | `core.hooksPath=.husky/_` · hooks installed · exit 0 | `yarn prettier` and `yarn eslint` clean on both changed files. ### 🎨 UI Changes None — build/install tooling only. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Improved post-install script configuration to make Git hook initialization more reliable and conditional based on repository presence. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
postinstallranhuskyunconditionally. npm executes a dependency'spostinstallfor every consumer, buthuskyis adevDependencyand isn't installed in a consumer's tree, sonpm install stream-chatfailed:Closes #1763.
Why husky has to stay in
postinstallYarn Berry (this repo's package manager) runs the root workspace's
postinstallonyarn installbut not itsprepare. So moving husky topreparewould silently stop installing contributors' git hooks. husky must stay inpostinstall; the fix is to stop running it for consumers.Fix
postinstallnow invokes a dev-onlyscripts/install-husky.mjsonly when it is present — and that file is intentionally not added topackage.json#files, so consumers never receive it and the guard short-circuits to a no-op.node(not a shell|| true) so it's cross-platform — npm runs consumer postinstalls throughcmd.exeon Windows, where||/truearen't valid.scripts/install-husky.mjsruns husky only inside a git checkout, and lets genuine husky setup errors surface (not swallowed) so contributors learn if hook installation actually fails.prepare: yarn run buildis unchanged (npm git-ref installs still build a package).Testing
Verified end-to-end with a packed tarball (
yarn pack) installed into a throwaway consumer, and a freshgit clone+yarn install:npm install <tarball>(consumer)git clone+yarn install(contributor)core.hooksPath=.husky/_· hooks installedpostinstall: huskycode 127/husky: command not foundyarn lintclean.