[달달쇼핑] 인생 첫 깃허브 액션 경험기 feat. Storybook, yarn berry

한낱·2024년 1월 21일
1

달달쇼핑

목록 보기
3/8

서론

다담다 프로젝트에서 유일한 프론트엔드로 활동하다가 처음 프론트엔드 팀으로 협업해보게 되었다. 의욕 넘치던 처음 환경 세팅을 좀 길게 가져가면서 할 수 있는 자동화는 모두 해보고자 했다. 오늘은 그 과정에서 가장 오랜 시간을 소요했던 스토리북 배포 과정에 대해서 다뤄보고자 한다.

패키지 매니저

yarn을 사용한 이유

npm으로 진행했던 지난 프로젝트에서는 특정 시점 이후부터는 peer-dependency로 인한 문제가 발생했다.

peer dependency 이슈

npm에서는 설치하려는 라이브러리가 다른 라이브러리에 의존할 때 이를 명시하기 위해 peer-dependency를 사용한다.

예를 들어, A라는 라이브러리를 설치할 때 해당 라이브러리가 B 라이브러리에 의존하고 있다면 이를 함께 설치하며 peer-dependency를 표기한다. 만약, 이 때 B 라이브러리가 이미 설치되어 있는 상태이고, 지금 설치되는 버전과 상이하다면 문제가 발생한다.

npm의 과거 버전에서는 자동으로 설치해주었다고 하는데 요즘 사용되는 npm 버전에서는 peer dependency가 일치하지 않으면 설치가 되지 않는다.

해결하기 위해서는 설치 명령어에 --force--legacy-peer-deps를 포함해야 한다. (전자는 충돌의 우회를, 후자는 충돌의 무시를 의미한다.)

이러한 이유로 지난 프로젝트에서는 unable to resolve dependency tree가 발생한 특정 시점 이후부터는 --legacy-peer-deps를 함께 적어 설치하였다.

엄청난 노력은 아니지만, 매번 legacy-peer-deps를 입력하다보면 yarn은 이런 문제 안 생긴다던데...? 하는 생각이 절로 들었다.

스토리북 이슈

그렇게 yarn을 시작하고 만족도 높은 세팅 생활을 이어가던 어느날... 스토리북도 연결하게 되었다.

스토리북 공식문서 를 따라 install도 하고, yarn storybook 키워드가 잘 동작하는 것도 확인하였다.

하지만, 꼭 스토리북을 설치한 직후는 스토리북이 동작하고 이후부터는 오류가 나는 이상한 오류가 발생하였다. 매번 삭제하고 재설치해야한다면 --legacy-peer-deps를 입력하는 것보다 더 귀찮은 일이 될 것이라고 예상하고, 해결책을 찾아보았다.

발생했던 에러는 다음과 같았고,

var stringWidth = require('string-width')
                  ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/phil/Projects/nextmission/node_modules/string-width/index.js from /Users/phil/Projects/nextmission/node_modules/wide-align/align.js not supported.
Instead change the require of index.js in /Users/phil/Projects/FPV/nextmission/node_modules/wide-align/align.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/wide-align/align.js:2:19)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/gauge/render-template.js:2:13)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/gauge/plumbing.js:3:22)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/gauge/index.js:2:16)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/npmlog/log.js:3:13)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/@storybook/node-logger/dist/index.js:1:1141)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/@storybook/cli/dist/generate.js:1:1014)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/@storybook/cli/bin/index.js:9:1)
    at Object.<anonymous> (/Users/phil/Projects/nextmission/node_modules/storybook/index.js:3:1) {
  code: 'ERR_REQUIRE_ESM'
}

이와 관련된 github issue에서 해결책을 찾을 수 있었다.

간략하게 요약하자면, string-width에 대한 dependency가 충돌을 일으켜 변경되어야 하지만, 이전 블로그 글을 참고해보면 알 수 있듯이 yarn은 yarn berry로 버전을 변경하면서 업데이트를 포기했다.

해당 이슈에서 논쟁을 벌이던 대다수의 외국인 개발자들이 deprecated된 yarn을 버리고 yarn berry로 바꾸면 자연히 이 문제가 해결된다고 말했고, 이에 넘어가버린 나는 yarn berry라는 금단의 사과를 먹게 되었다...

처음이지만 눈치로 때려맞추는 github-action

처음 yarn berry를 사용했을 때에는 아주 좋았다. node_modules를 삭제했기 때문에 종속성 꼬였다며 패키지 전체를 삭제/재설치하는 과정을 할 필요가 없었고, 어쩌다 시도해볼 때에도 node_modules의 삭제/재설치보다 속도가 월등히 빨랐다.

