⚡ scripts & 라이프사이클 훅 마스터 — pre/post, husky, lint-staged

2026년 3월 5일 수정됨

📋 개요

npm scripts 의 pre/post 훅, 라이프사이클 전체 지도, cross-env, husky & lint-staged 로 팀 개발 자동화를 완성하는 방법을 다룬다.

📋 목차


📌 이 문서를 읽기 전에

⏱️ 예상 읽기 시간: 18분(전체) / 핵심 파트만: 8분 (pre/post + husky)

🗺️ 이 문서의 흐름
scripts 기본 → pre/post 훅라이프사이클 전체 지도환경변수husky & lint-staged → 완성형 설정

🎯 이 문서를 다 읽으면 할 수 있는 것

  • npm run build 전에 자동으로 타입 체크가 실행되도록 prebuild 를 설정할 수 있다
  • prepare 훅을 이용해 팀원이 npm install 만 해도 husky 가 자동 세팅되도록 만들 수 있다
  • Windows/Mac/Linux 모두에서 동작하는 환경변수 설정을 cross-env 로 구현할 수 있다
  • lint-staged 로 커밋할 파일에만 린트와 포맷을 실행하도록 설정할 수 있다

🗺️ 이 문서의 배경 세계관: '영수네 커뮤니티'

  • 🐣 영철 ( 신입 ): "리드 님, 팀원들이 ESLint 에러 있는 코드를 자꾸 커밋해요. 저도 가끔 깜빡하고요. 빌드 때마다 린트 에러 잡는 게 너무 번거로워요. 그리고 NODE_ENV=production next build 이렇게 스크립트 작성했는데, 팀에 Windows 유저가 있어서 그 분 환경에서만 실패한대요. 어떻게 하면 되나요?"
  • 🦁 영호 ( 리드 ): "두 문제 모두 해결 방법이 있어요. 환경변수는 cross-env 로, 린트 자동화는 husky + lint-staged 로요. husky 는 git hook 에 연결해줘서 git commit 할 때 자동으로 린트가 실행돼요. prepare 훅을 쓰면 팀원이 npm install 만 해도 자동으로 설정이 완료돼요."

🤔 왜 알아야 하는가

코드 리뷰에서 실제 비즈니스 로직이 아닌 "ESLint 경고 있어요", "세미콜론 빠졌어요" 같은 피드백이 올라오면 시간 낭비다. 또한 CI 에서 린트 검사를 하면 "왜 미리 잡지 않았나요?" 하는 피드백이 나온다.

husky + lint-staged + pre-commit 훅 을 설정하면 커밋하는 순간 자동으로 린트와 포맷이 실행되어, 깨끗하지 않은 코드는 아예 커밋이 안 된다. 팀 전체의 코드 품질이 자동으로 유지된다.

scripts 는 단순한 명령어 모음이 아니다. 개발 워크플로 전체를 자동화하는 파이프라인이다.


📜 scripts 기본 문법과 실행 방법

{
  "scripts": {
    "dev":        "next dev", // 🐯 개발 서버를 띄울 때 가장 많이 치게 될 명령어예요.
    "build":      "next build", // 프로덕션 용으로 최적화된 결과물을 만듭니다.
    "start":      "next start", // 빌드된 결과물을 실제 서버로 돌릴 때 씁니다.
    "lint":       "next lint", // 린트(코드 스타일) 체크를 합니다.
    "type-check": "tsc --noEmit", // 🦁 타입스크립트 에러가 없는지만 딱 확인합니다. (파일 생성 X)
    "test":       "jest"
  }
}
npm run dev         # 개발 서버
npm run build       # 빌드
npm run type-check  # 타입 체크
 
# run 을 생략할 수 있는 특수 명령어
npm test            # jest 실행
npm start           # next start 실행

scripts 안에서 다른 script 참조

{
  "scripts": {
    "lint":       "next lint",
    "type-check": "tsc --noEmit",
    "validate":   "npm run lint && npm run type-check"
  }
}
npm run validate    # lint → type-check 순서로 실행

⏪⏩ pre / post 훅 — 자동 실행 체이닝

pre<script>post<script> 는 특정 스크립트 전후에 자동으로 실행된다.

{
  "scripts": {
    // 💡 [선수 필승] 빌드 전에 타입 에러가 하나라도 있으면 빌드를 시작도 안 하고 멈춥니다!
    "prebuild":   "npm run type-check",
    "build":      "next build",
    // 🦁 [뒷정리] 빌드가 성공하고 나면 사이트맵을 자동으로 생성하도록 예약합니다.
    "postbuild":  "node scripts/generate-sitemap.js"
  }
}
npm run build 실행 자동으로:
 
