Storybook 및 애드온을 Next.js 14에 적용하기

hodu·2024년 3월 4일
6
post-thumbnail

🎈 Storybook을 활용한 협업 강화

프로젝트 초기 단계에서 새로운 도구와 기술을 접하는 것은 언제나 도전적입니다. 이번 프로젝트에서는 Next.js 14와 Storybook을 통합하여, 팀원 간의 효율적인 커뮤니케이션을 목표로 하고 있습니다.

Turborepo에서 워크스페이스별로 관리

Turborepo는 프로젝트의 의존성과 작업을 효율적으로 관리할 수 있는 툴입니다. 현재 저희는 nest.js를 사용하는 백엔드와 mono repo인 turbo repo를 사용하여서 작업을 진행할 예정입니다.

그래서 turbo repo에서 storybook 사용하는 방법에 대해 검토가 필요했습니다.
공식 문서에 따르면, Storybook을 프로젝트 최상단에서 통합할 수 있으나, 최상단에서 관리하는 것은 팀원에게 추가적인 부담을 주는 것이라고 느꼈습니다.

더불어 추가적인 프로젝트 진행은 계획하지 않아서 워크스페이스 단위에서 Storybook을 관리하기로 결정했습니다. 😥


😎 Next.js 14와의 통합

Next.js 14에서 Storybook을 시작하는 것은 생각보다 간단합니다. 단순히 터미널에 npx storybook@latest init 명령어를 입력하면 Next.js 환경을 자동으로 감지하여 필요한 설정을 완료합니다.

현재는 Storybook의 최신 버전(8버전) 대신 7.6 버전을 사용하는 것이 좋습니다.

처음에는 8버전을 설치하였는데, 오류가 나서 정상 작동하지 않았습니다.
8버전은 beta 버전이어서 불안정하였고, 7.6 버전으로 변경하니 안정적이었습니다.

설치 이후에는 Storybook의 직관적인 인터페이스와 명확한 가이드라인 덕분에 설정을 손쉽게 마칠 수 있었습니다.

Storybook에 컴포넌트를 적용하는 과정은 아래와 같습니다

import type { Meta, StoryObj } from "@storybook/react";
import LoginForm from "./login-form";

const meta: Meta<typeof LoginForm> = {
  title: "Example/LoginForm",
  component: LoginForm,
  tags: ["autodocs"] // 자동 문서화 기능을 위한 태그
};

export default meta;

type Story = StoryObj<typeof meta>;

// 기본 스토리
export const Default: Story = {};

이 코드 예시는 LoginForm 컴포넌트를 Storybook에 쉽게 통합할 수 있음을 보여줍니다. 컴포넌트를 정의하고, Storybook에서의 제목과 태그를 설정하기만 하면 됩니다.

추가적인 설정으로 argsparameters를 정의하여 컴포넌트의 다양한 상태를 시각화할 수 있습니다.

이 글에서는 주로 Storybook의 Addons와 관련된 설정에 초점을 맞출 예정입니다.


🌊 Storybook에 TailwindCSS 적용하기

Storybook에 TailwindCSS를 적용하는 것은 공식 가이드에 따라 진행하면 간단합니다. 먼저, 전역 스타일 시트에 TailwindCSS의 기본, 컴포넌트, 유틸리티 클래스를 import 합니다.

/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

그 다음, Storybook의 preview.ts 파일 최상단에 위에서 작성한 CSS 파일을 import 합니다. 이렇게 하면 Storybook 프로젝트 전반에 걸쳐 TailwindCSS가 적용됩니다.

// preview.ts
import "../app/ui/shared/globals.css"; // 프로젝트의 경로에 맞게 조정하세요.

🚑 Next.js 14에서의 App Router 이슈 해결

Next.js 14와 함께 Storybook을 사용할 때 AppRouter 관련 이슈가 발생할 수 있습니다. 이 문제는 Storybook에서 Next.js의 AppRouter 컨텍스트를 인식하지 못해 발생하는 것으로, 다음과 같은 오류 메시지가 나타날 수 있습니다.

