Skip to content

Commit 640bf4b

Browse files
authored
fix: only run husky in a git checkout so npm consumers don't break (#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 -->
1 parent e2c53c2 commit 640bf4b

2 files changed

Lines changed: 12 additions & 1 deletion

File tree

β€Žpackage.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@
196196
"start:css": "node scripts/watch-styling.mjs",
197197
"start:tutorial": "yarn workspace @stream-io/stream-chat-react-tutorial dev",
198198
"start:vite": "yarn workspace @stream-io/stream-chat-react-vite dev",
199-
"postinstall": "husky",
199+
"postinstall": "node -e \"require('fs').existsSync('scripts/install-husky.mjs') && import('./scripts/install-husky.mjs')\"",
200200
"test": "vitest run",
201201
"test:watch": "vitest",
202202
"types": "tsc --emitDeclarationOnly false --noEmit",

β€Žscripts/install-husky.mjsβ€Ž

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { existsSync } from 'node:fs';
2+
3+
// husky installs this repo's local git hooks and is a dev-only dependency. It is
4+
// invoked from a presence-guarded postinstall (see package.json) so it never runs
5+
// for consumers β€” this file is intentionally not published. The .git check is a
6+
// secondary guard for non-checkout environments; husky's own default() already
7+
// no-ops gracefully on a missing .git or HUSKY=0, and any genuine setup error is
8+
// left to surface rather than be swallowed. See GetStream/stream-chat-js#1763.
9+
if (existsSync('.git')) {
10+
(await import('husky')).default();
11+
}

0 commit comments

Comments
Β (0)