prebuild (타입 체크)

build (Next.js 빌드)

postbuild (사이트맵 생성)

🔥 실무 활용 패턴:

{
  "scripts": {
    "pretest":  "npm run type-check",
    "test":     "jest",
    "posttest": "echo '✅ 모든 테스트 통과'"
  }
}

pre/post 훅은 언제 쓰면 좋은가:

상황스크립트
빌드 전 타입 에러 사전 차단prebuildtsc --noEmit
빌드 후 사이트맵/번들 분석postbuild분석 스크립트
배포 전 최종 검증predeploylint + test

🗺️ 라이프사이클 훅 전체 지도

npm 은 특정 명령어 실행 시 자동으로 트리거되는 내장 라이프사이클 훅을 제공한다.

npm install 라이프사이클

npm install 실행 시:

preinstall
  ↓
install / postinstall
  ↓
prepublish (deprecated)
  ↓
prepare                  ← 가장 중요! npm install 후 항상 실행
  ↓
prepublishOnly           ← npm publish 시만 실행

prepare — 팀 자동화의 핵심

{
  "scripts": {
    "prepare": "husky install"
  }
}

prepare 는:

  1. npm install 후 자동 실행
  2. npm publish 전 자동 실행
  3. git 에서 클론 후 npm install 시 자동 실행

효과: 팀원이 처음 프로젝트를 클론하고 npm install 만 하면 husky install 이 자동 실행되어 git 훅이 세팅된다. 별도 문서 없이 자동으로!

postinstall — 의존성 설치 후 자동 실행

{
  "scripts": {
    "postinstall": "prisma generate"
  }
}

npm install 후 자동으로 prisma generate 가 실행되어 Prisma Client 가 생성된다.

npm install 실행 → 의존성 설치 완료 → postinstall 자동 실행 → prisma generate

팀원이 클론 후 겪는 공통 문제 해결:

{
  "scripts": {
    // 🦁 팀원이 처음으로 이 프로젝트에 들어왔을 때, npm install만 치면...
    // 1. husky가 자동 설치되고 (.prepare)
    "prepare":     "husky",
    // 2. 프리즈마 클라이언트가 자동 생성됩니다 (.postinstall)
    "postinstall": "prisma generate"
  }
}

이 두 줄이 있으면 팀원은 npm install 만으로:

  • git 훅 자동 설정 (husky)
  • Prisma Client 자동 생성

완료된다.


🌍 환경변수와 scripts — cross-env 패턴

문제 — OS 별 환경변수 문법 차이

# Linux / macOS (동작)
NODE_ENV=production next build
 
# Windows (동작 안 함!)
NODE_ENV=production next build    # ← 에러
set NODE_ENV=production && next build  # ← Windows 문법
{
  "scripts": {
    "build:prod": "NODE_ENV=production next build"
    // Windows 팀원 PC 에서 실패!
  }
}

해결 — cross-env

npm install -D cross-env
{
  "scripts": {
    // 💡 Windows와 Mac/Linux는 환경변수 문법이 달라서 가끔 싸워요.
    // 'cross-env' 앱이 중간에서 통역사 역할을 해주어 모두가 행복해집니다.
    "build:prod":   "cross-env NODE_ENV=production next build",
    "build:analyze": "cross-env ANALYZE=true next build",
    "test:prod":    "cross-env NODE_ENV=test jest"
  }
}

cross-env 는 OS 에 상관없이 환경변수를 설정해준다.

Next.js 에서 환경변수와 scripts 패턴

{
  "scripts": {
    "dev":              "next dev",
    "dev:turbo":        "next dev --turbo",
    "dev:debug":        "cross-env NODE_OPTIONS='--inspect' next dev",
    "build":            "next build",
    "build:analyze":    "cross-env ANALYZE=true next build",
    "build:prod":       "cross-env NODE_ENV=production next build",
    "start":            "next start",
    "start:prod":       "cross-env NODE_ENV=production next start -p 8080"
  }
}

🐶 husky & lint-staged — 코드 품질 자동화

설정 과정

# 1. 설치
npm install -D husky lint-staged
 
# 2. husky 초기화
npx husky init
# → .husky/ 디렉터리 생성 + prepare 훅 자동 추가
// package.json 에 자동 추가된 내용
{
  "scripts": {
    "prepare": "husky"
  }
}

pre-commit 훅 설정

