본문 바로가기

Vue.js

[Vue.js] Vue3 환경에서 Storybook 설치 및 Pagination 공통 컴포넌트 적용기

어느 날, 새로운 기획 요구사항을 받았습니다. "페이지네이션 디자인을 변경해야 합니다."
일반적으로는 디자인 요구사항에 따라 기존 컴포넌트를 수정하거나 새로 제작하면 됩니다. 하지만 이번에는 단순히 디자인을 바꾸는 데 그치지 않고, 디자인 시스템을 도입해보면 좋겠다고 생각했습니다.

 

 

왜 디자인 시스템인가?

  1. 페이지네이션 같은 공통 컴포넌트는 서비스 전반에서 자주 사용되므로, 디자인 변경 시 전체적인 일관성을 유지하는 것이 중요합니다.
  2. 여러 개발자가 함께 작업할 때, 컴포넌트가 표준화되어 있지 않으면 유지보수성이 떨어지기 때문에 효율적인 협업 환경이 필요했습니다.
  3. Storybook을 활용하면 UI를 독립적으로 테스트하고 문서화할 수 있어 개발 및 디자인 협업이 수월해진다는 점에서 매력을 느꼈습니다.

 

왜 이 작업을 시작하게 되었나?

기존 페이지네이션은 단순히 앞뒤로 이동하는 버튼만 있었지만, 이번 기획에서는 "맨 앞으로""맨 뒤로" 버튼이 추가되었습니다. 이로 인해 버튼 동작에 따라 totalPagecurrentPage 값이 올바르게 반영되는지를 검증하는 것이 필수적이었습니다.

Storybook을 도입한 이유 중 하나는 바로 이 지점에서 더 효율적인 테스트가 가능하기 때문이었습니다. 로컬서버에서의 테스트 데이터 부족으로 버튼을 클릭하면 페이지가 잘 넘어가는지, 많은 페이지가 있을 때 기능 요구사항을 잘 따르는지 등을 테스트하기에 리소스가 많이 드는게 문제였습니다. 이를 위해 목데이터를 생성하고, 테스트 하여 확인 후 다시 없애고 하는 작업이 비효율적이였습니다.

그래서 Storybook 을 사용하면 상태(args)를 변경하며 다양한 상황에서 버튼이 올바르게 작동하는지 손쉽게 확인할 수 있고 개발 검증을 빠르게 할 수 있어 도입하게 되었습니다.

 

 

[기존 페이지네이션 UI]

 

[변경 페이지네이션 UI]

 

 

 


 

시작: Storybook 설치 및 초기 세팅

1. Storybook 설치

Storybook은 컴포넌트를 독립적으로 개발하고 시각적으로 테스트할 수 있는 도구입니다. Vue3 프로젝트에 Storybook을 설치하려면 아래 명령어를 실행하면 됩니다.

 
yarn dlx storybook@latest init
 
  • version : "storybook": "^8.4.6"

이 명령어를 실행하면 Storybook이 자동으로 프로젝트에 맞는 설정을 적용합니다. Vue3 프로젝트에 최적화된 환경이 기본으로 제공되며, Storybook에서 바로 컴포넌트를 로드할 수 있도록 파일 시스템을 스캔합니다.

 

 

기본 샘플 파일 설치됨

 

 

error : yarn dlx not found

해결참고 : https://stackoverflow.com/questions/78161928/yarn-dlx-not-found-why-how-to-run-yarn-dlx-command

 

yarn dlx not found. Why?! How to run yarn dlx command?

I installed yarn by brew install yarn i try yarn dlx storybook@latest upgrade result: yarn run v1.22.22 error Command "dlx" not found. info Visit https://yarnpkg.com/en yarn add or y...

stackoverflow.com

npm install -g yarn
yarn set version berry

 

 

 

2. package.json 실행 스크립트 작성

"scripts": {
   ...
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },

 

 

3. 실행 -> ✨ okay!

yarn storybook
[로컬도 실행시켜야 함]yarn serve

 

 

 

 

 


storybook 에 tailwindCSS 적용

Storybook은 기본적으로 PostCSS를 지원하지만, TailwindCSS를 사용하려면 설정 파일을 Storybook에서 읽을 수 있도록 추가 작업이 필요합니다. 

https://storybook.js.org/recipes/tailwindcss

 

Storybook: Frontend workshop for UI development

Storybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. It's open source and free.

storybook.js.org

 

npx storybook@latest add @storybook/addon-styling-webpack

안되면, 
npx @storybook/auto-config styling

 

 

yarn add @storybook/addon-styling-webpack

 

 

yarn add @storybook/addon-postcss

 

 

storybook/main.js

module.exports = {
  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
 addons: [
    "@storybook/addon-onboarding",
    "@storybook/addon-essentials",
    "@chromatic-com/storybook",
    "@storybook/addon-interactions",
    "@storybook/addon-postcss",👈 add ‼
  ],
  framework: '@storybook/vue3',
  webpackFinal: async (config) => { 👈 add ‼
    config.module.rules.push({
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'postcss-loader',
          options: {
            postcssOptions: {
              plugins: [
                require('tailwindcss'),
                require('autoprefixer'),
              ],
            },
          },
        },
      ],
      include: path.resolve(__dirname, '../'),
    });
    return config;
  },
};

 

 

.storybook/preview.js 파일에서 CSS 파일을 import

import "@/assets/css/tailwind.css";

 

 

 

