GitHub Actions로 프론트엔드 CI 자동화 구축하기 (Setting Up Frontend CI Automation with GitHub Actions)

2025. 11. 14. 13:00Web

반응형

github action ci

 

GitHub Actions로 프론트엔드 CI 자동화 구축하기 (Setting Up Frontend CI Automation with GitHub Actions)

프론트엔드 코드가 main에 머지되기 전에 자동으로 빌드, 테스트, 린트를 거치도록 만드는 CI 파이프라인 구축 과정을 정리했습니다.

This post walks through how to build a CI pipeline with GitHub Actions so your frontend code is automatically linted, tested, and built before being merged into main.

왜 프론트엔드에도 CI가 필요할까? (Why Do We Need CI for Frontend?)

작은 사이드 프로젝트를 할 때는 코드가 깨져도 금방 고칠 수 있지만, 팀 단위로 프론트엔드를 개발하다 보면 이야기가 완전히 달라집니다. 누군가가 타입을 잘못 맞추거나, 린트 규칙을 무시하거나, 빌드가 실패하는 코드를 푸시해버리면 팀 전체의 개발 흐름이 끊기기 쉽습니다.

When you’re working alone on a tiny side project, a broken build is usually not a big deal. But in a team-based frontend project, a single wrong type, a lint violation, or a build error can easily break the flow for everyone.

그래서 등장하는 것이 CI(Continuous Integration, 지속적 통합)입니다. CI는 “코드가 메인 브랜치에 합류하기 전에 한 번 더 자동으로 검문하는 시스템”이라고 생각하면 이해하기 쉽습니다. 사람 대신 자동화가 빌드, 테스트, 린트를 돌려보고 문제가 있으면 바로 빨간불을 켜주는 역할을 하죠.

That’s where CI (Continuous Integration) comes in. You can think of CI as an automated gatekeeper that runs builds, tests, and lint checks before your code is allowed into the main branch. Instead of humans manually verifying everything, automation does the boring work for us and raises a red flag when something goes wrong.

CI를 공항 보안 검색대로 비유해보기 (CI as an Airport Security Checkpoint)

개인적으로 CI를 가장 직관적으로 느꼈던 비유는 “공항 보안 검색대”입니다. 개발자가 작성한 코드는 탑승객이고, main 브랜치는 목적지행 비행기라고 생각해 봅시다. 보안 검색대를 통과하지 못한 탑승객은 비행기에 탈 수 없듯이, CI에서 에러가 난 코드는 절대 main에 머지되지 않습니다.

My favorite mental model for CI is the “airport security checkpoint.” Your code is the passenger, and the main branch is the plane. If a passenger fails the security check, they can’t board the plane. In the same way, if your CI pipeline fails, that code must not be merged into main.

덕분에 리뷰어는 “이 코드가 빌드 되긴 할까?”를 걱정하기보다, 로직과 구조에만 집중해서 리뷰할 수 있습니다. 그리고 팀 전체가 “main은 항상 빌드 가능한 상태”라는 묵시적인 신뢰를 공유하게 됩니다.

Thanks to this, reviewers no longer need to wonder, “Does this even build?” They can focus purely on logic and architecture, while the team gains a shared assumption that “main is always in a buildable state.”

GitHub Actions를 CI 도구로 선택한 이유 (Why Choose GitHub Actions for CI?)

CI 도구는 Jenkins, CircleCI, GitLab CI 등 여러 선택지가 있습니다. 각 도구마다 장단점이 있지만, GitHub에 코드를 올려 두고 있다면 GitHub Actions를 쓰는 것이 가장 자연스럽습니다.

There are many CI tools out there—Jenkins, CircleCI, GitLab CI, and more. Each has pros and cons, but if your code already lives on GitHub, GitHub Actions is often the most straightforward choice.

GitHub Actions를 선택하면 별도의 서버를 준비하지 않아도 되고, 리포지토리 안에 있는 .github/workflows 폴더만 잘 관리해도 꽤 강력한 자동화 파이프라인을 구성할 수 있습니다.

With GitHub Actions, you don’t need to manage extra CI servers. As long as you maintain the .github/workflows directory in your repository, you can build a surprisingly powerful automation pipeline.

YAML과 워크플로우 기본 개념 (YAML and Workflow Basics)