# .husky/pre-commit
npm run lint-staged
// 🐶 package.json
{
  "lint-staged": {
    // 🦁 영철아, 모든 파일을 검사하면 너무 느리니까 "이번에 내가 수정한 파일"만 골라서!
    "*.{ts,tsx}": [
      "eslint --fix", // 💡 고칠 수 있는 건 지가 알아서 다 고쳐줍니다.
      "prettier --write" // 💡 줄바꿈, 세미콜론까지 깔끔하게!
    ],
    "*.{json,md,css,scss}": [
      "prettier --write"
    ]
  }
}

동작 흐름

git commit 실행
  ↓
husky 의 pre-commit 훅 트리거
  ↓
lint-staged 실행
  ↓
커밋 대상 파일만 선별
  (git add 된 파일들만 — 전체 파일 검사 아님!)
  ↓
*.ts, *.tsx → eslint --fix + prettier --write
*.json, *.md → prettier --write
  ↓
수정된 파일 자동으로 다시 staging
  ↓
커밋 완료 (에러 있으면 커밋 중단)

💡 lint-staged 의 핵심: 전체 파일이 아닌 커밋 대상 파일만 검사한다. 10만 줄짜리 프로젝트에서도 커밋하는 파일 5개만 검사하므로 빠르다.

commit-msg 훅 — 커밋 메시지 형식 강제

# .husky/commit-msg
npx --no -- commitlint --edit $1
npm install -D @commitlint/config-conventional @commitlint/cli
// commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional']
}
# 올바른 커밋 메시지
git commit -m "feat: 스터디 매칭 기능 추가"
git commit -m "fix: 프로필 이미지 업로드 버그 수정"
 
# 잘못된 형식 → 커밋 거부
git commit -m "수정함"    # ← commitlint 에러

🏃 병렬 / 순차 실행 — npm-run-all

여러 스크립트를 순서대로 혹은 동시에 실행할 때:

npm install -D npm-run-all
{
  "scripts": {
    "validate":     "run-s type-check lint test",
    "validate:ci":  "run-p type-check lint",
 
    "type-check": "tsc --noEmit",
    "lint":       "next lint",
    "test":       "jest"
  }
}
# run-s = run-sequential (순차)
npm run validate
# type-check 완료 → lint 실행 → test 실행
 
# run-p = run-parallel (병렬)
npm run validate:ci
# type-check 와 lint 동시에 실행 (더 빠름)

🚀 Next.js 프로젝트 완성형 scripts

영수네 커뮤니티의 완성형 scripts:

{
  "scripts": {
    "dev":            "next dev",
    "dev:turbo":      "next dev --turbo",
    "build":          "next build",
    "build:analyze":  "cross-env ANALYZE=true next build",
    "start":          "next start",
    "lint":           "next lint",
    "lint:fix":       "next lint --fix",
    "type-check":     "tsc --noEmit",
    "test":           "jest --passWithNoTests",
    "test:watch":     "jest --watch",
    "test:ci":        "jest --ci --coverage --passWithNoTests",
    "validate":       "run-s type-check lint test",
    "prebuild":       "npm run type-check",
    "prepare":        "husky",
    "postinstall":    "prisma generate"
  },
 
  "lint-staged": {
    "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md,css}": "prettier --write"
  }
}

각 스크립트 역할:

스크립트실행 시점역할
prebuildnpm run build 전 자동타입 에러 있으면 빌드 차단
preparenpm install 후 자동husky git 훅 자동 설치
postinstallnpm install 후 자동Prisma Client 자동 생성
validate수동 or CI타입체크 + 린트 + 테스트 일괄 검증
dev:turbo개발 중Turbopack 으로 빠른 HMR
build:analyze번들 분석 시@next/bundle-analyzer 활성화

🏁 이번에 배운 내용 총정리

개념핵심 요약
pre/post 훅pre<script> 전 자동, post<script> 후 자동 실행
preparenpm install 후 항상 실행. 팀 환경 자동 설정에 활용
postinstall의존성 설치 후 자동 실행. Prisma generate 등에 활용
cross-envOS 불문 환경변수 설정. Windows 팀원 있으면 필수
huskygit hook 관리. prepare 로 팀원 자동 설치
lint-staged커밋 대상 파일만 선별해 린트/포맷 실행
npm-run-allrun-s (순차) / run-p (병렬) 스크립트 실행

📝 마무리 퀴즈

Q1. prepare 훅이 실행되는 시점이 아닌 것은?

