๐ npm โ pnpm ๋ง์ด๊ทธ๋ ์ด์ โ ์์ ํ๊ฒ, ์์ ํ๊ฒ
๐ ๊ฐ์
๊ธฐ์กด npm/Yarn ํ๋ก์ ํธ๋ฅผ pnpm ์ผ๋ก ์ ํํ๋ ๋จ๊ณ๋ณ ๋ฃจํด, ํํ ํจ์ ๊ณผ ํด๊ฒฐ์ฑ , ํ ์ ์ฒด ์จ๋ณด๋ฉ ์ฒดํฌ๋ฆฌ์คํธ๊น์ง
07. npm โ pnpm ๋ง์ด๊ทธ๋ ์ด์
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ์์์ผ ํ๋๊ฐ
- โ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ฒดํฌ๋ฆฌ์คํธ
- ๐ช ๋จ๊ณ๋ณ ๋ง์ด๊ทธ๋ ์ด์ ๋ฃจํด
- ๐ง ํํ ํจ์ ๊ณผ ํด๊ฒฐ์ฑ
- ๐ฅ ํ ์จ๋ณด๋ฉ & CI/CD ์ ํ
- ๐ฆ ๋ชจ๋ ธ๋ ํฌ ๋ง์ด๊ทธ๋ ์ด์
- pnpm ์ ์๋ ค์ง ์ ํ์ฌํญ
- ์ด์ ๋ฆฌ
- ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
- ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: ์ฝ 30๋ถ(์ ์ฒด) / ํต์ฌ ํํธ๋ง: 15๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
[์ ํ ์ ์ฒดํฌ๋ฆฌ์คํธ] โ [๋จ๊ณ๋ณ ๋ง์ด๊ทธ๋ ์ด์ ] โ [ํจ์ ํด๊ฒฐ] โ [ํ ์จ๋ณด๋ฉ] โ [์ ํ์ฌํญ ์ธ์]
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- npm/Yarn ํ๋ก์ ํธ๋ฅผ pnpm ์ผ๋ก ์์ ํ๊ฒ ์ ํํ๋ 7๋จ๊ณ ๋ฃจํด์ ์คํํ ์ ์๋ค
- ๋ง์ด๊ทธ๋ ์ด์ ํ ๋ฐ์ํ๋ ํํ ์๋ฌ๋ฅผ ์ค์ค๋ก ์ง๋จํ๊ณ ํด๊ฒฐํ ์ ์๋ค
- CI/CD, GitHub Actions, Docker ๋ฅผ pnpm ๊ธฐ์ค์ผ๋ก ์ ๋ฐ์ดํธํ ์ ์๋ค
- pnpm ์ ์๋ ค์ง ์ ํ์ฌํญ์ ํ์๊ฒ ์ฌ์ ์ ์๋ดํ ์ ์๋ค
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'