GitHub Actions에서 자동화 작업은 모두 .yml 또는 .yaml 확장자의 설정 파일로 정의합니다. 이 파일들은 .github/workflows 폴더에 위치하며, “어떤 이벤트가 발생했을 때 어떤 작업을 어떤 순서로 실행할지”를 설명하는 스크립트 역할을 합니다.

In GitHub Actions, automation is defined via .yml or .yaml configuration files. These live inside the .github/workflows folder and act as scripts that describe “which jobs to run in response to which events, and in what order.”

YAML은 들여쓰기로 계층 구조를 표현하는 포맷입니다. JSON보다 눈으로 읽기 편해서, 환경 설정이나 CI 설정에 널리 쓰이고 있습니다.

YAML represents structure through indentation and is generally easier on the eyes than JSON, which is why it’s widely used for configuration and CI definitions.

name: example-user
age: 25
skills:
  - React
  - TypeScript
  - AWS

위 예시처럼 들여쓰기로 중첩 구조를 표현하고, -로 리스트를 나타냅니다.

As you can see, indentation expresses nesting, and - denotes list items.

기본 Node.js CI 워크플로우 흐름 (Basic Node.js CI Workflow)

먼저, GitHub에서 제공하는 기본 Node.js 템플릿 워크플로우의 흐름을 간단히 살펴보겠습니다. 아래 코드는 “push 또는 PR가 main 브랜치에 들어올 때 Node.js 여러 버전에서 빌드와 테스트를 실행하는” 전형적인 예시입니다.

Let’s first look at the flow of the default Node.js template workflow from GitHub. The snippet below is a typical example that runs builds and tests against multiple Node.js versions whenever a push or PR targets the main branch.

name: Node.js CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x, 22.x]

    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"
      - run: npm ci
      - run: npm run build --if-present
      - run: npm test

흐름만 정리하면 다음과 같습니다.

Here’s the simplified flow:

PR 또는 push 발생
→ CI 트리거
→ Node 18 / 20 / 22 버전에서 병렬 실행
→ 각 환경에서 checkout → Node 설치 → 의존성 설치 → 빌드 → 테스트
→ 전부 성공하면 ✅, 하나라도 실패하면 ❌

프론트엔드 전용 커스텀 워크플로우 예시 (Custom Frontend-Only Workflow Example)

실제 현업 프로젝트에서는 템플릿을 그대로 쓰기보다는, 팀의 브랜치 전략과 폴더 구조에 맞게 워크플로우를 커스터마이징하는 경우가 많습니다. 예를 들어, 모노레포 구조에서 frontend 폴더만 CI 대상이고, develop 브랜치에서만 검사를 돌리고 싶다고 가정해 보겠습니다.

In real-world projects, you rarely use the template as-is. Instead, you adapt the workflow to your branching strategy and folder layout. For example, imagine a monorepo where only the frontend directory should trigger CI and all checks must run on the develop branch.

# frontend-dev-ci.yml

name: Frontend CI on develop branch

on:
  pull_request:
    branches: [ develop ]
    paths:
      - "frontend/**"
      - ".github/workflows/**"
  push:
    branches: [ develop ]
    paths:
      - "frontend/**"

jobs:
  build:
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: ./frontend

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 22.20

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Run lint
        run: npm run lint

      - name: Run build
        run: npm run build:dev

이 설정에서 핵심 포인트를 하나씩 짚어보겠습니다.

Let’s break down the key ideas in this configuration.

1) develop 브랜치 기준으로 동작 (Runs Against the develop Branch)

on.pull_request.brancheson.push.branchesdevelop으로 지정해, 이 브랜치로 향하는 PR 또는 이 브랜치에 대한 직접 push만 CI를 실행하도록 제한했습니다.

By setting both on.pull_request.branches and on.push.branches to develop, we ensure that CI only runs for PRs targeting develop or direct pushes to it.

2) paths 필터로 불필요한 실행 줄이기 (Using paths Filters to Avoid Unnecessary Runs)

paths 옵션을 통해 실제로 프론트엔드 관련 파일이 변경된 경우에만 워크플로우가 실행됩니다. 예를 들어, 백엔드 폴더나 문서만 수정했다면 프론트엔드 CI가 돌지 않습니다.

