投稿日: 2024年11月20日
※ここではソースディレクトリをデフォルトのルートディレクトリからsrcディレクトリに変更している想定としています。
・Nuxt.js: 3.14.159
・Storybook: 8.4.4
・unplugin-vue-components: 0.27.4
・unplugin-auto-import: 0.8.15
1. Nuxtプロジェクトのルートディレクトリで以下のコマンドを入力し、Storybook 8をインストールします。
$ npx storybook@latest init --type vue3 --builder vite
Need to install the following packages:
storybook@8.4.4
Ok to proceed? (y) y
※インストール完了後に自動生成されたstoriesディレクトリの中にあるサンプルファイルをすべて削除しておきます。
2. package.jsonに以下を追加します。
"scripts": {
"storybook": "storybook dev -p 6006",
},
3. vite.config.tsに以下を追加して保存します。
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
});
※Storybook 7ではViteプラグインの設定を自動で行っていましたが Storybook 8ではvite.config.tsに明示的に追加する必要があります。詳細は以下を参照ください。
https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#framework-specific-vite-plugins-have-to-be-explicitly-added
4. pages/index.vueを以下の内容で修正します。
<template>
<div>
<h1>Index.vue</h1>
</div>
</template>
5. stories/index.stories.tsを新規作成し、以下の内容で保存します。
import type { Meta, StoryObj } from '@storybook/vue3'
import Index from '../pages/index.vue'
type Story = StoryObj<typeof Index>
const meta: Meta<typeof Index> = {
title: 'Index',
}
export const Default: Story = {
render: () => ({
components: { Index },
template: '<Index />',
}),
}
export default meta
6. 以下のコマンドを実行します。
$ npm run storybook
7. 以下のURLにアクセスします。Storybookのダッシュボードの左側にIndexが表示されており、選択した場合にIndex.vueファイルの内容が表示されていることを確認します。
http://localhost:6006/
1. 以下のコマンドを入力してNuxtのStorybookプラグインをインストールします。
$ npx nuxi@latest module add storybook
2. nuxt.config.tsに以下を追加します。
export default defineNuxtConfig({
modules: ['@nuxtjs/storybook'],
// nuxt.config.tsでStorybookの設定ができます。設定できる項目は以下を参照ください。
// https://storybook.nuxtjs.org/getting-started/options
storybook: {
host: 'http://localhost',
port: 6006,
},
})
3. 以下のコマンドを入力してNuxtを起動します。3000番ポートでNuxtが起動し、6006番ポートでStorybookが起動していることを確認します。
$ npm run dev
> dev
> nuxt dev
Nuxt 3.14.159 with Nitro 2.10.4
➜ Local: http://localhost:3000/
➜ Network: use --host to expose
➜ DevTools: press Shift + Alt + D in the browser (v1.6.0)
➜ Storybook: http://localhost:6006/
4. 以下のURLにアクセスします。Storybookのダッシュボードが表示されていることを確認します。
http://localhost:6006/
1. main.jsとpreview.jsのファイルの拡張子をtsに修正します。
2. main.tsを以下の内容で保存します。
import type { StorybookConfig } from '@storybook/vue3-vite'
const config: StorybookConfig = {
stories: [
'../stories/**/*.mdx',
'../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
// ソースディレクトリをデフォルトのルートからsrcに変更している場合は以下を設定します。
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'
],
addons: [
'@storybook/addon-onboarding',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/vue3-vite',
options: {},
},
};
export default config
※修正前は以下になります。
/** @type { import('@storybook/vue3-vite').StorybookConfig } */
const config = {
stories: [
'../stories/**/*.mdx',
'../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-onboarding',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/vue3-vite',
options: {},
},
};
export default config
3. preview.tsを以下の内容で保存します。
import type { Preview } from '@storybook/vue3'
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview
※修正前
/** @type { import('@storybook/vue3').Preview } */
const preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview
import { foo } from '~/bar'
TypeError: Failed to fetch dynamically imported module:
1. .storybook/main.tsに以下を追加して保存します。
import type { StorybookConfig } from '@storybook/vue3-vite'
import path from 'path'
const config: StorybookConfig = {
// 以下を追加
viteFinal: async (config) => {
if (config?.resolve?.alias) {
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, '../src'),
'~': path.resolve(__dirname, '../src'),
}
}
return config
},
};
※上記はエイリアスとして「@」と「~」を追加しています。ソースディレクトリは「src」を想定しています。
1. 以下のコマンドを入力し、ライブラリをインストールします。
$ npm install --save-dev unplugin-auto-import
$ npm install --save-dev unplugin-vue-components
2. .storybook/main.tsに以下を追加して保存します。
import type { StorybookConfig } from '@storybook/vue3-vite'
import AutoImportFunctions from 'unplugin-auto-import/vite'
import AutoImportComponents from 'unplugin-vue-components/vite'
import path from 'path'
const config: StorybookConfig = {
viteFinal: async (config) => {
// 以下を追加
if (config?.plugins) {
config.plugins.push(
// プリセットでvueやvee-validateなどが指定できます。
// 指定できるプリセットは以下を参照ください。
// https://github.com/unplugin/unplugin-auto-import/tree/main/src/presets
AutoImportFunctions ({ imports: [
'vue',
'vee-validate',
'vue-router',
'pinia',
], dts: '.storybook/auto-imports.d.ts' }),
)
config.plugins.push(
AutoImportComponents({
// ソースディレクトリは「src」を想定しています。
// ソースディレクトリがデフォルトの場合はdirs: ['components'],としてください。
dirs: ['src/components'],
dts: '.storybook/components.d.ts',
}),
)
}
return config
},
}
export default config
3. components/button.vueを作成して以下の内容で保存します。
<template>
<input type='text'>
</template>
4. pages/index.vueを以下の内容で保存します。
<script setup lang='ts'>
// nuxt 3が自動インポートする関数
const foo = ref('foo')
</script>
<template>
<div>
<h1>Index.vue</h1>
<!-- nuxt 3が自動インポートするコンポーネント -->
<Button />
{{ foo }}
</div>
</template>
5. 以下のコマンドを入力して、Storybookを起動します。
$ npm run storybook
6. 以下のURLにアクセスします。画面にrefの値(foo)とコンポーネント(inputタグ)が表示されていることを確認します。
http://localhost:6006/?path=/story/index--default
"getActivePinia()" was called but there was no active Pinia.
Are you trying to use a store before calling "app.use(pinia)"?
// .storybook/preview.ts
import { type Preview, setup } from '@storybook/vue3'
import { type App } from 'vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
setup((app: App) => {
app.use(pinia)
})
※Piniaを利用していない場合はこの手順はスキップ可能です。
Error: No such validator 'XXXX' exists.
// .storybook/preview.ts
import { localize } from '@vee-validate/i18n'
import ja from '@vee-validate/i18n/dist/locale/ja.json'
import { all } from '@vee-validate/rules'
import { defineRule, configure } from 'vee-validate'
configure({
generateMessage: localize({ ja }),
})
Object.entries(all).forEach(([name, rule]) => {
// 全バリデーションルールの読み込み
defineRule(name, rule)
})
※Vee-Validateを利用していない場合はこの手順はスキップ可能です。
以上で全ての手順は完了になります