노트

pnpm 워크스페이스

pnpm Workspaces

프런트엔드#tooling · 연결된 개념 4개

쉽게 말하면

pnpm 워크스페이스는 한 집에 사는 형제가 장난감을 가게에서 새로 사지 않고 서로의 방에서 바로 빌려 쓰는 것과 같아요. 저장소 하나의 여러 패키지가 레지스트리 대신 로컬 폴더 링크로 서로를 참조해요.

비유가 깨지는 곳 빌려 쓰기만 하는 건 아니에요. workspace:로 적으면 밖에서 같은 이름을 받는 실수를 막고, publish 때는 실제 버전으로 바뀌어요. 바뀐 것만 다시 실행하는 캐시는 turborepo 같은 도구 몫이에요.

pnpm 워크스페이스는 저장소 하나에 여러 패키지를 두고 한 번에 설치·연결·실행하는 기능이다. 루트의 pnpm-workspace.yaml에 패키지 위치를 적으면, 패키지끼리 npm 레지스트리에서 받는 대신 로컬 폴더 링크로 서로를 참조한다. 모노레포를 시작하는 가장 기본 단계다.

# pnpm-workspace.yaml
packages:
  - apps/*
  - packages/*

workspace: 프로토콜

{
  "dependencies": {
    "@acme/ui": "workspace:*"
  }
}
  • workspace:로 적으면 pnpm은 반드시 워크스페이스 안의 패키지로만 해석한다. 없으면 레지스트리에서 받지 않고 설치가 실패하므로, 실수로 같은 이름의 외부 패키지를 받는 일이 없다
  • 의존 패키지가 로컬 폴더 링크이므로 공유 UI·설정 패키지를 고치면 레지스트리 배포 없이 앱에 반영된다(빌드 산출물을 내보내는 패키지라면 그 패키지 빌드는 필요하다)
  • pnpm publish·pnpm pack 때는 실제 버전으로 바뀐다. 버전이 1.5.0이면 workspace:* → 1.5.0, workspace:^ → ^1.5.0, workspace:~ → ~1.5.0

골라서 실행하기: --filter

pnpm --filter @acme/web dev        # 한 패키지만
pnpm --filter "./apps/*" build     # 경로 glob
pnpm --filter "@acme/ui..." test   # ui와 ui가 의존하는 패키지들
pnpm --filter "...@acme/ui" test   # ui와 ui에 의존하는 패키지들(영향 범위)
pnpm --filter "@acme/ui^..." test  # ui가 의존하는 패키지들만(ui 제외)
pnpm --filter "...[origin/main]" test  # origin/main 대비 바뀐 패키지와 그에 의존하는 것
pnpm -r build                      # 모든 패키지(의존 순서대로)

...이 이름 뒤에 붙으면 의존 대상, 앞에 붙으면 의존하는 쪽까지 넓히고, ^를 함께 쓰면 자기 자신은 빠진다. pnpm -r의 run·exec·test는 기본으로 의존 대상을 먼저 실행하며, 워크스페이스 루트 패키지는 대상에서 빠진다. 공유 패키지를 고친 뒤 영향받는 앱만 테스트할 때는 ... 필터가 유용하다.

함께 알아 둘 것

  • 잠금 파일(pnpm-lock.yaml)은 기본 설정(sharedWorkspaceLockfile: true)에서 루트에 하나만 생긴다
  • 루트 package.json에 공통 개발 도구를 추가할 때는 pnpm add -D eslint -w처럼 -w(--ignore-workspace-root-check)를 붙여야 한다. 없으면 실수 방지를 위해 실패한다
  • 워크스페이스는 설치·연결과 의존 순서대로 실행하기까지 맡는다. 작업 결과 캐시와 바뀐 것만 다시 실행하는 최적화는 Turborepo나 Nx 같은 빌드 시스템이 맡는다
  • pnpm의 저장 방식과 유령 의존성(Phantom Dependency) 차단은 npm과 pnpm을 본다

출처: pnpm — Workspace · pnpm — Workspace protocol · pnpm — Publishing workspace packages · pnpm — Filtering · pnpm — pnpm -r · pnpm — pnpm add: --ignore-workspace-root-check

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 번들 크기 줄이기

    번들 다이어트는 사용자가 내려받는 JavaScript 양을 측정하고 줄이는 작업이다. 같은 용량이라도 JS는 이미지보다 비싸다. 이미지는 다운로드와 디코딩만 하면 되지만, JS는 다운로드·파싱·컴파일·실행을 모두 거친다.

  • Pages Router에서 App Router로

    App Router는 Next.js 13에서 도입된 app/ 디렉터리 기반 라우터로, 서버 컴포넌트·중첩 레이아웃(Nested Layouts)·스트리밍을 기본으로 한다. pages/ 기반의 Pages Router에서 옮길 때 바뀌는 생각을 정리한다.

  • CPU 아키텍처와 네이티브 모듈

    CPU 아키텍처는 CPU가 실행하는 명령어 집합(Instruction Set Architecture, ISA)의 종류다. 서버와 PC에서는 x86-64와 ARM64 두 계열이 주로 쓰이고, 한 계열용으로 컴파일된 기계어는 다른 계열 CPU에서 실행되지 않는다. Node.js 프로젝트에서는 이 차이가 네이티브 모듈에서 드러난다.

  • Dockerfile: 레이어 캐시와 멀티 스테이지

    Dockerfile은 이미지를 만드는 명령을 순서대로 적은 파일이다. 파일시스템을 바꾸는 명령(RUN·COPY·ADD)이 각각 레이어(layer)가 되고, 바뀌지 않은 레이어는 캐시를 재사용한다. 그래서 자주 바뀌는 것을 뒤에 두는 순서가 빌드 속도를 좌우한다.

  • 여러 저장소 합치기

    따로 관리하던 Git 저장소를 하나로 합칠 때, 히스토리를 버리지 않고 옮기는 방법이 두 가지 있다. 저장소 루트끼리 그대로 합치거나(unrelated histories 머지), 한쪽을 다른 쪽의 하위 폴더로 넣는다(subtree). 모노레포로 옮길 때 자주 쓴다.

보기 옵션