개발여행

Vue 달력 라이브러리 v-calendar의 버그와 대안책 본문

Frontend

Vue 달력 라이브러리 v-calendar의 버그와 대안책

jbilee 2024. 7. 10. 00:36

리액트 생태계에 react-calendar가 있듯, Vue 생태계에는 v-calendar 라이브러리가 있다. 현재 깃헙에 수많은 이슈들이 오픈되어 있지만, 간단한 캘린더를 구현할 땐 특별히 큰 문제는 없어서 나도 계속 사용할 것 같다.

 

다만 v-calendar의 주간 view 컴포넌트에 버그가 있어서 해결하기 위해 이런저런 시도를 해봤고, 그 끝에 나름대로의 대안책을 찾았다.

 

v-calendar는 view prop을 통해 주 단위로 보여주는 캘린더를 구현할 수 있다. 추가로 attributes prop을 전달하면 캘린더 날짜에 이벤트가 있음을 나타내주는 표시와 팝업도 넣을 수 있다.

라이브러리에서 제공하는 빌트인 라벨 기능

 

그런데 주간 view와 과거 날짜의 이벤트가 포함되어 있는 attributes를 함께 설정하면 제일 오래된 이벤트가 발생한 주를 디폴트로 보여주는 것이다. 아래와 같이 코드를 작성하면 (현 시점) 2024년 7월 둘째주 대신 제일 첫 이벤트가 있는 2017년 10월부터 시작한다.

<script setup lang="ts">
import { Calendar } from "v-calendar"

// v-calendar에 attributes prop으로 전달할 값 (내용 생략)
const attributes = ...
</script>

<template>
  <Calendar view="weekly" :attributes="attributes" locale="ko-KR" />
</template>

attributes로 전달한 이벤트들 중 제일 오래된 이벤트가 포함된 주부터 보여주는 스크린

 

다행히 <Calendar> 컴포넌트는 시작 지점을 따로 설정하는 initial-page prop도 있어서, 포맷에 맞게 시작 날짜를 객체로 전달하면 위와 같은 문제는 해결할 수 있다.

<script setup lang="ts">
import { Calendar } from "v-calendar"

const attributes = ...
// initial-page prop에 전달할 weekly view의 시작 페이지
const startPage = {
  year: new Date().getFullYear(),
  month: new Date().getMonth() + 1,
  day: new Date().getDate()
}
</script>

<template>
  <Calendar view="weekly" :attributes="attributes" :initial-page="startPage" locale="ko-KR" />
</template>

 

하지만 startPage 객체를 initial-page prop으로 넘겨도 주간 view는 7월 둘째주부터 시작하지 않는다. 아래처럼 7월 첫째주가 캘린더의 시작페이지로 고정된다.

startPage 객체의 day 값이 (7월) 10일이어도 7월 첫째주부터 보여주는 버그

 

day 값을 바꿔봐도 7월 첫째주가 고정인 것을 보면 day의 값이 무용지물인 버그가 있는 것 같다. 대신 week 값을 전달하면 정상적으로 7월 둘째주가 시작 페이지로 설정되는 것을 확인했다.

 

day 대신 week을 지정해주면 해결되지만, 자바스크립트의 Date prototype에는 getWeek() 메소드가 없다... 주어진 날짜가 그 달의 몇째 주에 해당하는지는 따로 계산식을 만들어야 한다.

 

date-fns 라이브러리로 해결

소스코드를 보던 중, v-calendar가 date-fns 라이브러리를 dependency로 사용하고 있다는 것을 알게 됐다. date-fns는 Date 객체를 조작하기 편하도록 각종 메소드를 제공하는데, 그 중 week의 값을 계산해주는 getWeekOfMonth() 메소드도 포함되어 있었다. 근본적인 문제(버그)를 해결한 건 아니지만, 일단 겪고 있던 이슈는 없어졌다.

const startPage = {
  year: new Date().getFullYear(),
  month: new Date().getMonth() + 1,
  week: getWeekOfMonth(new Date())
}

 

 

실력이 부족해 라이브러리의 소스코드에서 문제가 되는 부분을 찾진 못했지만, 그 과정에서 또다른 유용한 라이브러리를 알게 된 경험이었던 것 같다. 언젠간 꼭 버그를 직접 해결해 오픈소스 프로젝트에 기여해보고 싶다.

'Frontend' 카테고리의 다른 글

Nuxt 시작하기  (2) 2024.07.16
Konva 배우기 (1)  (1) 2024.07.12
Vue SFC 컴포넌트의 CSS 적용 방식  (0) 2024.06.12
Vue 배우기 (3)  (0) 2024.06.06
Clerk metadata로 어드민 계정 롤 부여하기  (0) 2024.06.05