본문 바로가기
카테고리 없음

pnpm version patch 삽질하기

by LucetTin5 2024. 8. 9.

배경

모듈을 만들어서 배포를 자동화하는 과정에서 겪은 이슈를 적어봅니다. 이 글은 pnpm으로 구성한 모노레포 환경에서 발생한 문제와 그 해결 과정을 다룹니다.

프로젝트 구조

  • pnpm으로 구성한 모노레포
  • packages 하위에 사용하고자 하는 커스텀 모듈 위치
  • mainpush 발생 시 GitHub Actions를 통해 packages/package-AGitHub Packages로 배포

문제 상황

npm 모듈의 버전은 달라야 하기에 package.json의 version을 변경하고 배포를 진행해야 합니다.

매번 PR에서 이 package.json의 버전을 직접 바꾸는 것보다는 이를 자동화하는 것을 목표로 했고, 액션의 배포 단계에서 마이너 패치 버전을 자동으로 올리도록 설정하기로 했습니다.

에러 발생

packages/package-A 디렉토리에서 다음 명령어가 실행될 때 에러가 발생

pnpm version patch

 

에러 메시지:

npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type "workspace:": workspace:*

 

원인 분석

모노레포의 구성에서 기인하는 문제였습니다. package/package-A는 example(개발용 react 환경, 예시로도 이용) 패키지의 package.json에서 다음과 같이 참조되고 있었습니다. version 스크립트가 워크스페이스의 모든 패키지의 의존성을 업데이트하려 하지만, 워크스페이스 프로토콜로 선언된 부분에서 에러가 발생합니다.

"dependencies": {
  "package-A": "workspace:*"
}

 

workspace:*로 지정되어, 이는 package-A가 어떤 버전이어도 현재 워크스페이스의 버전을 사용하겠다는 의미입니다.

해결 방법

npm 공식 문서의 npm version 부분을 참조하여 workspaces-update 옵션을 사용했습니다. 이 옵션은 기본값은 true로, version 스크립트의 실행 시 워크스페이스 전체의 의존성을 확인하여 함께 업데이트합니다.

다음의 명령어를 사용하여 배포 시 package-A의 버전만을 업데이트하고 워크스페이스 전체의 의존성 검사를 건너뛸 수 있었습니다.

pnpm version patch --workspaces-update=false

 

여기서 npm-version을 참조한 이유는 pnpm version patch 시 발생한 에러 메시지가 npm으로 표시되었던 점과, pnpm docs에는 version에 대한 안내가 없다는 점 때문이었습니다.

최종 스크립트

해당 명령을 적용하여 완성된 publish workflow의 bash script는 다음과 같습니다.

 

# package-A의 현재 버전을 확인합니다.
current_version=$(node -p "require('./package.json').version")
echo "Current local version: $current_version"

# package-A의 배포된 버전을 확인하고, 오류가 발생하면 그 메시지는 무시하고 else로 진행합니다.
if published_version=$(pnpm view . version 2>/dev/null); then
  # 배포된 최신 버전을 확인합니다.
  echo "Latest published version: $published_version"

  # 로컬 버전과 배포된 버전을 비교하여, 배포된 버전이 더 높으면 로컬 버전을 배포 버전으로 업데이트 후 패치를 진행합니다.
  if [ "$(printf '%s\n' "$current_version" "$published_version" | sort -V | tail -n1)" = "$published_version" ]; then
    echo "Published version is newer. Updating local version and then patching."

    # 로컬 버전을 배포 버전으로 업데이트합니다.
    pnpm version $published_version --workspaces-update=false --no-git-tag-version --allow-same-version

    # 패치를 진행합니다.
    new_version=$(pnpm version patch --workspaces-update=false --no-git-tag-version)

    echo "Updated to new version: $new_version"

    git add package.json
    git commit -m "chore: Bump version to $new_version"
    git push
  # 로컬 버전과 배포 버전이 같으면 패치를 진행합니다.
  elif [ "$current_version" = "$published_version" ]; then
    echo "Local version is equal to published version. Patching."
    new_version=$(pnpm version patch --workspaces-update=false --no-git-tag-version)
    echo "New version: $new_version"
    git add package.json
    git commit -m "chore: Bump version to $new_version"
    git push
  # 로컬 버전이 더 높은 경우 그대로 사용합니다.
  else
    echo "Local version is newer. Preparing to publish current version."
    new_version=$current_version
  fi
else
  # 배포된 버전이 없는 경우, 로컬 버전을 그대로 사용합니다.
  echo "Package not published yet. Preparing for first publish."
  new_version=$current_version
fi

# 배포를 진행합니다.
echo "Publishing version $new_version"
pnpm publish --no-git-checks

 

결론

모노레포 환경에서 pnpm을 사용할 때, 패키지 버전 관리와 자동 배포 설정에 주의가 필요합니다. workspaces-update 옵션을 적절히 활용하면 원하는 패키지만 버전 업데이트할 수 있습니다. 이 경험을 통해 모노레포 구조에서 모듈의 버전 관리를 어떻게 하면 좋을 지 알게 되었습니다.


참조

https://docs.npmjs.com/cli/v10/commands/npm-version#workspaces-update

 

npm-version | npm Docs

Bump a package version

docs.npmjs.com

 

https://pnpm.io/workspaces#referencing-workspace-packages-through-aliases

 

Workspace | pnpm

pnpm has built-in support for monorepositories (AKA multi-package repositories,

pnpm.io