- ๐ฃ ์์ฒ ( ์ ์
): "์ํธ ๋, ๋๋์ด ์์ ๋์ด pnpm ์ ํ ์น์ธํด์ฃผ์
จ์ด์! ๊ทผ๋ฐ ๋ง์ ์์ํ๋ ค๋ ์ด๋์๋ถํฐ ํด์ผ ํ ์ง ๋ชจ๋ฅด๊ฒ ์ด์. ๊ทธ๋ฅ
npm install๋์pnpm installํ๋ฉด ๋๋ ๊ฑด๊ฐ์? ๊ธฐ์กดpackage-lock.json์ ์ด๋ป๊ฒ ํ๊ณ ,.github/workflows๋ ๋ฐ๊ฟ์ผ ํ๋์? CI ์์ ๋ฐฐํฌ ํ์ดํ๋ผ์ธ ๋์ค์ ์คํจํ๋ฉด ๋๋๋ฆด ์ ์๋์?" - ๐ฆ ์ํธ ( ๋ฆฌ๋ ): "๊ธํ๊ฒ ํ๋ฉด ๊ผญ ๋ญ๊ฐ ๋น ์ ธ์. ์์๊ฐ ์ค์ํด์.
pnpm import๋ก ๊ธฐ์กด lock ํ์ผ์ ๋ณํํ๊ณ ,.npmrc์์ hoisting ์ค์ ์ ์ ๊ฒํ๊ณ , ๋ก์ปฌ์์ dev/build/test ๋ค ํต๊ณผํ ๋ค์ CI ์์ ํด์ผ ํด์. ํนํ GitHub Actions ์ํฌํ๋ก์ฐ ํ์ผ์ ๋ธ๋์น๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ PR ๋ก ๊ฒ์ฆํ๊ณ ๋จธ์งํ๋ ๊ฒ ์์ ํด์. ์๋๋ฅด์ง ๋ง๊ณ ์ฒดํฌ๋ฆฌ์คํธ ํ๋์ฉ ๋ฐ์๊ฐ์ธ์."
๐ค ์ ์์์ผ ํ๋๊ฐ
pnpm ์ npm ๊ณผ ๊ฐ๋ ์ ์ผ๋ก ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋จ์ํ ๋ช ๋ น์ด๋ง ๋ฐ๊พธ๋ฉด ๋๋ค๋ ์๊ฐ์ ํจ์ ์ด๋ค.
์ค์ ๋ก ๋ง์ด๊ทธ๋ ์ด์ ๋์ค ์์ฃผ ๊ฒช๋ ์ํฉ:
โ
๋ก์ปฌ์์๋ ์ ๋๋๋ฐ CI ์์ ์คํจ
โ
๋น๋๋ ๋๋๋ฐ ESLint ๊ฐ ์ ๋จ
โ
๊ฐ๋ฐ ์๋ฒ๋ ๋จ๋๋ฐ ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ import ์๋ฌ
โ
ํ์ A ๋ ๋๋๋ฐ ํ์ B ๋ ์ ๋จ
โ
Docker ๋น๋๊ฐ ๊ฐ์๊ธฐ ํจ์ฌ ๋๋ ค์ง
์ด ๋ชจ๋ ์ํฉ์ ์ฒด๊ณ์ ์ธ ์์ ๋ก ์งํํ๋ฉด ๋๋ถ๋ถ ์๋ฐฉํ ์ ์๋ค.
โ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ฒดํฌ๋ฆฌ์คํธ
๋ง์ด๊ทธ๋ ์ด์ ์์ ์ , ํ์ฌ ํ๋ก์ ํธ ์ํ๋ฅผ ์ ๊ฒํ๋ผ.
# 1. ํ์ฌ ํจํค์ง ๋งค๋์ ํ์ธ
cat package.json | grep packageManager
ls -la | grep -E "package-lock|yarn.lock|pnpm-lock"
# 2. ์ฌ์ฉ ์ค์ธ npm scripts ํ์ธ (postinstall ์ด ์๋์ง)
cat package.json | grep -A 20 '"scripts"'
# 3. .npmrc ๊ฐ ์์ผ๋ฉด ๋ด์ฉ ํ์ธ
cat .npmrc 2>/dev/null
# 4. CI/CD ํ์ผ ๋ชฉ๋ก ํ์ธ
ls .github/workflows/์ฒดํฌ๋ฆฌ์คํธ:
| ํญ๋ชฉ | ํ์ธ ๋ฐฉ๋ฒ | ์ฃผ์์ฌํญ |
|---|---|---|
| Node.js ๋ฒ์ | .nvmrc ๋๋ package.json engines | pnpm 9 ์ Node.js 18.12+ ํ์ |
| postinstall ์คํฌ๋ฆฝํธ | package.json scripts | Prisma, Husky ๋ฑ โ pnpm ์์๋ ๋์ ํ์ธ ํ์ |
| private registry | .npmrc | ์ค์ฝํ๋ณ registry ์ค์ pnpm ๋ ์ง์ |
| CI ํ๋ซํผ | .github/, .circleci/ ๋ฑ | pnpm ์ค์น ๋จ๊ณ ์ถ๊ฐ ํ์ |
| Docker | Dockerfile | pnpm ์ค์น + store ์บ์ ์ ๋ต |
| Dependabot | .github/dependabot.yml | package-ecosystem: "npm" ์ผ๋ก๋ pnpm ์ง์ |
๐ช ๋จ๊ณ๋ณ ๋ง์ด๊ทธ๋ ์ด์ ๋ฃจํด
Step 1: pnpm ์ค์น
# Corepack ์ผ๋ก ์ค์น (๊ถ์ฅ)
corepack enable
corepack prepare pnpm@latest --activate
# ๋๋ npm ์ผ๋ก
npm install -g pnpm
# ๋ฒ์ ํ์ธ
pnpm --versionStep 2: lock ํ์ผ ๋ณํ
# npm โ pnpm: package-lock.json ์ pnpm-lock.yaml ๋ก ๋ณํ
pnpm import
# yarn.lock โ pnpm-lock.yaml
pnpm import
# ๋ณํ ํ ํ์ธ
ls pnpm-lock.yaml # ์์ฑ๋จ์ฃผ์: pnpm import ๋ ๊ธฐ์กด lock ํ์ผ์ ์ฐธ๊ณ ํด์ pnpm-lock.yaml ์ ์์ฑํ์ง๋ง, 100% ๋์ผํ ๋ฒ์ ์ด ๋ณด์ฅ๋์ง ์์ ์ ์๋ค. ํนํ ๊ฐ์ ์์กด์ฑ ๋ฒ์ ์ด ๋ฌ๋ผ์ง ์ ์์ผ๋ฏ๋ก, Step 4 ์์ ๋ฐ๋์ ํ
์คํธ๋ก ๊ฒ์ฆํ๋ค.
Step 3: ๊ธฐ์กด lock ํ์ผ ๋ฐ node_modules ์ ๋ฆฌ
# ๊ธฐ์กด ํ์ผ ์ ๊ฑฐ
rm -rf node_modules
rm package-lock.json # npm ์ด์๋ค๋ฉด
# rm yarn.lock # yarn ์ด์๋ค๋ฉด
# ๐ฆ .gitignore ์ pnpm-lock.yaml ์ด ์๋์ง ํ์ธ (์์ผ๋ฉด ์ ๊ฑฐ)
grep "pnpm-lock" .gitignoreStep 4: .npmrc ์ค์
# .npmrc (์ ๊ท๋ก ์์ฑํ๊ฑฐ๋, ๊ธฐ์กด ํ์ผ ๋งจ ์์ ์ด ๋ด์ฉ์ ์ถ๊ฐํฉ๋๋ค)
# ๐ฆ [์ดํต์ฌ] Next.js ํ๋ก์ ํธ ํ์ ์ค์ (ํธ์ด์คํ
ํ์ฉ)
# ์๋ pnpm์ ์จ๊ฒจ์ง ์์กด์ฑ์ ์ ๋ ํ์ฉํ์ง ์์ง๋ง, ์๋ ์ ํ ๋
์๋ค์ ์์ธ๋ก ์ณ์ค๋๋ค.
# ์ด๊ฑธ ์ ์ ์ด์ฃผ๋ฉด ESLint๋ Tailwind๊ฐ "๋ชจ๋์ ์ฐพ์ ์ ์๋ค"๊ณ ํ์
์ ์ ์ธํฉ๋๋ค.
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=prettier
public-hoist-pattern[]=tailwindcss
public-hoist-pattern[]=postcss
public-hoist-pattern[]=autoprefixer
# ๐ฆ [์์ ์ฅ์น] package.json์ ์ ํ Node/pnpm ๋ฒ์ ์ด ์๋๋ฉด ์ค์น ์์ฒด๋ฅผ ํ๊ฒจ๋
๋๋ค.
engine-strict=trueStep 5: pnpm install & ๊ฒ์ฆ
# ์๋ก ์ค์น
pnpm install
# ๋ก์ปฌ ๊ฒ์ฆ (์ด ์ธ ๊ฐ์ง ๋ชจ๋ ํต๊ณผํด์ผ ๋ค์ ๋จ๊ณ๋ก)
pnpm dev # ๊ฐ๋ฐ ์๋ฒ ์ ์ ๋์ ํ์ธ
pnpm build # ํ๋ก๋์
๋น๋ ์ฑ๊ณต ํ์ธ
pnpm test # ํ
์คํธ ํต๊ณผ ํ์ธ
pnpm lint # lint ์๋ฌ ์์ ํ์ธ
pnpm typecheck # TypeScript ์๋ฌ ์์ ํ์ธStep 6: package.json ์ ๋ฐ์ดํธ
// package.json
{
"packageManager": "pnpm@9.15.0",
"engines": {
"node": ">=20.0.0",
"pnpm": ">=9.0.0"
},
"scripts": {
// npm ci โ pnpm install --frozen-lockfile
// npx โ pnpm dlx
"postinstall": "prisma generate" // ๊ทธ๋๋ก ์ ์ง (pnpm ๋ ์คํํจ)
}
}Step 7: git ์ปค๋ฐ
git add pnpm-lock.yaml .npmrc package.json
git rm package-lock.json # ๋๋ yarn.lock
git commit -m "chore: npm โ pnpm ๋ง์ด๊ทธ๋ ์ด์
- package-lock.json โ pnpm-lock.yaml ๋ณํ (pnpm import)
- .npmrc ์ถ๊ฐ (public-hoist-pattern ์ค์ )
- package.json ์ packageManager ํ๋ ์ถ๊ฐ
- engines ํ๋ ์
๋ฐ์ดํธ (node>=20, pnpm>=9)"๐ง ํํ ํจ์ ๊ณผ ํด๊ฒฐ์ฑ
ํจ์ 1: ESLint / TypeScript ๊ด๋ จ ์๋ฌ
Error: Cannot find module 'eslint'
Error: Cannot find module '@types/react'
ํด๊ฒฐ:
# .npmrc ์ ํธ์ด์คํ
ํจํด ์ถ๊ฐ
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*pnpm install # ์ฌ์ค์นํ๋ฉด ์ ์ฉ๋จํจ์ 2: Prisma generate ์คํจ
Error: @prisma/client did not initialize yet.
Please run "prisma generate"
ํด๊ฒฐ:
// package.json
{
"scripts": {
"postinstall": "prisma generate"
}
}ํจ์ 3: Husky hooks ๊ฐ ๋์ํ์ง ์์
.husky/pre-commit not found
ํด๊ฒฐ:
# husky ์ฌ์ด๊ธฐํ
pnpm dlx husky install
# ๋๋ package.json ์ prepare ์คํฌ๋ฆฝํธ
{
"scripts": {
"prepare": "husky"
}
}ํจ์ 4: ํฌํ ์์กด์ฑ์ผ๋ก ์ธํ ๋น๋ ์๋ฌ
Error: Cannot find module 'some-package'
# package.json ์ ์๋ ํจํค์ง๋ฅผ ์ง์ import ํ๊ณ ์์์
ํด๊ฒฐ:
# ์ด๋ค ํจํค์ง์ธ์ง ํ์ธ
pnpm why some-package
# package.json ์ ๋ช
์์ ์ผ๋ก ์ถ๊ฐ
pnpm add some-package์ด ์๋ฌ๋ npm ์์ ํฌํ
์์กด์ฑ์ผ๋ก ๋์ํ๋ค๊ฐ pnpm ์์ ์ ์์ ์ผ๋ก ์ฐจ๋จ๋ ์ผ์ด์ค๋ค. ์์ ์ด ํ์ํ ์ฝ๋ ํ์ง ๋ฌธ์ ์ด๋ฏ๋ก ๋ฐ๋์ package.json ์ ์ถ๊ฐํด์ผ ํ๋ค.
ํจ์ 5: ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ฌ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ์ง ๋ชปํจ
Error: ENOENT: no such file or directory, scandir '.../node_modules/...'
ํด๊ฒฐ (๋จ๊ณ์ ์ ๊ทผ):
# 1๋จ๊ณ: ํด๋น ํจํค์ง๋ง ์ ํ์ ์ผ๋ก ํธ์ด์คํ
public-hoist-pattern[]=๋ฌธ์ ๊ฐ๋๋ํจํค์ง๋ช
# 2๋จ๊ณ: ๊ทธ๋๋ ์ ๋๋ฉด nodeLinker ๋ฅผ hoisted ๋ก ๋ณ๊ฒฝ
# pnpm-workspace.yaml ๋๋ .npmrc
node-linker=hoistedํจ์ 6: Docker ๋น๋ ์ corepack ๋ฏธ์ค์น
# โ ๋ฌธ์ ์๋ Dockerfile
FROM node:20-slim
RUN npm install -g pnpm # ์ด๋ ๊ฒ ํ๋ฉด ๋ฒ์ ๋ถ์ผ์น ๊ฐ๋ฅ
# โ
์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ
FROM node:20-slim
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
# package.json ์ packageManager ๋ฒ์ ์ผ๋ก ์๋ ํ์ฑํ๋จํจ์ 7: pnpm-lock.yaml ์ด .gitignore ์ ํฌํจ๋ ๊ฒฝ์ฐ
# .gitignore ํ์ธ
grep "pnpm-lock" .gitignore
# ์๋ค๋ฉด ์ ๊ฑฐ
# pnpm-lock.yaml ์ ๋ฐ๋์ git ์ ์ปค๋ฐํด์ผ ํจ
# (npm ์ package-lock.json ๊ณผ ๋์ผํ ์ญํ )๐ฅ ํ ์จ๋ณด๋ฉ & CI/CD ์ ํ
ํ์ ์จ๋ณด๋ฉ ์๋ด๋ฌธ ํ ํ๋ฆฟ
## pnpm ์ผ๋ก ์ ํ๋์์ต๋๋ค ๐
### ์ค์น
\`\`\`bash
corepack enable
pnpm --version # 9.x.x ๊ฐ ํ์๋๋ฉด ์๋ฃ
\`\`\`
### ๊ธฐ์กด ๋ช
๋ น์ด โ ์ ๋ช
๋ น์ด
| ๊ธฐ์กด | ๋ณ๊ฒฝ |
|------|------|
| npm install | pnpm install |
| npm install ํจํค์ง | pnpm add ํจํค์ง |
| npm install -D ํจํค์ง | pnpm add -D ํจํค์ง |
| npm uninstall ํจํค์ง | pnpm remove ํจํค์ง |
| npm run dev | pnpm dev |
| npx create-next-app | pnpm dlx create-next-app |
| npm ci | pnpm install --frozen-lockfile |
### ์ฃผ์์ฌํญ
- \`package-lock.json\` ์ ๋ ์ด์ ์ฌ์ฉํ์ง ์์์
- \`pnpm-lock.yaml\` ์ด ์๋ก์ด lock ํ์ผ์ด์์ (์ปค๋ฐ ํ์)
- \`node_modules\` ๊ตฌ์กฐ๊ฐ ๋ฌ๋ผ ๋ณด์ฌ๋ ์ ์์ด์์GitHub Actions ์ ํ
# ๐ก CI ํ์ดํ๋ผ์ธ (GitHub Actions) ์ ํ ์ ํ ๋น๊ต
# โ ๋ณ๊ฒฝ ์ (npm ์์ ) โ
- name: Install
run: npm ci # ํจํค์ง ์ค์น์๋ง 2~3๋ถ์ด ๊ฑธ๋ฆฌ๋ ์์
# --------------------------------------------------
# โ
๋ณ๊ฒฝ ํ (pnpm ๋์
) โ
# 1๏ธโฃ ์ปดํจํฐ์ pnpm์ ๊น์์ฃผ๋ ๋ง๋ฒ์ Action
- name: Setup pnpm
uses: pnpm/action-setup@v4
# (์ฌ๊ธฐ์ version: 9 ๋ผ๊ณ ์ฐ์ง ์์๋ package.json์ packageManager๋ฅผ ์์์ ์ฝ์ต๋๋ค!)
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
# 2๏ธโฃ [ํต์ฌ] ์ด๊ฑฐ ํ ์ค๋ง ์ฐ๋ฉด ๋! pnpm ๊ธ๋ก๋ฒ ์ ์ฅ์๊ฐ ํต์งธ๋ก ์บ์ฑ๋ฉ๋๋ค.
cache: 'pnpm'
- name: Install
# 3๏ธโฃ ๋ฐฐํฌ ์์ ์๋ ๋ฌด์กฐ๊ฑด lock ํ์ผ์ ์ ๋ขฐํด์ผ ํ๋ฏ๋ก --frozen-lockfile์ ์๋๋ค. (npm ci ์ ๋๊ฐ์ ์ญํ )
# ์์์ ์บ์๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ ์ฉ๋์๋ค๋ฉด ์ค์น๊ฐ 15์ด ์ปท์ผ๋ก ๋๋ฉ๋๋ค!
run: pnpm install --frozen-lockfileDependabot ์ค์ (๋ณ๊ฒฝ ์์)
# .github/dependabot.yml
# npm ecosystem ์ด pnpm-lock.yaml ๋ ์ง์ํจ โ ๋ณ๊ฒฝ ๋ถํ์
version: 2
updates:
- package-ecosystem: "npm" # npm ๊ทธ๋๋ก ์ฌ์ฉ
directory: "/"
schedule:
interval: "weekly"๐ฆ ๋ชจ๋ ธ๋ ํฌ ๋ง์ด๊ทธ๋ ์ด์
๊ธฐ์กด Lerna, Yarn Workspaces ์์ pnpm workspace ๋ก ์ ํํ ๋.
Yarn Workspaces โ pnpm workspace
# ๋ณ๊ฒฝ ์ : package.json workspaces ํ๋
# {
# "workspaces": ["apps/*", "packages/*"]
# }
# ๋ณ๊ฒฝ ํ: pnpm-workspace.yaml ์ ๊ท ์์ฑ
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'# package.json ์์ workspaces ํ๋ ์ ๊ฑฐ
# yarn.lock ์ ๊ฑฐ
rm yarn.lock
rm -rf node_modules apps/*/node_modules packages/*/node_modules
# pnpm ์ผ๋ก ์ฌ์ค์น
pnpm installworkspace: ํ๋กํ ์ฝ ๋ณํ
// ๋ณ๊ฒฝ ์ (Yarn)
{ "@youngsu/ui": "*" }
// ๋ณ๊ฒฝ ํ (pnpm)
{ "@youngsu/ui": "workspace:*" }โ ๏ธ pnpm ์ ์๋ ค์ง ์ ํ์ฌํญ
๋ง์ด๊ทธ๋ ์ด์ ์ ์ ํ์๊ฒ ๊ณต์ ํด์ผ ํ ์ ํ์ฌํญ๋ค.
1. ํ๋๋งํฌ๊ฐ ์ง์๋์ง ์๋ ํ๊ฒฝ
Docker ๋น๋ ์ ์ปจํ
์ด๋-ํธ์คํธ ๊ฐ ํ๋๋งํฌ ์์ฑ ๋ถ๊ฐ
โ Docker ๋ด๋ถ์์ pnpm ์ ์ฌ์ฉํ ๋๋ ํ๋๋งํฌ ๋์ ๋ณต์ฌ(copy)
โ ์ฑ๋ฅ ์ ํ๋ ์์ผ๋ BuildKit ์บ์๋ก ๋ณด์
ํด๊ฒฐ: --mount=type=cache ์ฌ์ฉ (06ํธ ์ฐธ๊ณ )
2. ์ฌ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ์ง ๋ชปํ๋ ๊ตฌํ ๋๊ตฌ
์ผ๋ถ Electron ์ฑ, ๊ตฌํ webpack config, ํน์ Jest transform ์ด
์ฌ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ์ง ๋ชปํ๋ ๊ฒฝ์ฐ ๋ฐ์
ํด๊ฒฐ ๋ฐฉ๋ฒ (์ ํธ๋ ์):
1. public-hoist-pattern ์ผ๋ก ํด๋น ํจํค์ง ํธ์ด์คํ
2. nodeLinker=hoisted (npm ๋ฐฉ์์ผ๋ก ํด๋ฐฑ)
3. shamefully-hoist=true (์ตํ์ ์๋จ)
3. ์ผ๋ถ ํจํค์ง์ postinstall ์คํฌ๋ฆฝํธ ์คํ ์ฐจ์ด
npm ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ postinstall ์ ์คํํ์ง๋ง
pnpm ์ ๋ณด์์ ์ผ๋ถ ํจํค์ง์ ๋น๋ ์คํฌ๋ฆฝํธ๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ์น์ธ ํ์
ํด๊ฒฐ:
pnpm approve-builds # ํ ๋ฒ ์คํํ๋ฉด ~/.pnpm-state ์ ์น์ธ ๋ชฉ๋ก ์ ์ฅ
๋๋
# pnpm-workspace.yaml
onlyBuiltDependencies:
- esbuild
- sharp
4. Zero-Install ๋ฏธ์ง์
Yarn PnP ์ Zero-Install (node_modules ์์ด .yarn/cache ๋ฅผ git ์ ์ปค๋ฐ)
์ pnpm ์์ ์ง์ํ์ง ์์
pnpm ์ ๋์: pnpm install --offline ์ผ๋ก ์คํ ์ด ๊ธฐ๋ฐ ์คํ๋ผ์ธ ์ค์น
๐ ์ด์ ๋ฆฌ
๋ง์ด๊ทธ๋ ์ด์
7๋จ๊ณ ์ฒดํฌ๋ฆฌ์คํธ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Step 1: pnpm ์ค์น (corepack enable)
Step 2: pnpm import (lock ํ์ผ ๋ณํ)
Step 3: ๊ธฐ์กด node_modules / package-lock.json ์ญ์
Step 4: .npmrc ์ค์ (public-hoist-pattern)
Step 5: pnpm install + dev/build/test ๊ฒ์ฆ
Step 6: package.json ์ packageManager / engines ์ถ๊ฐ
Step 7: git commit (pnpm-lock.yaml ํฌํจ)
+์ถ๊ฐ: CI/CD, Docker ์
๋ฐ์ดํธ (๋ณ๋ PR ๊ถ์ฅ)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. pnpm import ๋ก ๋ณํํ pnpm-lock.yaml ์ด ์์ ํ ๋์ผํ ๋ฒ์ ์ ๋ณด์ฅํ์ง ์๋ ์ด์ ์, ์ด๋ฅผ ๊ฒ์ฆํ๋ ๋ฐฉ๋ฒ์?
โ
์ ๋ต: pnpm import ๋ ๊ธฐ์กด lock ํ์ผ์ ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํ์ง๋ง, pnpm ์ ์์กด์ฑ ํด๊ฒฐ ์๊ณ ๋ฆฌ์ฆ ์ด npm/Yarn ๊ณผ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ผ๋ถ ๊ฐ์ ์์กด์ฑ์ ๋ฒ์ ์ด ๋ฌ๋ผ์ง ์ ์๋ค. ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ๋ณํ ํ ๋ฐ๋์ pnpm dev, pnpm build, pnpm test ๋ฅผ ๋ชจ๋ ์คํํด์ ๋์์ ํ์ธํ๊ณ , ํนํ pnpm list --depth=3 ์ผ๋ก ํต์ฌ ํจํค์ง์ ๋ฒ์ ์ ํ์ธํ๋ ๊ฒ์ด๋ค.
๐ก ์์ธ ํด์ค:
- ์ง์ ์์กด์ฑ ๋ฒ์ ์ ๋๋ถ๋ถ ์ ์ง๋์ง๋ง, ๊ฐ์ ์์กด์ฑ(transitive)์ ๋ค๋ฅผ ์ ์์
- ํนํ ํผ์ด ์์กด์ฑ ํด์ ๋ฐฉ์์ด ๋ฌ๋ผ ์ผ๋ถ ํจํค์ง๊ฐ ๋ค๋ฅธ ๋ฒ์ ์ผ๋ก ์ค์น๋ ์ ์์
- ๊ฐ์ฅ ์์ ํ ๋ฐฉ๋ฒ:
package.json์ ์ง์ ์์กด์ฑ์ ๋ฒ์ ์ ๋ช ํํ๊ฒ ๊ณ ์ ํ๊ณ (e.g.,"react": "18.2.0"exact) ๋ณํ ํ ๊ฒ์ฆ - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "import ๋ ๋ฒ์ญ์ด์ง ๋ณต์ฌ๊ฐ ์๋๋ค โ ๋ฐ๋์ ๊ฒ์ฆ ํ ์คํธ๋ฅผ ๋๋ ค๋ผ."
Q2. ๋ง์ด๊ทธ๋ ์ด์
ํ ํฌํ
์์กด์ฑ ์๋ฌ (Cannot find module 'X') ๊ฐ ๋ฐ์ํ์ ๋, ์ด๋ฅผ ์์ ํ๋ ๋ ๊ฐ์ง ์ฌ๋ฐ๋ฅธ ์ ๊ทผ๋ฒ์?
โ
์ ๋ต: ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ ์ ๋ ๊ฐ์ง๋ค. ์ฒซ์งธ, ํด๋น ํจํค์ง๋ฅผ package.json ์ ๋ช
์์ ์ผ๋ก ์ถ๊ฐ (pnpm add X) ํ๋ ๊ฒ์ด๋ค โ ํฌํ
์์กด์ฑ์ ์ค์ ์์กด์ฑ์ผ๋ก ๊ฒฉ์์ํจ๋ค. ๋์งธ, pnpm why X ๋ก ์ถ์ฒ๋ฅผ ํ์ธํด์ ์ค์ ๋ก ํ์ ์๋ค๋ฉด ํด๋น import ๋ฌธ์ ์ ๊ฑฐ ํ๋ ๊ฒ์ด๋ค. shamefully-hoist=true ๋ก ์๋ฌ๋ฅผ ์จ๊ธฐ๋ ๊ฒ์ ๋ฌธ์ ๋ฅผ ๊ฐ์ถ๋ ๊ฒ์ด์ง ํด๊ฒฐ์ด ์๋๋ค.
๐ก ์์ธ ํด์ค:
- ํฌํ ์์กด์ฑ์ "npm ์์ ์ด ์ข๊ฒ ๋๋ ์ฝ๋ ํ์ง ๋ฌธ์ " โ pnpm ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ฐจ๋จํ ๊ฒ
pnpm add X๋ก ์ถ๊ฐ โ ์ดํ X ๊ฐ ์ง์ ์์กด์ฑ์ด ๋ผ์ ์์ shamefully-hoist๋ ์์๋ฐฉํธ์ด์ง ์ฝ๋ ํ์ง ํด๊ฒฐ์ด ์๋- ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "ํฌํ
์๋ฌ = pnpm ์ด ์ก์์ค ์ฝ๋ ๋น โ ๋๋ง์น์ง ๋ง๊ณ
pnpm add๋ก ๊ฐ์๋ผ."
Q3. ์์ฒ ์ด์ ํ ์คํธ ํ์: ์ค๋ฌด ๋๋ ๋ง (์์ฒ ์ ์ ํ)
์์ฒ ์ด๊ฐ ๋ง์ด๊ทธ๋ ์ด์ ํ CI ์์๋ง ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
Error: Cannot find module 'eslint'๋ก์ปฌ์์๋ ์ ๋๋๋ฐ GitHub Actions ์์๋ง ์ ๋๋ค.
๊ฐ๋ฅํ ์์ธ์ 2๊ฐ์ง ์ด์ ์ ์ํ๊ณ , ๊ฐ๊ฐ์ ํ์ธ ๋ฐฉ๋ฒ๊ณผ ํด๊ฒฐ์ฑ ์ ์ค๋ช ํ๋ผ.
โ
์ ๋ต: ์์ธ 1: ๋ก์ปฌ ~/.npmrc ์ public-hoist-pattern[]=*eslint* ๊ฐ ์์ง๋ง ํ๋ก์ ํธ .npmrc ์๋ ์๋ ๊ฒฝ์ฐ. ์์ธ 2: CI workflow ์์ pnpm/action-setup ์ด ์๊ฑฐ๋ cache: 'pnpm' ์ด ๋๋ฝ๋์ด ์บ์ ์์ด ์๋ก ์ค์นํ๋ฉด์ ๋์์ด ๋ฌ๋ผ์ง๋ ๊ฒฝ์ฐ. ์์ธ 3: workflow ์ ์ฌ์ ํ npm ci ๊ฐ ๋จ์์๋ ๊ฒฝ์ฐ.
๐ก ์์ธ ํด์ค:
- ์์ธ 1 ํ์ธ:
cat .npmrcvscat ~/.npmrc๋น๊ต / ํด๊ฒฐ: ํ๋ก์ ํธ.npmrc์ ํจํด ์ถ๊ฐ ํ ์ปค๋ฐ - ์์ธ 2 ํ์ธ: workflow ์
pnpm/action-setup@v4์คํ ์ด ์๋์ง ํ์ธ / ํด๊ฒฐ: setup ์คํ ์ถ๊ฐ - ์์ธ 3 ํ์ธ: workflow ์
npm ci๊ฐ ์๋์ง grep / ํด๊ฒฐ:pnpm install --frozen-lockfile์ผ๋ก ๊ต์ฒด - ํต์ฌ ์์น: "๋ก์ปฌ OK, CI ์คํจ = ํ๊ฒฝ ์ค์ ์ด ๋ค๋ฅธ ๊ฒ์ด๋ค โ ํ๋ก์ ํธ ๋ฃจํธ ํ์ผ๋ก ํต์ผํ๋ผ."
- ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "์ค์ ์ ํ ๋๋ ํ ๋ฆฌ๊ฐ ์๋ ํ๋ก์ ํธ ๋ฃจํธ
.npmrc์ โ ๊ทธ๋์ผ CI ๋ ๊ฐ๋ค."
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
๋๋์ด pnpm ๊ฐ์ด๋ 7ํธ ๋ง์ง๋ง์ด๋ค.
์์งํ ๋ง์ด๊ทธ๋ ์ด์ ์ฑํฐ๊ฐ ์ฒ์์ ๋ณ๊ฑฐ ์์ ๊ฒ ๊ฐ์๋๋ฐ, ๋ง์ ์ ๋ฆฌํ๋ค ๋ณด๋ ํจ์ ์ด ์๊ฐ๋ณด๋ค ๋ง์๋ค. ํฌํ ์์กด์ฑ ์๋ฌ, ๋ก์ปฌ-CI ํ๊ฒฝ ์ฐจ์ด, Husky hooks ์ฌ์ค์ , Prisma postinstall... ํ๋ํ๋๋ ๋ณ๊ฒ ์๋์ง๋ง ๋์์ ์ฌ๋ฌ ๊ฐ๊ฐ ํฐ์ง๋ฉด ์ ๋ง ํจ๋์ด ์ฌ ์ ์๊ฒ ๋ค ์ถ์๋ค.
์ํธ ๋ฆฌ๋ ๋์ด "๊ธํ๊ฒ ํ๋ฉด ๊ผญ ๋ญ๊ฐ ๋น ์ง๋ค"๊ณ ํ์ ๋ง์์ด ์ด์ ์์ผ ์ง์ง๋ก ์ดํด๋๋ค. ์ฒดํฌ๋ฆฌ์คํธ ํ๋์ฉ ๋ฐ์๊ฐ๋ ๊ฒ ๊ฒฐ๊ตญ ๊ฐ์ฅ ๋น ๋ฅธ ๊ธธ์ด๋ค. ๊ธํ๊ฒ ๋ฌ๋ฆฌ๋ค๊ฐ ๋น ์ง ๊ฑฐ ์ฐพ์ผ๋ฌ ๋๋์๊ฐ๋ ๊ฒ๋ณด๋ค.
pnpm ๊ฐ์ด๋ 7ํธ์ ์ฒ์๋ถํฐ ๋๊น์ง ๋ค ์ผ๋ค. ๋ฉํ ๋ชจ๋ธ, node_modules ๊ตฌ์กฐ, CLI, workspace, Catalogs, CI/Docker, ๊ทธ๋ฆฌ๊ณ ๋ง์ด๊ทธ๋ ์ด์ ๊น์ง. ์ฒ์ pnpm ์ ์์์ ๋ "๊ทธ๋ฅ npm ์ด๋ ๋น์ทํ ๊ฑฐ ์๋?" ๋ผ๊ณ ์๊ฐํ๋๋ฐ, ์ด์ pnpm ์ด ์ผ๋ง๋ ๋ค๋ฅด๊ณ ์ผ๋ง๋ ์ ์ค๊ณ๋ ๋๊ตฌ์ธ์ง ์ ๋๋ก ์๊ฒ ๋๋ค.
๐ก ์ค๋์ ๊ตํ: "๋ง์ด๊ทธ๋ ์ด์ ์ ๊ฒฐ์น์ ์ด ์๋๋ผ ์ถ๋ฐ์ ์ด๋ค. ์์๋ฅผ ์งํค๊ณ , ๊ฒ์ฆํ๊ณ , ํ์๊ฒ ๊ณต์ ํ๋ฉด โ ๊ทธ๋๋ถํฐ pnpm ์ ์ง์ง ์ด์ ์ ๋๋ฆด ์ ์๋ค."
๋ด์ผ๋ถํฐ๋ ์ค์ ํ๋ก์ ํธ์ pnpm ์ ์ ์ฉํด๋ณผ ์ฐจ๋ก๋ค. ์ด๋ก ์ ์ถฉ๋ถํ ์์๋ค. ์ด์ ์ค์ ์ด๋ค. ์ํธ ๋ฆฌ๋ ๋์ด ์ ํ๋ค๊ณ ์คํฐ์ปค ํ๋ ์ฃผ์ จ๋ค. ์ค๋์ ๊ธฐ๋ถ ์ข๊ฒ ์ง ๊ฐ์ ๋ง์๋ ๊ฑฐ ๋จน์ด์ผ์ง.