Lit + Vite + StoryBook 개발환경 구성하기

반응형

패키지 세팅하기

디렉토리 생성

터미널을 이용해서 프로젝트의 디렉토리를 생성하자.

mkdir vite-lit-storybook

패키지 설치 Install

Vite 로 패키지를 생성하면 프레임워크와 언어도 자동으로 설치할 수 있다.

npm create vite@latest

해당 명령어를 이용하면 vite 의 최신버전을 설치한다.

설치를 시작하면 사용할 Project name 과 사용할 FrameWork, JS 언어 기본값 을 설정할 수 있다.

설정할때는 방향키Enter 를 눌러 설정한다.

✔ Project name: … vite-lit-storybook
✔ Select a framework: › Lit
✔ Select a variant: › TypeScript
Scaffolding project in /Users/dhcho/Desktop/development/space.developher/vite-lit-storybook/vite-lit-storybook...

Done. Now run:

  cd vite-lit-storybook
  npm install
  npm run dev

Vite 패키지가 설정되었다.

StoryBook@6 안정화 버전 설치하기

storybook 을 먼저 설치하자

npx storybook init

빌드 툴에 따라 자동으로 탐지해서 설치해주기 때문에 별도로 vite용 storybook 을 설치할 필요는 없다.

만약 별도의 명령어를 통해 설치하고 싶은 경우에는 아래의 명령어와 같다.

npm install @storybook/builder-vite --save-dev

StoryBook@6 Docs 작성하기

StoryBook Docs 에는 기본적으로 해당 컴포넌트에서 사용하는 프로퍼티들에 대한 args 테이블이 존재한다.

해당 내용은 Meta 정보에서 선언하면 적용할 수 있다.

Meta 는 stories 에서 export default 로 선언되는 객체이다.

export default {
  ... 내용 ...
} as Meta;

컴포넌트 Docs Description 작성

컴포넌트 Docs 에 반영할 description 을 작성할 수 있다.

작성 방법은 다음과 같다.

export default {
    title: "Test/Test Component",
    paramaters: {
        docs: {
            description: {
                component: `컴포넌트 Docs Description 내용`
            }
        }
    }
    ... 내용 ...
} as Meta;

컴포넌트 Docs Source Code 제어

Docs 에서는 Show code 를 선택하면 해당 스토리의 소스 코드를 볼 수 있다.

이 소스 코드를 별도의 속성값 설정을 통해서 제어할 수 있다.

Metaparameters 프로퍼티에서 제어할 수 있으며, 아래의 예제와 같다.

export default {
    parameters: {
        docs: {
          source: {
            code: 'Your code snippet goes here.',
            language: "yml",
          },
      },
   }
}

code 는 직접적으로 보여줄 소스 코드 정보이다. 스토리의 실제 소스코드가 아닌, 임의의 코드를 직접 노출하는데 사용된다.
language 는 소스 코드를 보여줄 타입으로 생각하면 된다. 기본적으로는 html 로 보여준다.

하지만 스토리의 소스 코드를 보여줘야 하기 때문에 잘 사용하진 않을 것 같은 옵션이다.

프로퍼티에 대한 Table 정보 작성

기본적으로 Docs Table 에는 Name, Description, Default, Control 에 대한 정보가 있다.

해당 정보는 Meta 정보의 argTypes 객체 내에서 선언한다.

각 프로퍼티 별로 선언하는 것이 특징이다.

export default { 
    ... 내용 ...

    argTypes: {
        label: { ... },
        label2 : { ... } // label 은 프로퍼티 이름을 의미한다.
    }

    ... 내용 ... 
} as Meta;

Name

name

프로퍼티의 이름을 사용자 임의로 규정하는 속성이다.

기본값은 argTypes 에 사용된 프로퍼티 명으로 설정되지만, name 을 규정하면 해당 내용으로 보여진다.

일반적으로는 프로퍼티명 대로 작성하기에 잘 사용될 것 같지는 않은 속성이다.

export default { 
    ... 내용 ...

    argTypes: {
        size: { 
            name: "input name"
        },
    }

    ... 내용 ... 
} as Meta;

만약 size 프로퍼티명에 name 으로 _size 를 작성했다면, 아래처럼 _size 로 보여진다.

type

프로퍼티의 타입 이름과 필수값 여부를 규정하는 속성이다.

필수값의 경우 기본값은 false 로 정의된다.

필수값이 true 로 정의되면 빨간색 * 가 표시된다.

export default { 
    ... 내용 ...

    argTypes: {
        size: { 
            type: {
                name: "number",
                required: true
            }
        },
    }

    ... 내용 ... 
} as Meta;

Description

description

프로퍼티의 표시할 설명을 규정하는 속성이다.

별도로 정의하지 않을 경우 아무런 값이 표시되지 않는다.

export default { 
    ... 내용 ...

    argTypes: {
        size: { 
            description: "example"
        },
    }

    ... 내용 ... 
} as Meta;
table

프로퍼티의 타입 속성에 대한 정보와 툴팁 정보를 규정하는 속성이다.

type

타입과 관련해서 규정하는 속성이다.

summarydetail 속성을 가진다.

summary 는 타입을 명시하며, detail 은 타입의 툴팁에 표현될 내용이다.

