Storybook × Nuxt/SvelteKit/VitePress:マルチフレームワーク併用の初期配線
モダンなフロントエンド開発では、単一のプロジェクトで複数のフレームワークを使い分けるケースが増えています。アプリケーション本体は Nuxt で構築し、ドキュメントサイトは VitePress、そしてコンポーネントカタログは Storybook で管理する、といった具合です。
この記事では、Storybook 環境に複数のフレームワーク(Nuxt、SvelteKit、VitePress)を併用して配置する際の初期設定手順と、それぞれのフレームワークを共存させるための配線方法を解説します。マルチフレームワーク構成の第一歩として、プロジェクトの土台作りに焦点を当ててご紹介しましょう。
背景
マルチフレームワーク構成の需要
近年のフロントエンド開発では、目的に応じて最適なフレームワークを選択するアプローチが一般的になっています。
たとえば、以下のような使い分けが考えられます:
| # | 用途 | フレームワーク | 理由 |
|---|---|---|---|
| 1 | アプリケーション本体 | Nuxt | SSR/SSG に強く、Vue.js エコシステムが充実 |
| 2 | 管理画面・ダッシュボード | SvelteKit | 軽量で高速、シンプルな記述が可能 |
| 3 | ドキュメントサイト | VitePress | Markdown ベースで簡単に構築できる |
| 4 | コンポーネントカタログ | Storybook | UI コンポーネントの開発・テスト・ドキュメント化 |
このような構成を採用すると、それぞれの強みを活かしながら、開発効率と保守性を両立できるのです。
Storybook の役割
Storybook は、UI コンポーネントを独立した環境で開発・テスト・ドキュメント化するためのツールです。複数のフレームワークで構築されたコンポーネントを一元管理できるため、マルチフレームワーク構成において中心的な役割を果たします。
以下の図は、Storybook を中心としたマルチフレームワーク構成の概要を示しています。
mermaidflowchart TB
dev["開発者"] -->|コンポーネント開発| sb["Storybook<br/>統合環境"]
sb -->|Nuxt用| nuxt["Nuxt アプリ"]
sb -->|SvelteKit用| svelte["SvelteKit 管理画面"]
sb -->|VitePress用| vite["VitePress ドキュメント"]
nuxt -->|共有コンポーネント| shared[("共有ライブラリ")]
svelte -->|共有コンポーネント| shared
vite -->|共有コンポーネント| shared
Storybook が各フレームワークのコンポーネントを統合管理し、共有ライブラリとして再利用可能な形で提供します。この構成により、コンポーネントの一貫性を保ちながら、フレームワーク固有の最適化も実現できるわけですね。
課題
マルチフレームワーク併用時の技術的課題
複数のフレームワークを Storybook で管理する際、以下のような課題に直面します。
ビルドツールとバンドラーの競合
各フレームワークは独自のビルドツール(Vite、Webpack、Rollup など)を使用しています。これらを 1 つの Storybook プロジェクトで共存させるには、設定の調整が必要です。
依存関係の管理
Nuxt、SvelteKit、VitePress はそれぞれ異なる依存パッケージを必要とします。バージョンの競合や重複を避けながら、すべてのフレームワークが正常に動作する環境を構築しなければなりません。
TypeScript 設定の統一
フレームワークごとに TypeScript の設定(tsconfig.json)が異なる場合、型定義の整合性を保つのが難しくなります。
以下の図は、マルチフレームワーク構成における主な課題を示しています。
mermaidflowchart LR
issues["マルチフレームワーク<br/>併用時の課題"]
issues -->|課題1| build["ビルドツール<br/>の競合"]
issues -->|課題2| deps["依存関係<br/>管理の複雑化"]
issues -->|課題3| types["TypeScript設定<br/>の不整合"]
build -->|解決策| vite_main["Vite統一化"]
deps -->|解決策| yarn_ws["Yarn Workspaces"]
types -->|解決策| shared_config["共通tsconfig"]
これらの課題を適切に解決することで、スムーズなマルチフレームワーク開発環境が実現します。
解決策
モノレポ構成によるプロジェクト管理
マルチフレームワーク構成を管理する最も効果的な方法は、モノレポ(monorepo)アーキテクチャの採用です。Yarn Workspaces を使用することで、複数のフレームワークを 1 つのリポジトリで効率的に管理できます。
プロジェクト構成の全体像
まず、推奨されるディレクトリ構成を確認しましょう。
csharpproject-root/
├── package.json # ルートパッケージ設定
├── yarn.lock # 依存関係ロックファイル
├── .storybook/ # Storybook共通設定
│ ├── main.ts
│ └── preview.ts
├── packages/
│ ├── nuxt-app/ # Nuxtアプリケーション
│ │ ├── package.json
│ │ ├── nuxt.config.ts
│ │ └── components/
│ ├── sveltekit-app/ # SvelteKitアプリケーション
│ │ ├── package.json
│ │ ├── svelte.config.js
│ │ └── src/lib/
│ ├── vitepress-docs/ # VitePressドキュメント
│ │ ├── package.json
│ │ ├── .vitepress/
│ │ └── docs/
│ └── shared/ # 共有コンポーネント・ユーティリティ
│ ├── package.json
│ ├── components/
│ └── utils/
└── tsconfig.base.json # TypeScript共通設定
この構成により、各フレームワークを独立したパッケージとして管理しつつ、共通の依存関係やツールを効率的に共有できます。
Yarn Workspaces の設定
プロジェクトルートに配置する package.json で、Yarn Workspaces を有効化します。
json{
"name": "multi-framework-storybook",
"private": true,
"workspaces": ["packages/*"],
"scripts": {
"dev": "yarn workspace @app/nuxt-app dev",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
}
}
workspacesフィールドにpackages/*を指定することで、packages ディレクトリ配下のすべてのサブディレクトリがワークスペースとして認識されます。これにより、各パッケージ間で依存関係を簡単に共有できるのです。
具体例
ステップ 1:プロジェクトの初期化
まず、プロジェクトのルートディレクトリを作成し、Yarn Workspaces を初期化しましょう。
bashmkdir multi-framework-storybook
cd multi-framework-storybook
yarn init -y
次に、ルートの package.json を編集してワークスペースを有効化します。
json{
"name": "multi-framework-storybook",
"version": "1.0.0",
"private": true,
"workspaces": ["packages/*"]
}
private: trueを設定することで、このルートパッケージが npm レジストリに公開されないようにします。ワークスペース構成では必須の設定ですね。
ステップ 2:Storybook の導入
プロジェクトルートで Storybook を初期化します。
bashnpx storybook@latest init --type vue3
Storybook のインストールが完了したら、マルチフレームワークに対応できるように設定を調整します。
.storybook/main.ts を以下のように設定しましょう。
typescriptimport type { StorybookConfig } from '@storybook/vue3-vite';
const config: StorybookConfig = {
// Storiesの検索パターンを複数フレームワークに対応
stories: [
'../packages/nuxt-app/**/*.stories.@(js|jsx|ts|tsx)',
'../packages/sveltekit-app/**/*.stories.@(js|jsx|ts|tsx)',
'../packages/shared/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/vue3-vite',
options: {},
},
};
export default config;
stories配列に複数のパッケージディレクトリを指定することで、各フレームワークのストーリーファイルを自動的に読み込めます。
ステップ 3:Nuxt アプリケーションの追加
packages ディレクトリ配下に Nuxt アプリケーションを作成します。
bashmkdir -p packages/nuxt-app
cd packages/nuxt-app
npx nuxi init .
Nuxt の初期化が完了したら、package.json にワークスペース用の名前を設定しましょう。
json{
"name": "@app/nuxt-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate"
}
}
@app/nuxt-appというスコープ付きの名前を使用することで、ワークスペース内での識別が明確になります。
次に、Nuxt コンポーネント用の Storybook ストーリーを作成します。
Nuxt コンポーネントの作成
components/HelloWorld.vue を作成しましょう。
vue<template>
<div class="hello-world">
<h1>{{ message }}</h1>
<p>{{ description }}</p>
</div>
</template>
<script setup lang="ts">
// Propsの型定義
interface Props {
message: string;
description?: string;
}
// デフォルト値を持つPropsの定義
withDefaults(defineProps<Props>(), {
description: 'Nuxtで構築されたコンポーネントです',
});
</script>
このコンポーネントは、メッセージと説明文を表示するシンプルなコンポーネントです。TypeScript の型定義も含めているため、型安全性が確保されます。
Storybook ストーリーの作成
components/HelloWorld.stories.ts を作成します。
typescriptimport type { Meta, StoryObj } from '@storybook/vue3';
import HelloWorld from './HelloWorld.vue';
// メタデータの定義
const meta: Meta<typeof HelloWorld> = {
title: 'Nuxt/HelloWorld',
component: HelloWorld,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof HelloWorld>;
メタデータでは、ストーリーのタイトルやコンポーネント、自動ドキュメント生成のタグを設定しています。titleにNuxt/というプレフィックスを付けることで、Storybook 上でフレームワークごとに分類されるのです。
次に、具体的なストーリーを定義しましょう。
typescript// デフォルトストーリー
export const Default: Story = {
args: {
message: 'こんにちは、Nuxtの世界へ!',
},
};
// カスタムストーリー
export const WithCustomDescription: Story = {
args: {
message: 'Nuxt × Storybook',
description:
'マルチフレームワーク構成でコンポーネントを管理しています',
},
};
複数のストーリーを定義することで、コンポーネントの様々な状態を視覚的に確認できます。
ステップ 4:SvelteKit アプリケーションの追加
続いて、SvelteKit アプリケーションを packages ディレクトリに追加します。
bashcd ../../
mkdir -p packages/sveltekit-app
cd packages/sveltekit-app
yarn create svelte@latest .
対話形式のプロンプトでは、以下のように選択しましょう:
- Skeleton project を選択
- TypeScript を有効化
- ESLint、Prettier などのツールを必要に応じて追加
SvelteKit の初期化が完了したら、package.json を編集します。
json{
"name": "@app/sveltekit-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
}
}
SvelteKit コンポーネントの作成
src/lib/components/Counter.svelte を作成しましょう。
svelte<script lang="ts">
// カウンターの状態管理
let count = 0;
// カウントアップ関数
function increment() {
count += 1;
}
// カウントダウン関数
function decrement() {
count -= 1;
}
// リセット関数
function reset() {
count = 0;
}
</script>
<div class="counter">
<h2>カウンター: {count}</h2>
<div class="buttons">
<button on:click={increment}>+1</button>
<button on:click={decrement}>-1</button>
<button on:click={reset}>リセット</button>
</div>
</div>
Svelte のリアクティブシステムを活用した、シンプルなカウンターコンポーネントです。状態管理がとても直感的で理解しやすいのが特徴ですね。
Storybook ストーリーの作成
src/lib/components/Counter.stories.ts を作成します。
typescriptimport type { Meta, StoryObj } from '@storybook/svelte';
import Counter from './Counter.svelte';
const meta: Meta<typeof Counter> = {
title: 'SvelteKit/Counter',
component: Counter,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof Counter>;
SvelteKit 用のストーリーでは、@storybook/svelteを使用します。Nuxt と同様に、タイトルにフレームワーク名を含めることで分類します。
typescriptexport const Default: Story = {};
カウンターコンポーネントは Props を受け取らないため、デフォルトストーリーは空のオブジェクトで十分です。
ステップ 5:VitePress ドキュメントの追加
最後に、VitePress によるドキュメントサイトを追加しましょう。
bashcd ../../
mkdir -p packages/vitepress-docs
cd packages/vitepress-docs
yarn init -y
yarn add -D vitepress vue
package.json にスクリプトを追加します。
json{
"name": "@app/vitepress-docs",
"version": "1.0.0",
"private": true,
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
"devDependencies": {
"vitepress": "^1.0.0",
"vue": "^3.4.0"
}
}
VitePress 設定ファイルの作成
.vitepress/config.ts を作成し、基本設定を行います。
typescriptimport { defineConfig } from 'vitepress';
export default defineConfig({
title: 'マルチフレームワーク ドキュメント',
description:
'Nuxt、SvelteKit、VitePressの統合ドキュメント',
themeConfig: {
nav: [
{ text: 'ホーム', link: '/' },
{ text: 'ガイド', link: '/guide/' },
{ text: 'コンポーネント', link: '/components/' },
],
},
});
この設定により、ナビゲーションメニューが表示され、各セクションへのアクセスが容易になります。
次に、サイドバーの設定を追加しましょう。
typescriptexport default defineConfig({
// ... 前述の設定
themeConfig: {
// ... nav設定
sidebar: [
{
text: 'はじめに',
items: [
{ text: '概要', link: '/guide/' },
{ text: 'セットアップ', link: '/guide/setup' },
],
},
{
text: 'コンポーネント',
items: [
{ text: 'Nuxt', link: '/components/nuxt' },
{ text: 'SvelteKit', link: '/components/svelte' },
],
},
],
},
});
サイドバー設定により、ドキュメントの構造が明確になり、ユーザーが必要な情報を素早く見つけられます。
ドキュメントページの作成
docs/index.md を作成し、トップページを作成します。
markdown# マルチフレームワーク構成へようこそ
このプロジェクトでは、Nuxt、SvelteKit、VitePress を組み合わせた
マルチフレームワーク構成を採用しています。
# 特徴
- **Nuxt**: アプリケーション本体の構築
- **SvelteKit**: 管理画面やダッシュボード
- **VitePress**: ドキュメントサイト
- **Storybook**: コンポーネントカタログ
各フレームワークの強みを活かした、効率的な開発環境です。
Markdown 形式でドキュメントを記述できるため、技術ドキュメントの作成が非常に簡単ですね。
ステップ 6:TypeScript 共通設定の作成
プロジェクトルートに tsconfig.base.json を作成し、共通の TypeScript 設定を定義します。
json{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true
}
}
この基本設定により、型チェックの厳密性と互換性が確保されます。各フレームワークの tsconfig.json では、この設定を継承することで一貫性を保てるのです。
各パッケージの tsconfig.json で基本設定を継承しましょう。
Nuxt の tsconfig.json
packages/nuxt-app/tsconfig.json を作成します。
json{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["@nuxt/types"]
}
}
SvelteKit の tsconfig.json
packages/sveltekit-app/tsconfig.json を編集します。
json{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["vite/client", "@sveltejs/kit"]
},
"include": ["src/**/*.ts", "src/**/*.svelte"]
}
これにより、すべてのフレームワークで一貫した TypeScript 設定が適用されます。
ステップ 7:Storybook の起動と動作確認
すべての設定が完了したら、Storybook を起動して動作を確認しましょう。
bashcd /path/to/project-root
yarn storybook
Storybook が起動すると、ブラウザでhttp://localhost:6006にアクセスできます。サイドバーには以下のように各フレームワークのコンポーネントが分類表示されるはずです:
| # | カテゴリ | コンポーネント | フレームワーク |
|---|---|---|---|
| 1 | Nuxt | HelloWorld | Vue 3 / Nuxt |
| 2 | SvelteKit | Counter | Svelte / SvelteKit |
以下の図は、Storybook を中心とした開発フローを示しています。
mermaidsequenceDiagram
participant Dev as 開発者
participant SB as Storybook
participant Nuxt as Nuxt コンポーネント
participant Svelte as SvelteKit コンポーネント
Dev->>SB: yarn storybook
SB->>SB: ビルド設定読み込み
SB->>Nuxt: ストーリー検索
Nuxt-->>SB: HelloWorld.stories.ts
SB->>Svelte: ストーリー検索
Svelte-->>SB: Counter.stories.ts
SB->>Dev: localhost:6006 起動完了
Dev->>SB: コンポーネント選択
SB->>Dev: プレビュー表示
開発者が Storybook を起動すると、各フレームワークのストーリーが自動的に読み込まれ、統合された UI で閲覧できます。コンポーネントの開発と確認がとてもスムーズになるわけです。
ステップ 8:共有コンポーネントライブラリの作成
複数のフレームワークで再利用可能な共有コンポーネントを管理するため、shared パッケージを作成します。
bashmkdir -p packages/shared
cd packages/shared
yarn init -y
package.json を編集します。
json{
"name": "@app/shared",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}
exportsフィールドを使用することで、ES モジュールとしてパッケージをエクスポートできます。
共有ユーティリティ関数の作成
utils/format.ts を作成し、共通のユーティリティ関数を定義しましょう。
typescript/**
* 日付を指定フォーマットで文字列に変換
*/
export function formatDate(
date: Date,
format: string = 'YYYY-MM-DD'
): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(
2,
'0'
);
const day = String(date.getDate()).padStart(2, '0');
return format
.replace('YYYY', String(year))
.replace('MM', month)
.replace('DD', day);
}
この関数は、各フレームワークから共通して利用できる日付フォーマット機能を提供します。
次に、数値フォーマット関数も追加しましょう。
typescript/**
* 数値をカンマ区切りの文字列に変換
*/
export function formatNumber(num: number): string {
return num.toLocaleString('ja-JP');
}
utils/index.ts でエクスポートします。
typescriptexport { formatDate, formatNumber } from './format';
これらのユーティリティ関数は、Nuxt でも SvelteKit でも同じように利用できるため、コードの重複を避けられます。
動作確認のポイント
マルチフレームワーク構成が正しく動作しているか、以下の点を確認しましょう:
| # | 確認項目 | 期待される結果 |
|---|---|---|
| 1 | Storybook の起動 | エラーなく起動し、localhost:6006 にアクセス可能 |
| 2 | Nuxt ストーリー表示 | HelloWorld コンポーネントが正しくレンダリングされる |
| 3 | SvelteKit ストーリー表示 | Counter コンポーネントが動作し、カウントが増減する |
| 4 | 型チェック | yarn tsc でエラーが発生しない |
| 5 | ホットリロード | コンポーネント編集時に自動更新される |
これらすべてが正常に動作すれば、マルチフレームワーク併用の初期配線は完了です。
まとめ
本記事では、Storybook を中心としたマルチフレームワーク(Nuxt、SvelteKit、VitePress)併用環境の構築手順を解説しました。
重要なポイントをおさらいしましょう:
環境構築の要点
- Yarn Workspaces を使用したモノレポ構成により、複数のフレームワークを効率的に管理
- Storybook の設定で各フレームワークのストーリーパスを指定し、統合的なコンポーネントカタログを実現
- 共通の TypeScript 設定を継承することで、型安全性と一貫性を確保
各フレームワークの役割
- Nuxt はアプリケーション本体の構築に適しており、SSR/SSG の強みを活かせる
- SvelteKit は軽量で高速な管理画面構築に最適
- VitePress は Markdown ベースのドキュメントを簡単に作成できる
- Storybook はすべてのコンポーネントを一元管理し、開発効率を向上させる
この初期配線を土台として、各フレームワークの特性を活かした開発を進められます。コンポーネントの共有やスタイルの統一、状態管理の最適化など、さらなる発展的な実装にも対応可能です。
マルチフレームワーク構成は、一見複雑に思えるかもしれませんが、適切な設定と構造化により、各技術の利点を最大限に引き出せる強力なアプローチになります。ぜひ、この記事を参考に、プロジェクトに最適な構成を見つけてください。
関連リンク
articleStorybook × Nuxt/SvelteKit/VitePress:マルチフレームワーク併用の初期配線
articleStorybook で Zustand をモックする:Controls 連動とシナリオ駆動 UI
articleStorybook 代替ツール比較:Ladle/Histoire/Pattern Lab と何が違う?
articleStorybook の HMR が遅い問題を撃退:大型プロジェクト最適化の実践手順
articleStorybook で“仕様が生きる”開発:ドキュメント駆動 UI の実践ロードマップ
articleStorybook リリース運用:Changesets とバージョン別ドキュメントの整備術
articleDeno/Bun/Node のランタイムで共通動く Zod 環境のセットアップ
articleFFmpeg マッピング完全攻略:-map/-disposition/-metadata の黄金レシピ
articleYarn PnP で「モジュールが見つからない」時の解決大全:packageExtensions/patch で対処
articleESLint no-restricted-* 活用レシピ集:API 禁止・依存制限・危険パターン封じ込め
articleWeb Components のポリフィル戦略:@webcomponents 系を最小限で入れる判断基準
articleDify ワークフロー定型 30:分岐・並列・リトライ・サーキットブレーカの型
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来