a) npm install 실행 후
b) npm publish 실행 전
c) npm run build 실행 전
d) git 클론 후 npm install 실행 시

정답: cnpm run build 전에는 실행되지 않는다

💡 상세 해설:

  • 원리 설명: prepare 는 npm 의 내장 라이프사이클 훅으로, npm install (의존성 설치), npm publish (패키지 배포), npm pack 실행 시 트리거된다. npm run <임의스크립트> 실행 시에는 트리거되지 않는다. npm run build 전에 뭔가를 자동 실행하려면 prebuild 훅을 사용해야 한다.
  • 📌 핵심 기억법: "prepare = npm 내장 이벤트(install, publish)에만 반응. 커스텀 스크립트에는 pre<script> 를 사용."

Q2. lint-staged 를 사용하는 주요 이유는?

a) ESLint 를 더 빠르게 실행하기 위한 캐시 시스템이다
b) 커밋할 파일만 선별해 린트를 실행하므로 속도가 빠르고 불필요한 검사를 줄인다
c) git blame 에서 린트 관련 커밋을 숨긴다
d) ESLint 설정을 자동으로 생성해준다

정답: b — 커밋 대상 파일만 선별해 실행

💡 상세 해설:

  • 원리 설명: lint-stagedgit add 된 파일(staged files)만 필터링해서 린트와 포맷을 실행한다. 1만 개 파일이 있어도 커밋하는 5개 파일만 검사하므로 매우 빠르다. 또한 --fix 옵션으로 자동 수정된 파일을 다시 staging 해주어 수정 후 재커밋 없이 바로 커밋된다.
  • 📌 핵심 기억법: "lint-staged = 변경한 파일만 검사. 전체 검사가 아니라 staged(커밋 예정) 파일만."

Q3. 🐣 영철이의 테스트 타임 — 아키텍처 설계

영숙 디자이너가 슬랙에 메시지를 보냈다. "영철 님, 제가 작은 CSS 수정을 했는데 커밋하려고 했더니 자꾸 ESLint 에러가 나서 커밋이 안 돼요. 저는 CSS 만 바꿨는데요..." 영호 리드가 "lint-staged 설정 확인해봐요" 라고 했다. 현재 설정은:

{
  "lint-staged": {
    "*": ["eslint --fix", "prettier --write"]
  }
}

문제점과 올바른 수정 방법을 설명하라.

정답: 모든 파일(*)에 ESLint 를 적용하는 것이 문제. 파일 확장자별로 분리해야 한다.

{
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{css,scss,json,md}": [
      "prettier --write"
    ]
  }
}

💡 상세 해설:

  • 원인: "*" 패턴은 CSS, JSON, 이미지 파일 등 모든 파일에 ESLint 를 실행한다. ESLint 는 JavaScript/TypeScript 파일에만 작동하므로 CSS 파일에 적용되면 파싱 에러가 발생해 커밋을 막는다.
  • 수정: 확장자별로 적용할 도구를 분리한다. .ts, .tsx 에만 ESLint 를 적용하고, CSS/JSON/MD 에는 Prettier 만 적용한다.
  • 영숙 님 상황: CSS 파일에 ESLint 가 적용되어 "이 파일을 파싱할 수 없다" 에러가 나서 커밋이 막혔던 것이다.
  • 📌 핵심 기억법: "lint-staged 패턴은 도구에 맞는 파일만 선별해야 한다. * 는 너무 광범위하다."

🐣 영철이의 퇴근 일기

오늘 husky + lint-staged 설정을 완성했다. 영숙 님 덕분에 CSS 파일 패턴 문제도 잡았고, 이제 팀 전체가 커밋할 때 자동으로 린트가 돌아간다.

prepare 훅 덕분에 새 팀원이 들어와도 npm install 하나로 git 훅이 자동으로 세팅된다는 게 진짜 편하다. 이전에는 팀에 들어온 사람마다 "husky 설치했어요?" 물어봐야 했는데.

💡 오늘의 교훈: "좋은 scripts 설정은 '팀원이 아무것도 기억하지 않아도 자동으로 돌아가게' 만드는 것이다. preparepostinstall 이 그 자동화의 핵심이다."

cross-env 도 이제 안 쓰면 찝찝할 것 같다. Windows 유저를 위해 항상 챙겨야지.

퇴근 후에 라면 먹고 싶었는데, 회사 근처 편의점 라면이 맛있더라. 오늘 기분도 좋고 빨리 집 가서 게임 하나 해야겠다. 내일은 Next.js 프로젝트 설정 실전편.


🔗 더 알아보기