PARA/03_Resources/R001_개발_레퍼런스(참고문서)/JavaScript/어렵게 만든 차트를 react기반 프로젝트에서 재사용할 수는 없을까.md

어렵게 만든 차트를 react기반 프로젝트에서 재사용할 수는 없을까

개요

현재 nuxt로 만들어진 chartJS기반 컴포넌트를 next 기반 시스템에서 재사용하려는 니즈가 있다.

상세

아쉽게도 당장 내 지식으로는 vue와 react를 같이 쓰는 최선의 아이디어가 없다.
그나마 생각나는건

  1. 바닐라 자바스크립트로 만들기
  2. nuxt와 next.js 따로 만들기
  3. 아예 독립적인 라이브러리로 만들어서 배포하기

이정도인데
1,3은 실제로 해보지 않아서 추상적인 아이디어라고 할 수 있다.

당장 이 요구사항은 해야할 이슈는 아니므로 문제 정의만 해두고 나중에 이 일을 해야 할 상황에 다시 정리해보도록 하자.

해결방안(예비)

1. 바닐라 자바스크립트 기반으로 작성하기

개요

  • Vue/React 같은 프레임워크 의존성을 제거하고, Chart.js를 직접 활용해 컴포넌트를 구현.
  • 순수 자바스크립트(또는 TypeScript)로 Chart.js 초기화 로직과 DOM 조작을 작성한 뒤, 해당 로직을 Vue나 React 컴포넌트에서 각각 래핑(wrapping)하는 방식.

장점

  • 프레임워크 독립성: Vue, React 양쪽에서 똑같이 가져다 쓰기 쉬워짐.
  • 유지보수 단순화: 바닐라 코드만 업데이트하면, Vue/React 컴포넌트는 동일 로직을 가져다 써서 재사용.

단점

  • 직접 DOM 제어: Vue/React의 데이터 바인딩, 라이프사이클 등을 활용하기 어려워 더 세밀한 DOM 관리가 필요.
  • 개발 난이도 증가: Vue/React에 익숙하다면 “바닐라 + Chart.js” 접근은 생소할 수 있음.
  • 추가 래퍼(wrapper) 작성 필요: 결국 Vue용 래퍼 컴포넌트, React용 래퍼 컴포넌트를 각각 만들어야 함.

2. Vue와 React 각각 별도 개발(혹은 유지)

개요

  • Nuxt(Vue)와 Next(React) 프로젝트에서 동일한 UI/UX를 가진 ChartJS 컴포넌트를 각각 구현/관리.
  • 현재 Nuxt용 코드는 그대로 유지하고, React에서는 새롭게 컴포넌트를 작성.

장점

  • 프레임워크 친화적: Vue, React 각각의 생태계와 문법에 맞춰 최적화할 수 있음.
  • 학습 비용 낮음: 기존 Nuxt 코드를 유지하면서, React 환경에서는 React답게(특히 훅, 라이프사이클, 상태 관리 등) 컴포넌트를 구현.

단점

  • 코드 중복 발생: 동일한 로직을 서로 다른 두 코드베이스에서 관리해야 함.
  • 유지보수 비용 증가: 기능 수정 시, 두 프레임워크 버전을 모두 반영해야 함.
  • 장기적으로 비효율: 컴포넌트가 많아지면 업데이트 부담이 커짐.

3. 독립된 라이브러리(패키지)로 배포

개요

  • Chart.js를 사용해 만든 핵심 로직을 하나의 NPM 패키지로 추상화.
  • Vue/React 라이브러리로 “래퍼”를 만들어 이 핵심 로직을 각각 가져다 사용하는 구조.
    • 예시: @company/chart-core (바닐라+Chart.js 구현)
    • Vue 래퍼: @company/chart-vue
    • React 래퍼: @company/chart-react

장점

  • 모듈화·재사용성 극대화: “chart-core”라는 단일 소스를 유지하므로, 라이브러리 업데이트 시 Vue/React 쪽도 자동으로 최신화 가능.
  • 유지보수 편의성: 하위 레벨 로직(Chart.js 초기화, 업데이트 등)은 한 군데에서 관리.
  • 프레임워크 별 최적화 가능: Vue, React 래퍼는 각자의 문법과 상태 관리를 활용해 UX 개선.

단점

  • 초기 세팅 복잡도: monorepo(또는 멀티 패키지 구조)를 구성해야 할 수 있음.
  • 퍼블리시 자동화 필요: NPM 배포 파이프라인(CI/CD)이 필요하고, 버전 관리도 신경써야 함.
  • 학습 비용: 팀에서 npm 패키지를 만들어 배포·관리하는 데 대한 추가 지식 필요.