공식 가이드라인에서 제시한 해결책인 nextjs: {appDirectory: true},를 추가해도 문제가 해결되지 않았습니다.

GitHub 이슈(#24722)에서 제시한 해결 방법을 통해 해결하였습니다.

// withAppRouterContext.tsx
import {
  AppRouterContext,
  type AppRouterInstance
} from "next/dist/shared/lib/app-router-context.shared-runtime";
import { FC } from "react";

const withAppRouterContext = (Story: FC) => (
  <AppRouterContext.Provider value={{} as AppRouterInstance}>
    <Story />
  </AppRouterContext.Provider>
);

export default withAppRouterContext;

위 컴포넌트를 작성한 후, preview.ts 파일의 decorators 배열에 추가합니다.

// preview.ts
const preview: Preview = {
  // 생략
  decorators: [withAppRouterContext]
};

이 방법을 통해 App Router 관련 문제를 해결할 수 있었습니다.

전체 next14 전용으로 사용할 것이어서 전체에 적용하였지만, 특정 스토리에만 적용할 수도 있는데, 그럴 경우 해당 스토리 파일의 decorators 배열에 위 컴포넌트를 추가하면 됩니다.


절대 경로 설정 이슈

Storybook에서 절대 경로를 사용할 때 발생하는 문제는 tsconfig.json 파일에 baseUrl을 설정하여 해결할 수 있습니다. Storybook이 TypeScript 설정을 참조할 때 baseUrl이 명시되어 있지 않으면 절대 경로를 올바르게 인식하지 못합니다.

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    }
  }
}

이 설정을 추가함으로써, Storybook에서도 절대 경로를 사용할 수 있었습니다.
하지만 main.ts와 preview.ts에서는 상대경로를 사용하였는데, 이부분은 더 검토가 필요합니다.


➕ Storybook 애드온으로 개발 경험 향상시키기

Storybook은 컴포넌트 기반 개발을 용이하게 만들어주는 도구입니다. 이번 프로젝트에서는 Storybook의 여러 애드온을 통해 개발 효율성을 높이고자 했습니다.

@storybook/addon-viewport로 반응형 디자인 확인

pnpm add -D @storybook/addon-viewport

이 애드온을 설치하고 preview.ts 파일에 초기 설정을 추가함으로써, Storybook 내에서 다양한 디바이스 사이즈에서의 컴포넌트 렌더링을 확인할 수 있었습니다.

// preview.ts
import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from "@storybook/addon-viewport";

const preview: Preview = {
  viewport: {
    viewports: {
      ...INITIAL_VIEWPORTS,
      ...MINIMAL_VIEWPORTS
    },
    defaultViewport: "iphone14promax"
  },
}

Viewport Addon

아쉬운 점이 있다면 기본적으로 제공해주는 size가 한국에서 보편적이지 않아서, viewport에서 추가가 필요해보입니다.


@storybook/addon-a11y로 접근성 확인

웹 접근성은 중요한 요소입니다. @storybook/addon-a11y를 설치하고 설정함으로써, 컴포넌트의 접근성을 UI확인과 더불어 체크할 수 있습니다.

A11y Addon


@storybook/addon-storysource로 소스 코드 확인

@storybook/addon-storysource 애드온은 Storybook에서 직접 컴포넌트의 스토리북 객체 코드를 확인할 수 있게 도와줍니다. 이를 통해 컴포넌트의 구현 방식을 빠르게 이해할 수 있습니다.

Storysource Addon


@storybook/addon-designs로 디자인 시스템 통합

디자인과 개발의 일관성을 유지하는 것은 프로젝트의 성공에 있어 중요합니다. @storybook/addon-designs를 통해 Figma와 같은 디자인 툴과 Storybook을 연동할 수 있게 되었습니다. 이를 통해 디자이너와 개발자 간의 소통이 한층 간편해졌습니다.

Designs Addon


📷 Chromatic 추가하기