export default { 
    ... 내용 ...

  argTypes: {
    label: {
      table: {
        type: {
          summary: "string",
          detail: "타입에 대한 정보를 표현한다."
        },
      },
    },

    ... 내용 ... 
} as Meta;

아래와 같이 표현된다.

defaultValue

기본값을 규정하는 속성이다.

summarydetail 속성을 가진다.

동작 방식은 type 과 동일하다.

export default { 
    ... 내용 ...

  argTypes: {
    label: {
      table: {
        defaultValue: {
          summary: "string",
          detail: "타입에 대한 정보를 표현한다."
        },
      },
    },

    ... 내용 ... 
} as Meta;
control

테이블 내에서 기능을 조작하는데 어떤 방식으로 사용되는지 규정하는 속성이다.

기본값은 text 이다.


export default { 
    ... 내용 ...

  argTypes: {
    label: {
      control: {
          type: "text"
      }
    },

    ... 내용 ... 
} as Meta;

category 와 subcategory

테이블의 정보를 그룹핑하는데 사용되는 속성이다.

그룹핑을 하면 테이블 내에서 하나의 그룹 단위로 화면에서 보여진다.

테이블의 카테고리 category 와 하위 카테고리 subcategory 가 동일한 값끼리 그룹핑된다.

카테고리가 더 상위의 개념으로, 먼저 그룹핑한 후 하위 카테고리를 그룹핑한다.

export default { 
    ... 내용 ...

  argTypes: {
    label: {
      table: {
          category: "catagory-name"
      }
    },

    ... 내용 ... 
} as Meta;

StoryBook@7 베타 버전 설치

storybookstable 한 버전이 아닌 beta 버전을 설치하고자 한다면 다음과 같이 진행하면 된다.

주의사항!
storybook@7node@16 이상에서만 동작된다.


npx storybook@next init

StoryBook@7 Story 작성 방법

테스트 컴포넌트

테스트 컴포넌트는 button 클릭시 카운트가 올라가며, input 입력시 button 의 사이즈가 변하는 간단한 예제 컴포넌트이다.

다음과 같이 컴포넌트를 선언하였다.

import { css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { MobxLitElement } from "@adobe/lit-mobx";
import { TestStore } from "./TestStore";
import { styleMap } from "lit-html/directives/style-map.js";

@customElement("test-element")
export default class TestElement extends MobxLitElement {
  static style = css`
    .size--small {
      width: 80px;
      height: 80px;
    }

    .size--medium {
      width: 120px;
      height: 120px;
    }

    .size--large {
      width: 160px;
      height: 160px;
    }
  `;
  store = new TestStore();

  @property()
  size: number = 80;

  @property()
  iconText: string = `+`;

  @property()
  backgroundColor: string = `red`;

  render() {
    return html`
      <div>
        <button
          @click=${this.store.changeValue}
          style=${styleMap({
            width: `${this.size || 10}px`,
            height: `${this.size || 10}px`,
            backgroundColor: this.backgroundColor,
          })}
        >
          ${this.iconText}
        </button>
        ${this.store.value}
        <input
          type="number"
          @change=${(event: any) => (this.size = event.target.value)}
        />
      </div>
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "test-element": TestElement;
  }
}

스토어

사실 스토어는 사용하지 않아도 되지만, 회사 프로젝트에서는 UI 컴포넌트에서 Store 를 사용하는 구간이 있어서 동작하는지 테스트 하기 위해 사용하였다.

import { action, makeObservable, observable } from "mobx";

export class TestStore {
  constructor() {
    makeObservable(this, { value: observable, changeValue: action.bound });
  }

  value = 0;

  changeValue(event: any) {
    this.value = ++event.target.value;
  }
}

스토리

import type { Meta } from "@storybook/web-components";

import "./Test";

const meta: Meta = {
  title: "Button",
  component: "test-element",
};
export default meta;

export const Primary = {
  args: {
    size: 50,
    iconText: `+`,
    backgroundColor: `blue`,
  },
};

자동으로 Docs 생성하기

StoryBook@7 부터는 자동으로 Docs 를 생성할 수 있는 AutoDocs 기능이 추가되었다.
meta 정보 내에서 tags: ["autodocs"] 프로퍼티를 추가함으로써 자동으로 변경할 수 있다.

const meta: Meta = {
  title: "Test/Component",
  component: "test-element",
  tags: ["autodocs"],
};
export default meta;

에러발생
Docs 를 생성하는데 다음과 같은 에러가 발생했다.

error loading dynamically imported module

구글링 결과 vite-builder 관련 문제로 보인다.

내 경우 node_modules 를 삭제했다가 재설치 하니 해결되었다. (node_modules 의 cahce 문제라고 한다.)

rm -rf node_modules

npm ci

Docs 내 Description 작성하기

StoryBook@7 에서는 JSDOC 을 이용해서 Docs 에 Description 을 추가할 수 있다.

사용 방법은 Story 코드 바로 위줄에 JSDOC 을 작성하면 된다.

JSDOC 작성방법은 다음과 같다.

/** 내용 */

적용하면 다음과 같다.

/** 테스트 */
export const Primary = {
  args: {
    primary: true,
    size: 50,
    iconText: `+`,
    backgroundColor: `red`,
  },
};

만약 한개의 Story 가 아닌, 전체 Stories 의 Docs 에 대한 Description 을 작성하고자 한다면, Stories 에 대한 JSDOC 을 작성하면 된다.

/** 테스트2 */
const meta: Meta = {
  title: "Test/Component",
  component: "test-element",
  tags: ["autodocs"],

  parameters: {
    docs: {
      story: { inline: true }, // render the story in an iframe
      canvas: { sourceState: "shown" }, // start with the source open
      source: { type: "code" }, // forces the raw source code (rather than the rendered JSX).
    },
  },
};
export default meta;

레퍼런스

Vite + StoryBook
StoryBook 7 설치방법
StoryBook 7 스토리 작성 방법
StoryBook Dynamic Import Error Solve

반응형