4. Web Component(Custom Elements)로 래핑

개요

  • Vue 코드(또는 바닐라+Chart.js)로 만든 컴포넌트를 Web Component(Custom Element) 규격으로 빌드.
  • React 쪽에서는 일반 DOM 태그처럼 <my-chart></my-chart>를 사용하여 삽입.
  • Vue 3부터는 vue-web-component-wrapper 등을 활용하여 Web Component로 변환 가능(단, Nuxt 환경에서의 세팅은 추가 검토 필요).

장점

  • 프레임워크 무관한 배포: Web Component이므로 어떤 환경에서든 <my-chart> 태그로 사용 가능.
  • 캡슐화: 컴포넌트 내부 스타일이나 기능을 섀도 DOM으로 격리 가능.

단점

  • 학습 난이도: Web Component 생태계와 래핑 방식을 익혀야 함.
  • 프레임워크 통합 이슈: React에서 Web Component를 사용할 때, props/이벤트 바인딩 등이 번거로울 수 있음.
  • SSR(서버 사이드 렌더링) 난관: Web Component가 클라이언트 사이드에서만 동작할 경우, Nuxt/Next의 SSR과 충돌이 생길 가능성 있음.

5. (참고) Micro-Frontend 접근

개요

  • Vue 기반(Chart)과 React 기반(Next)을 각각 독립된 마이크로 프런트엔드로 구성, 런타임 시 통합.
  • 단순히 컴포넌트 하나가 아니라 각 프로젝트 일부 모듈을 분리하는 수준으로 커지는 경우 고려 가능.

장점

  • 완벽한 독립성: Vue, React 버전 충돌 없이 각 팀/프로젝트가 자유롭게 개발.
  • 확장성: 여러 SPA가 합쳐지는 수준에서도 통합 가능.

단점

  • 구현 복잡도: Webpack 모듈 연합(Module Federation) 등 지식이 필요하며 설정이 어려움.
  • 규모가 큰 프로젝트에만 권장: 단일 컴포넌트를 위해서는 과도한 방식일 수 있음.

권장 시나리오 및 결론

  1. 신속·단기적으로 “React에서도 같은 UI를 빨리 써야 한다”면

    • (2) 각 프레임워크별로 별도 구현을 고려
    • 장기적으로 코드 중복이 아쉽지만, 당장 업무를 빠르게 처리 가능.
  2. 장기 유지보수팀 단위 협업이 중요하다면

    • (3) 독립 라이브러리(패키지) 형태로 빼는 방식을 추천.
    • 가장 유연하면서도 재사용성 높고, Nuxt와 Next 어디에서도 쉽게 import 가능.
  3. “진짜” 프레임워크 독립성과 범용성을 원한다면

    • (4) Web Component(Custom Element) 고려
    • 프레임워크 무관하게 재사용은 가능하나, 이벤트/데이터 바인딩, SSR 등에서 추가 세팅이 필요.
  4. 프로젝트 규모가 크고 마이크로프런트엔드를 검토 중이라면

    • (5) Micro-Frontend 접근도 가능하지만, 단일 컴포넌트 재사용 목적이라면 과도할 수 있음.

추가

  1. Proof of Concept(시작 전 검증)

    • 새롭게 시도할 접근(특히 웹 컴포넌트, 독립 라이브러리)이라면 간단한 예시를 만들어 POC를 진행해보는 것이 좋.
  2. SSR 고려

    • Nuxt와 Next 모두 SSR을 사용하는 경우가 많으므로, 서버 렌더링 시 Chart.js 같은 라이브러리가 어떻게 동작하는지 검토가 필요.
  3. 프로젝트 규모 vs. 유지보수

    • 재사용하고자 하는 컴포넌트의 개수, 난이도, 추후 확장 가능성 등을 고려해 “가장 단순한 방법”을 먼저 시도하는 것도 좋은 방법.
    • 작은 규모라면 (2)번처럼 “각자 구현”이 빠르고 단순하며, 큰 규모라면 (3)번 방식이 나음.

결론

“가장 단순한 방법은 가장 빠른 결과를 내지만, 장기적으로는 중복코드 관리가 어려워질 수 있다.
반대로 재사용성과 확장성을 극대화하려면 빌드·배포 파이프라인 등 초기 비용이 들 수 있다.”
프레임워크 간 컴포넌트 호환성을 다른 각도로 바라본 시각은 [[KnowledgeBase/Blog/잡다한 글/스벨트를 통해 리액트 더 잘 이해하기]]에서 확인할 수 있다.

댓글

첫 번째 댓글을 남겨보세요.