Chromatic은 Storybook과 긴밀하게 통합되어 UI 컴포넌트의 시각적 회귀 테스트를 자동화하는 강력한 도구입니다. 이를 통해 개발자는 UI 변경사항을 신속하게 식별할 수 있습니다.
아래 내용은 Chromatic을 프로젝트에 통합하고 설정하는 과정을 단계별로 설명합니다.

  1. Chromatic 설치: 프로젝트에 Chromatic을 추가하기 위해, 먼저 패키지 매니저를 사용하여 chromatic을 설치합니다.

    pnpm add -D chromatic
  2. GitHub Actions 설정: Chromatic을 CI/CD 파이프라인에 통합하기 위해 GitHub Actions 워크플로우를 설정합니다. 기본적인 설정은 프로젝트의 루트 디렉토리에서 진행되며, on: push 이벤트에 반응하여 Chromatic 테스트를 실행합니다.

    # Workflow name
    name: "Chromatic Deployment"
    
    # Event for the workflow
    on: push
    
    # List of jobs
    jobs:
      test:
        # Operating System
        runs-on: ubuntu-latest
        # Job steps
        steps:
          - uses: actions/checkout@v1
          - name: Install pnpm
            run: npm install -g pnpm
    
          - name: Install dependencies with pnpm
            run: pnpm install
    
          - uses: chromaui/action@v1
            with:
              projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
              token: ${{ secrets.GITHUB_TOKEN }}
  3. Turborepo 환경에서의 Chromatic 설정: Turborepo와 같은 모노레포 환경에서는 특정 워크스페이스에 Chromatic을 적용해야 할 수 있습니다. 이 경우, workingDir 옵션을 사용하여 Chromatic이 실행될 워크스페이스를 지정합니다.

    # Workflow name
    name: "Chromatic for Flower House Project"
    
    on: push
    
    jobs:
      chromatic:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v1
    
          - name: Install pnpm
            run: npm install -g pnpm
    
          - name: Install dependencies for Flower House Project
            run: pnpm install
            working-directory: apps/flower-house
    
          - name: Publish to Chromatic
            uses: chromaui/action@v1
            with:
              projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
              token: ${{ secrets.GITHUB_TOKEN }}
              workingDir: apps/flower-house
  4. 병렬 또는 직렬 실행: 프로젝트가 확장되어 여러 워크스페이스에 Chromatic을 적용해야 할 경우, 각각을 직렬로 실행하거나 병렬로 구성하여 실행 시간을 최적화할 수 있습니다.

Chromatic을 사용함으로써, 개발자는 코드 변경이 생길때 마다, UI에 미치는 영향을 즉각적으로 시각화하고 검토할 수 있습니다.


🎇 후기

Storybook과 그 애드온들을 프로젝트에 적용한 경험은 매우 긍정적이었습니다. 문서가 잘 정리되어 있고, 접근성이 좋아서 학습 곡선이 상대적으로 낮았습니다.

Storybook을 최대한 활용하여서 개발 프로세스의 효율성을 높이고, 팀원 간의 소통을 강화해 나갈 예정입니다.


출처 :

https://storybook.js.org/recipes/next
https://storybook.js.org/blog/get-started-with-storybook-and-next-js/
https://storybook.js.org/tutorials/intro-to-storybook/react/ko/get-started/
https://storybook.js.org/recipes/tailwindcss
https://help.figma.com/hc/en-us/articles/360045003494-Storybook-and-Figma
https://www.npmjs.com/package/@storybook/addon-designs
https://www.chromatic.com/docs/github-actions/#run-chromatic-on-monorepos
https://storybook.js.org/tutorials/intro-to-storybook/react/ko/deploy/

profile
잘부탁드립니다.

1개의 댓글

comment-user-thumbnail
2024년 4월 21일

appRouter를 사용할 때, asPathpath 설정이 되나요? console.log로 pathname 값을 출력해보고 있는데 '/'로만 결과가 나오네요.

답글 달기