스토리북과 깃허브 액션을 연결하는 것은 공식 문서에도 나와있고, 블로그 글도 많아서 금방 하리라 생각했다. 하지만...

새로운 기술을 도입하면 인생이 고달파지는 이유

: 자료가 없음... 정말 없음...

서치 결과 npm으로, yarn으로 스토리북을 깃허브에 배포한 코드는 아주 많았다. 그리고, 당연히 그 코드를 날먹하려던 나는 아주 실패했고, 약 3일은 고생하였다.

기존 프로젝트를 yarn berry로 버전을 올리면서 package.json에 패키지 매니저의 버전이 명시되어버렸다.

이 부분 때문에 인터넷에 있는 코드를 그대로 루팡해오면 설치되어야 하는 패키지 매니저와 버전이 상이하기 때문에 action에 오류가 발생하였다.

(당시 workflow 파일)

name: Storybook Deployment
run-name: ${{ github.actor }}의 스토리북 배포
on:
  pull_request:
    branches:
      - develop
jobs:
  storybook:
    runs-on: ubuntu-20.04
    outputs:
      status: ${{ job.status }}
    steps:
      - name: checkout repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: cache dependencies
        id: cache
        uses: actions/cache@v3
        with:
          path: '**/node_modules'
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-storybook

      - name: depedency install
        run: yarn install --immutable --immutable-cache

      - name: publish to chromatic
        id: chromatic
        uses: chromaui/action@v1
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: comment PR
        uses: thollander/actions-comment-pull-request@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          message: '🚀storybook: ${{ steps.chromatic.outputs.storybookUrl }}'

(당시 오류 메시지)

Run yarn install --immutable --immutable-cache
error This project's package.json defines "packageManager": "yarn@4.0.2". However the current global version of Yarn is 1.22.21.

Presence of the "packageManager" field indicates that the project is meant to be used with Corepack, a tool included by default with all official Node.js distributions starting from 16.9 and 14.19.
Corepack must currently be enabled by running corepack enable in your terminal. For more information, check out https://yarnpkg.com/corepack.
Error: Process completed with exit code 1.

이 오류를 마주치고 깃허브 액션 한 번도 직접 짜본 적 없던 터라 스토리북과 깃허브 자동 배포 연결은 포기해야겠다 생각했다.

과정

0. 코드 간략하게 하기

다른 블로그들과 스토리북 공식 문서를 살펴보니 사람마다 yml 파일이 조금씩 달랐다. 무지랭이의 혼란을 최대한 줄여보기 위해 공통된 코드를 제외하곤 지운 상태에서 시도해 보았다.

1. set version 추가하기

action에서 알려주는 에러 메시지를 잘 읽어보면 패키지 매니저의 버전이 문제임을 알 수 있다. 이를 변경해보기 위해 프로젝트에서 yarn berry로 버전을 업데이트 하기 위해 사용했던 cli 명령어를 추가해보았다.

- name: Use Yarn version
        run: yarn set version 4.0.2

그리고 당연히 실패했다.

2. corepack enable

왜 아직도 yarn 버전이 변경되지 않았지? 라고 생각했는데, 기억을 더듬어보니 yarn berry로 버전을 올릴 때, corepack이라는 것을 사용했던 것을 기억해냈다.

기존에는 npm을 통해 yarn을 설치했었지만, 요즘은 공식문서에서 corepack을 통한 설치를 권장한다.
: corepack은 node js 16 버전부터 포함된 기능으로, yarn이나 pnpm같은 패키지 매니저를 프로젝트 별로 지정하여 사용할 수 있도록 해준다.

corepack enable의 활성화가 빠진 것이 문제가 되었나 생각하여

- name: Enable Corepack
        run: yarn corepack enable

을 추가해보았고, 또 실패했다.

3. node js 버전 명시

corepack은 위에서 적은 것처럼 node js 특정 버전의 실험적인 기능이다. 따라서, 버전에 따라 corepack enable이 불가능하다.

그래서 이 코드를 추가했고,

- uses: actions/setup-node@v4
        with:
          node-version: 20

또 실패했다.

4. node js 세팅의 위치

점점 오기가 생겨 구글링하던 도중 나와 유사한 문제를 겪는 사람의 이슈를 발견했다.

This is not ideal, because actions/checkout it designed for carrying out git commands, so you can't be sure that node is present, or that it has the correct version you are specifying in the next step with Node 16 at least required for corepack. Instead I have managed to workaround this issue by running two steps:
This will setup Node to version 20, run corepack enable, then setup the cache

	- uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: corepack enable
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: yarn
      - run: yarn install --immutable