The paths option ensures the workflow only runs when frontend-related files change. If you modify only backend code or documentation, the frontend CI won’t be triggered.

  • frontend/** : 프론트엔드 폴더 안의 변경이 있을 때
  • .github/workflows/** : 워크플로우 파일 자체를 수정했을 때
  • frontend/**: whenever something inside the frontend directory changes
  • .github/workflows/**: whenever a workflow file itself changes

3) working-directory로 루트 정리 (Setting working-directory)

defaults.run.working-directory./frontend로 지정하면, 아래에 나오는 모든 run 명령어가 자동으로 프론트엔드 폴더 기준으로 실행됩니다. 덕분에 매번 cd frontend를 적지 않아도 되어 설정 파일이 깔끔해집니다.

By defining defaults.run.working-directory as ./frontend, all subsequent run commands execute from that directory. This keeps the YAML clean and avoids sprinkling cd frontend everywhere.

4) Node.js 버전 고정 (Locking Node.js Version)

템플릿에서는 여러 Node.js 버전을 matrix로 돌리지만, 실제 배포 환경이 특정 버전으로 고정되어 있다면 CI에서도 동일한 버전만 사용하는 것이 관리 측면에서 더 간단합니다. 여기서는 22.20 버전을 기준으로 테스트, 린트, 빌드를 수행합니다.

The template uses a matrix to test multiple Node.js versions, but if your production environment runs a single version, it’s often simpler to mirror that in CI. In this example, all checks run against Node.js 22.20.

5) 테스트 → 린트 → 빌드 순서 (Test → Lint → Build Order)

단계 순서는 팀마다 다르게 정할 수 있지만, 일반적으로 “의존성 설치 → 테스트 → 린트 → 빌드” 흐름이면 충분히 안정적인 검증이 가능합니다. 중요한 점은, 이 모든 과정이 “PR이 올라오는 순간 자동으로” 실행된다는 사실입니다.

The exact order can vary by team, but a common and practical flow is “install dependencies → run tests → run lint → build.” The crucial part is that all of this happens automatically whenever someone opens a PR.

CI를 도입하고 나서 달라진 점 (How CI Changes Your Daily Workflow)

CI가 없을 때는 리뷰어가 직접 브랜치를 받아 빌드를 돌려보거나, 타입 에러와 린트 에러를 눈으로 찾아가며 코멘트를 남겨야 했습니다. 심하면 머지 이후에야 빌드가 깨졌다는 사실을 발견하는 경우도 있었죠.

Without CI, reviewers often have to pull down branches, run the build locally, and manually spot type or lint issues. In the worst case, you only realize the build is broken after the merge.

CI를 제대로 도입하고 나면, PR 화면에서 초록 체크 ✔ 또는 빨간 X ❌ 만 봐도 현재 상태를 빠르게 파악할 수 있습니다. “Details” 로그를 열어보면 어느 단계에서 실패했는지도 바로 확인할 수 있고, 작성자는 머지 전에 스스로 문제를 수정할 수 있습니다.

Once CI is in place, a simple green check ✔ or red X ❌ on the PR tells you the current status at a glance. You can open the “Details” log to see exactly which step failed, and authors can fix issues before merging.

결국 팀은 “main은 항상 동작한다”는 신뢰를 얻게 되고, 리뷰어는 비즈니스 로직과 설계에 더 많은 에너지를 쓸 수 있게 됩니다. 그리고 개발자는 초록 체크가 뜨는 순간, 작은 성취감을 느끼게 되죠.

In the end, the team gains trust that “main always works,” reviewers can spend more energy on business logic and design, and developers get a tiny shot of dopamine every time that green check appears.

마무리 및 다음 단계 (Wrapping Up and Next Steps)

지금까지 프론트엔드 프로젝트를 예로 들어, GitHub Actions로 CI를 구축하는 흐름과 예시 워크플로우를 살펴보았습니다. 요약하면, CI는 “사람 대신 반복적인 검사를 책임지는 자동 보안관”입니다.

We’ve walked through how to set up CI for a frontend project using GitHub Actions, along with a concrete workflow example. In short, CI is your automated sheriff that takes care of repetitive checks for you.

다음 단계로는, 여기서 통과한 코드를 자동으로 서버에 배포하는 CD(Continuous Delivery/Deployment)를 붙여 볼 수 있습니다. 예를 들어 AWS CodePipeline, GitHub Actions의 deploy job 등을 활용해 “PR → CI 통과 → 자동 배포”까지 이어지는 전체 파이프라인을 구성할 수 있습니다.

As a next step, you can hook up CD (Continuous Delivery/Deployment) so that code which passes CI is automatically deployed to your environment. Using tools like AWS CodePipeline or deployment jobs in GitHub Actions, you can build a full pipeline from “PR → CI passed → deployed.”

 

반응형