와.. 이걸 내가 해냄ㅠㅠ
깃허브에서 서비스와 스토리북을 동시에 배포하고자 했다.
처음에는 깃허브 액션(GitHub Actions) 스크립트를 두 개로 나눠서 각각 진행하려고 했지만...
결론: 한 개의 스크립트에서 모든 배포를 진행해야 한다.
GitHub Pages의 기본 URL은 아래와 같은 구조를 가진다:
https://<username>.github.io/<repository-name>/
여기서 나는 다음과 같은 요구사항이 있었다:
/
하위에는 서비스를 배포/storybook
하위에는 스토리북을 배포이렇게 설정하려면 단순히 두 개의 배포 스크립트를 작성한다고 끝나는 게 아니다.
GitHub Pages와 GitHub Actions의 특성을 이해하고, 배포 과정에서 파일 충돌과 404 문제를 해결해야 한다.
처음에는 배포 스크립트를 두 개로 나눠서 각각 React 서비스와 Storybook을 배포했다.
하지만 두 작업이 같은 gh-pages
브랜치를 덮어쓰기 때문에, 마지막에 실행된 배포만 살아남았다.
GitHub Actions에서 keep_files: true
옵션을 사용하여 기존 파일을 유지하면서, 서비스와 스토리북을 각각 다른 디렉토리에 배포하도록 설정했다.
React는 SPA(Single Page Application)이기 때문에, 브라우저 새로고침 시 index.html
로 리다이렉트되지 않으면 404가 발생한다.
GitHub Pages는 404 요청을 404.html
로 처리할 수 있다. 이를 이용해 모든 잘못된 요청을 React의 index.html
로 리다이렉트하거나, /storybook
요청은 Storybook으로 리다이렉트하도록 스크립트를 작성했다.
storybook과 서비스를 배포하기 전에 공통적으로 진행하는 부분이다
베이스로 하는 브랜치 코드를 가져와 의존성을 설치하고 캐싱을 진행해 최적화한다.
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install dependencies
run: npm ci
github의 환경변수 설정을 하고 시스템에서 사용할 환경변수에 넣어준다. (환경변수를 안쓰면 건너뛰어도 된다)
- name: Setup environment variables
run: |
echo "REACT_APP_BASE_URL=${{ secrets.REACT_APP_BASE_URL }}" >> .env
PUBLIC_URL=$(echo $GITHUB_REPOSITORY | sed -r 's/^.+\/(.+)$/\/\1\//')
echo PUBLIC_URL=$PUBLIC_URL > .env
각 애플리케이션을 빌드하여 dist
디렉토리와 storybook-static
디렉토리에 결과물을 생성한다.
- name: Build React App
run: npm run build
- name: Build Storybook
run: npm run build-storybook
GitHub Pages에서 React 앱과 Storybook 간 경로 충돌 문제를 해결하기 위해 404.html
에 스크립트를 추가한다. myrok_client
는 나의 레포지토리 이름이기 때문에 이곳에 본인의 레포 이름을 넣는다.
- name: Create 404.html for GitHub Pages
run: |
cp dist/index.html dist/404.html
echo '
<script>
if (location.pathname.includes("/storybook")) {
location.href = "/myrok_client/storybook/";
}
</script>
' >> dist/404.html
React 앱의 빌드 결과물을 GitHub Pages에 업로드한다. 이때 publish_dir
는 어떤 dir에 있는 파일을 배포할건지이다. 이건 루트경로에 배포된다.keep_files: true
로 설정하여 Storybook 파일을 덮어쓰지 않도록 보장하자.
- name: Upload to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
destination_dir: .
keep_files: true
그리고 Storybook의 빌드 결과물을 GitHub Pages에 업로드한다.
- name: Upload Storybook to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./storybook-static
destination_dir: storybook
keep_files: true
이러면 경로별로 여러 서비스 배포할 수 있다!!
당연하지만 주의할 점으론 서비스의 페이지 경로가 스토리북이 있는 경로와 겹치지 않도록한다.
위 코드를 잘 조합한 결과이다..! 진짜진짜 이거 성공시킨다고 커밋을 80개는 넘게 했다.
여러분은 고생하지 마시길… 아래 링크는 내가 배포 성공한 결과물이다.
다만 이거 학교 플젝이라 혼자 프론트 다 개발하느라 반응형? 개나줘버려! 버그? 흐린 눈 해! 라는 마인드로 개발해서 결과물은 처참하다ㅋㅋㅋ
그냥 배포가 된다는 것만.. 확인하셔요
본 서비스: https://myrokkk.github.io/myrok_client/
스토리북 : https://myrokkk.github.io/myrok_client/storybook/
name: deploy frontend and storybook
on:
push:
branches: ['develop']
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Setup Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Setup environment variables
run: |
echo "REACT_APP_BASE_URL=${{ secrets.REACT_APP_BASE_URL }}" >> .env
PUBLIC_URL=$(echo $GITHUB_REPOSITORY | sed -r 's/^.+\/(.+)$/\/\1\//')
echo PUBLIC_URL=$PUBLIC_URL > .env
- name: Install dependencies
run: npm ci
- name: Build Frontend
run: npm run build
- name: Create 404.html for GitHub Pages
run: |
cp dist/index.html dist/404.html
echo '
<script>
if (location.pathname.includes("/storybook")) {
location.href = "/myrok_client/storybook/";
}
</script>
' >> dist/404.html
- name: Upload Frontend to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
destination_dir: .
keep_files: true
- name: Build Storybook
run: npm run build-storybook
- name: Update Storybook Base Path
run: |
echo "Updating Storybook base path for /storybook"
sed -i 's|href="/|href="/storybook/|g' storybook-static/index.html
sed -i 's|src="/|src="/storybook/|g' storybook-static/index.html
- name: Upload Storybook to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./storybook-static
destination_dir: storybook
keep_files: true