위 답글에 따르면 actions나 checkout은 git 명령을 실행하는 데에 집중하기 때문에, node가 설치되어있는지, 올바른 버전을 가지고 있는지 확신할 수 없다고 한다.

하지만, corepack을 사용하기 위해서는 16버전 이상의 node가 필요한 상황이기 때문에 이를 해결하기 위한 꼼수로 위와 같은 코드를 알려주었다.

그리고 이 코드를 적용하니 오류 메시지가 바뀌었다!

5. secret key

이때부터는 chromatic에 publish하는 부분에서 오류가 발생하기 시작했다.

분명히 github secret에 잘 담아두었고, local에서 chromatic build는 정상적으로 동작하며, 블로그 코드들과 네이밍도 똑같이 해두었는데 뭐가 문제였을까?

이 부분에서 도저히 혼자 해결할 수 없어 살며시 팀 백엔드분께 도움을 요청했다.

감사하게도, 가장 간략한 형태인 chromatic에서 제공하는 yml 파일을 찾아주시면서 해당 코드에서부터 점점 확장해나가보라고 제안을 주셨다.

이 코드를 뜯어보면서 한 가지 놀라운 점은 github secret을 이용하지 않고, token을 직접적으로 적어둔 것이었다.

AWS와 같은 서비스는 실수로 github에 업로드하면 악의적인 사람들이 이를 이용하여 타 서비스에 사용하면서 과금이 발생한다...식의 괴담을 너무 많이 들어 본능적으로 chromatic token을 깃허브에 업로드하지 않으려 했던 것 같다.

chromatic은 유료로 서비스를 이용할 수도 있지만, AWS처럼 쓰는 만큼 돈을 내는 것이 아니라 필요할 때 업그레이드하는 서비스이기 때문에 과금이 날 걱정이 없음을 깨달았다. 물론, 다른 사람들이 내 chromatic에 접근할 수 있게 되면서 변경을 일으킬 위험도 있겠지(만 공식에서 이렇게 쓰는데 누가 나에게 돌을 던지겠나...!)

이 마인드로 코드를 변경하였고, 성공했다.

원인 추측

pr 메시지로 배포된 스토리북 링크를 남겨주는 자동화를 시도하던 중 secret key가 동작하지 않은 이유를 추측해볼 수 있었다. (해당 문제를 마주한 사람을 본인 이외에 보지 못해서 정확하진 않으나)

위 action은 개인 레파지토리에서 동작하는 것이 아니라, organization의 레파지토리를 fork해서 작업한 후 upstream에 합치려할 때 일어난다. 이처럼 PR과 관련된 동작이 이루어질 때, 나를 신뢰할 수 없다고 판단하여 PR 메시지를 자동으로 적을 수 없게 깃허브 자체에 설정이 되어있다.

동일한 이유로 이전 다담다 프로젝트에서도 백엔드 팀원이 jacoco를 통해 테스트 결과를 자동화하려다 실패했었다. 당시 팀원은 멋지게도 pr을 두 번 날리는 방법으로 해결했다.

이를 보며 신뢰할 수 없는 유저(나)에 대해 pr 메시지의 작성을 못하게 막는 것과 동일한 맥락으로 secret key에 대한 접근도 차단해놓은 것이 아닐까 추측해보았다.

결론

이러한 과정을 거쳐 완성된 workflow 파일은 다음과 같다.

name: Storybook Deployment
run-name: ${{ github.actor }}의 스토리북 배포
on:
  pull_request:
    branches:
      - develop
jobs:
  storybook:
    runs-on: ubuntu-latest
    outputs:
      status: ${{ job.status }}
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: corepack enable
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: yarn
      - run: yarn
      - uses: chromaui/action@v1
        with:
          projectToken: 본인 토큰 입력하기!
          token: ${{ secrets.GITHUB_TOKEN }}

포스팅의 길이로 짐작할 수 있겠지만 이를 가능하게 하는 데에 아주 고생을 많이 했다.

정말 많이 했다...

이후에 yarn으로 스토리북을 깔고 github에 자동 배포를 연결해놓을 누군가에게는 이 글이 도움이 되었으면 좋겠다.

ps) 위 코드는 정상적으로 배포가 일어나는 대신에 속도가 아주 느립니다. 아마 최대한 간략화된 코드를 참고하면서 캐시에 대한 내용을 제거해서인 것 같습니다. 참고하실 분은 캐시를 추가해서 사용하세요...

profile
제일 재밌는 개발 블로그(희망 사항)

0개의 댓글

관련 채용 정보