この記事は現在、韓国語のみでご覧いただけます。
BUILT & IMPROVED · 2025.02 — 03
공통 설정을 공유하는 단순한 구조로 시작했지만, Nuxt 런타임과 Storybook의 독립 빌드 환경이 충돌했습니다. 네 가지 대안을 검증한 뒤 패키지별 구성을 선택했습니다.
여러 Nuxt 패키지의 UI를 독립적으로 개발하고 검증할 환경이 필요했습니다. 초기에는 유지보수 비용을 줄이기 위해 모노레포 루트에 Storybook 설정을 두고 모든 패키지가 공유하도록 구성했습니다.
그러나 Storybook은 Nuxt 애플리케이션과 별도로 빌드되기 때문에 Tailwind 설정, 사내 디자인 시스템, Nuxt Auto Imports가 자동으로 이어지지 않았습니다.
편의성만으로 도구를 선택하지 않고, 당시 프로젝트의 pnpm 모노레포 구조에서 실제로 실행되는지 확인했습니다.
Vite 기반 애드온이라 번들러를 webpack에서 Vite로 전환해 적용했지만, 화면이 렌더링되지 않았고 원인을 추적할 단서도 충분하지 않았습니다.
단독 패키지로 구성한 개인 검증용 저장소에서는 정상 동작했지만, 루트의 공통 설정에서 실행하면 메모리 사용량이 급증했습니다. 도구 자체가 아니라 모노레포 루트 구성과의 결합이 원인임을 특정할 수 있었습니다.
타입 정보는 연결할 수 있었지만 Storybook 런타임에는 실제 구현이 주입되지 않아 컴포넌트를 실행할 수 없었습니다.
타입 선언과 번들된 런타임 산출물의 구조가 달라 안정적인 연결 방식으로 사용하기 어려웠습니다.
Nuxt 전용 프레임워크의 단독 패키지 검증은 별도의 개인 저장소를 만들어 진행했습니다. 검증에 사용한 저장소
webpackFinal: async (config) => {
// Storybook 기동 시 .nuxt 폴더를 생성시킨 뒤,
execSync('pnpm run postinstall', {stdio: 'inherit'});
// Nuxt가 만들어 주는 alias를 산출물로 직접 연결
config.resolve.alias = {
...config.resolve.alias,
'#imports': require.resolve('./.nuxt/imports.d.ts'),
'#app': require.resolve('./.nuxt/imports.d.ts'),
};
return config;
};
// 결과: imports.d.ts는 타입 선언뿐이라 구현체가 주입되지 않았고,
// 실제 구현이 있는 dist는 번들·난독화되어 참조할 수 없었다.공통 설정이 주는 관리 편의보다 Nuxt 런타임을 억지로 공유할 때 생기는 결합 비용이 더 크다고 판단했습니다. 설정의 중복을 일부 감수하고, Storybook이 필요한 패키지 안에 설정을 두는 구조로 전환했습니다.
viteFinal: async (config) => {
// Nuxt 가상 모듈은 Vite 사전 번들링에서 제외해야 동작한다
config.optimizeDeps = {
...config.optimizeDeps,
include: ['vue', 'vue-router'],
exclude: ['#build', '#internal'],
};
// node_modules에 실체가 없는 vue-docgen-plugin이
// 에러를 일으켜 플러그인 목록에서 직접 제거
const index = config.plugins.findIndex(
({name}) => name === 'storybook:vue-docgen-plugin',
);
if (index !== -1) config.plugins.splice(index, 1);
return config;
},import {stds} from '@stove-ui/vue';
// 디자인 시스템이 export하는 breakpoint 토큰을 그대로 순회해
// 뷰포트 프리셋을 생성 — 토큰이 바뀌면 Storybook도 함께 바뀐다
export const viewport = {
viewports: Object.fromEntries(
Object.entries(stds.glob.breakpoint).map(([breakpoint, width]) => [
breakpoint,
{name: `breakpoint.${breakpoint}`, styles: {width, height: '800px'}},
]),
),
};전환 후에도 일부 데이터 로직이 Storybook에서만 동작하지 않는 이슈가 남았지만, 이를 고치는 대신 리뷰 논의를 통해 Storybook의 책임을 UI·스타일·Props·이벤트 검증까지로 합의하고 데이터 로직 재현은 범위에서 제외했습니다.
이 작업을 통해 ‘설정을 얼마나 많이 공유하는가’보다 ‘각 도구가 기대하는 실행 경계를 얼마나 명확하게 지키는가’가 모노레포의 유지보수성에 더 중요할 수 있음을 배웠습니다.