tailwind.config.js에서 Storybook을 포함한 경로가 설정되어야 Tailwind가 적용됩니다.

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./src/**/*.{html,js}", 
    "./src/**/*.{vue,js,ts,jsx,tsx}", 
    "./stories/**/*.{vue,js,ts,jsx,tsx}" 👈 add ‼
  ],
  theme: {
    extend: {},
    colors: {
     ...
};

 

 

 


 

 

 

 

Pagination 컴포넌트 제작

이번 작업의 핵심은 Pagination 컴포넌트였습니다. 페이지네이션은 다양한 서비스에서 필수적으로 사용되는 요소로, 디자인 변경과 함께 여러 가지 기능 요구사항도 있었습니다.

  • 기능 요구사항
    • 현재 페이지를 하이라이트.
    • 앞/뒤 페이지로 이동 가능.
    • 첫 페이지와 마지막 페이지 버튼 제공.
    • 6페이지 이상 시, 페이지 숫자는 5페이지 단위로 노출
  • 디자인 요구사항
    • 버튼 크기, 색상, 간격 등을 디자이너가 제공한 스타일에 맞춤.
    • 반응형 레이아웃을 고려해 모바일 환경에서도 적절히 보이도록 구현.

 

Storybook에서 Pagination 문서화

Pagination 컴포넌트를 Storybook에 등록하고 UI를 독립적으로 테스트할 수 있도록 했습니다.

아래는 Storybook용 Pagination.stories.js 코드입니다.

 

 

🔗 src/stories/Pagination/Pagination.vue

<template>
  <div class="flex">
    <!-- 처음으로 이동 -->
    <button @click="goToFirstPage" :disabled="isFirstPage" class="pagination-button mr-1">
      <img src="@/assets/img/page/prev.png" />
      <img src="@/assets/img/page/prev.png" />
    </button>

    <!-- 이전 페이지 -->
    <button @click="prevPage" :disabled="isFirstPage" class="pagination-button mr-2">
      <img src="@/assets/img/page/prev.png" />
    </button>

    <!-- 페이지 번호 표시 -->
    <button
      v-for="page in visiblePages"
      :key="page"
      @click="goToPage(page)"
      :class="['number-tag', { 'current-page': page === currentPage }]"
    >
      {{ page }}
    </button>

    <!-- 다음 페이지 -->
    <button @click="nextPage" :disabled="isLastPage" class="pagination-button ml-2 mr-1">
      <img src="@/assets/img/page/next.png" />
    </button>

    <!-- 마지막 페이지로 이동 -->
    <button @click="goToLastPage" :disabled="isLastPage" class="pagination-button">
      <img src="@/assets/img/page/next.png" />
      <img src="@/assets/img/page/next.png" />
    </button>
  </div>
</template>
...

// classCSS -> tailwindCSS 로 적용 (@apply~)

 

 

🔗 src/stories/Pagination/Pagination.stories.js

 
 
import Pagination from "./Pagination.vue";

export default {
  title: "Components/Pagination",
  component: Pagination,
  argTypes: {
    totalPages: { control: { type: "number", min: 1 } },
    currentPage: { control: { type: "number", min: 1 } },
  },
};

const Template = (args) => ({
  components: { Pagination },
  setup() {
    return { args };
  },
  template: '<Pagination v-bind="args" />',
});

export const Default = Template.bind({});
Default.args = {
  totalPages: 10,
  currentPage: 1,
};
 
argTypes는 컴포넌트의 속성(props)와 이벤트를 제어할 수 있도록 정의합니다.
▫️ totalPages: 페이지의 총 개수 (숫자 입력, 최소값 1)
▫️ currentPage: 현재 페이지 (숫자 입력, 최소값 1).

 

 

[동작 영상]

 

develop(로컬)서버에서의 데이터 부족으로 많은 페이지의 테스트가 불가하였는데 storybook 도입으로 totalPage 와, currentPage 를 조절하여 테스트할 수 있게 되었습니다.

Storybook을 활용하면 디자이너와 개발자가 동일한 화면을 보면서 소통할 수 있어 디자인-개발 간 갭을 줄이는 데 큰 효과가 있었습니다.

 

 

 

개발하며 느낀 점

  1. Storybook 도입의 장점
    Storybook을 사용하면서 가장 큰 장점은 UI 컴포넌트를 독립적으로 개발하고 테스트할 수 있었다는 점입니다. 페이지 전체를 실행하지 않아도 특정 컴포넌트의 동작과 디자인을 바로 확인할 수 있었습니다.
  2. 디자인 시스템과의 연계
    페이지네이션을 Storybook에 등록하며, 다른 컴포넌트들도 디자인 시스템의 일부로 통합할 가능성을 모색했습니다. 이는 장기적으로 컴포넌트의 재사용성과 일관성을 높이는 데 기여할 것이라 느꼈습니다.
  3. Vue3와 Storybook의 궁합
    Vue3의 Composition API와 Storybook의 조합은 매우 강력했습니다. 특히 args와 argTypes를 통해 Props를 쉽게 제어할 수 있어 개발 속도와 문서화 효율이 크게 향상되었습니다.
  4. 앞으로의 개선 방향
    이번 작업을 통해 공통 컴포넌트와 Storybook의 중요성을 다시 한번 느꼈습니다. 앞으로 더 많은 컴포넌트를 Storybook에 등록하고, 팀원들과의 협업을 강화하여 더 나은 사용자 경험을 제공하고 싶습니다.

 

마무리하며

이번 작업은 단순히 페이지네이션 디자인을 변경하는 것을 넘어, 효율적인 협업 환경을 구축하고 디자인 시스템을 도입하기 위한 첫걸음이었습니다. Vue3와 Storybook을 활용해 더욱 정리된 코드와 UI 문서화를 경험하며, 앞으로의 프로젝트에도 큰 자신감을 얻을 수 있었습니다.

 

728x90
반응형