6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

『Viteで環境構築』 Vue3, TypeScript, Vuetify, StoryBook

Posted at

はじめに

npm create vuetify@latestを使わずにviteを利用してvue3 vuetifyの環境を作成し、StoryBookを追加します。

Vueプロジェクトの作成

1 vue projectの作成

$ npm create vite@latest
  - Vue → TypeScript

VueとVuetifyの統合

1 vuetifyのinstall
『Vuetify公式』 既存プロジェクトへの導入

$ npm install vuetify

2 vite-plugin-vuetifyのinstall
『Vuetify公式』 TreeShaking(不要コードの削除)
『npm』vite-plugin-vuetify

$ npm i vite-plugin-vuetify

3 fileを変更

3-1 Vueアプリケーションを作成するファイルに以下を追加 (main.ts) (createAppするところ)

import { createApp } from 'vue'

// Vuetify
import 'vuetify/styles'
import { createVuetify } from 'vuetify'

// Components
import App from './App.vue'

const vuetify = createVuetify()

createApp(App).use(vuetify).mount('#app')

3-2 vite.config.ts

import vue from '@vitejs/plugin-vue'
import vuetify from 'vite-plugin-vuetify'

export default {
  plugins: [
    vue(),
    vuetify(), // vue()の後ろに設定すること
  ],
}

error解決

main.tsのimport 'vuetify/styles'で『モジュール 'vuetify/styles' またはそれに対応する型宣言が見つかりません。』というerrorが発生する方がいるかもしれません。
副作用の発生するかもしれないimportを警告する機能がONになっているのが原因です

解決策1: インラインでnoUncheckedSideEffectImportsのルールを無効化する

// @ts-expect-error -- side effects import
import 'vuetify/styles'

解決策2: tsconfig.app.json"noUncheckedSideEffectImports": trueのルールを削除する

{
...
// 以下を消す
"noUncheckedSideEffectImports": true
...
}

4 お好みで
Iconを使う場合はinstall
Sass変数を利用してVuetifyのデフォルトスタイルをカスタマイズ

5 App.vueで動作確認
styleの当たったchipが表示されれば成功です

<v-chip>Chip Component</v-chip>

StoryBook

1 rootディレクトリで以下を実行 (自動で必要な初期設定をやってくれる)
『StoryBook公式』 StoryBook with Vite

$ npx storybook@latest init

2 vuetify componentを使えるように設定する
『StoryBook公式』 VuetifyとStorybookを統合する

2-1 StoryBookにVuetifyを登録
今回の作成方法だとregisterPlugins関数を使用していないので、公式ページの例と若干違います

// .storybook/preview.ts

// 追加
import { setup } from "@storybook/vue3";
import "vuetify/styles";
import { createVuetify } from "vuetify";

...

// 追加
setup((app) => {
  const vuetify = createVuetify();
  app.use(vuetify);
});

2-2 ストーリーラッパーコンポーネントの作成
storybookでvuetifyを扱うには<v-app></v-app>でラップする必要があります。

<!-- .storybook/StoryWrapper.vue -->
 
<template>
  <v-app>
    <v-main>
      <slot name="story"></slot>
    </v-main>
  </v-app>
</template>


// 公式では記載されていませんが、 setup lang="ts"を記述しないと後にimportした際にtsのerrorが表示されました
// 公式はtsではなくjsを前提に解説されています
<script setup lang="ts"></script>

2-3 .withVuetifyThemeデコレータを作成する

// .storybook/withVeutifyTheme.decorator.ts

import { h } from 'vue';
// ここでtsのerrorが出る場合はStoryWrapper.vueでsetupやlang="ts"を記述してみてください
import StoryWrapper from './StoryWrapper.vue';

export const withVuetifyTheme = (storyFn, context) => {
  const story = storyFn();

  return () => {
    return h(
      StoryWrapper,
      {}, // Props for StoryWrapper
      {
        // Puts your story into StoryWrapper's "story" slot with your story args
        story: () => h(story, { ...context.args }),
      }
    );
  };
};

2-4 作成したでコレータをpreview.jsのStorybookに渡す

// 追加
import { withVuetifyTheme } from "./withVuetifyTheme.decorator";

// 追加
export const decorators = [withVuetifyTheme];

最終的なprevie.ts
初期設定で生成されたコードも含めると以下のようになります。

import type { Preview } from "@storybook/vue3";

// 以下importは全部追加したコード
import { setup } from "@storybook/vue3";
import "vuetify/styles";
import { createVuetify } from "vuetify";
import { withVuetifyTheme } from "./withVuetifyTheme.decorator";

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
};

// 追加したコード
setup((app) => {
  const vuetify = createVuetify();
  app.use(vuetify);
});

export default preview;

// 追加したコード
export const decorators = [withVuetifyTheme];

動作確認

1 適当にお好きなコンポーネントを作成

// src/components/BaseChip.vue
<script setup lang="ts">
withDefaults(
  defineProps<{
    color?: string;
    closable?: true;
    onClick?: () => void;
    onClickClose?: () => void;
  }>(),
  {
    color: "primary",
    onClick: undefined,
    onClickClose: undefined,
  }
);
</script>

<template>
  <v-chip
    :color="color"
    @onClick="onClick"
    @click:close="onClickClose"
    :closable="closable"
>      
    <slot></slot>
  </v-chip>
</template>

2 簡易的ですが表示確認用のStoryを作成

// src/components/BaseChip.stories.ts

import type { Meta, StoryObj } from "@storybook/vue3";

import BaseChip from "./BaseChip.vue";

const meta: Meta<typeof BaseChip> = {
  title: "BaseChip",
  component: BaseChip,
  argTypes: {
    color: {
      options: ["primary", "secondary", "success", "error", "warning"],
      control: { type: "select" },
    },
  },
};

export default meta;
type Story = StoryObj<typeof BaseChip>;

export const Primary: Story = {
  args: {
    default: "IT事業促進部",
    color: "primary",
  },
};

おわりに

1 モチベーション
tsconfig.app.jsonの初期設定はviteでの始め方によって設定がまちまちです。
当記事投稿時点ではnpm crreate vite@latestvuetypescripで作成するとnoUncheckedSideEffectImports": trueが含まれており上記errorが発生します。
実際にはPrettier, EsLint, Vue-Routerを使いたいケースがほとんどだと思うので、Vue → Customize with create-vueで作成するとtsconfig.app.jsonにnoUncheckedSideEffectImports": trueが含まれませんので、当エラーは発生しません。 加えてvuetify公式で紹介されているnpm create vuetify@latestを使った場合も発生しませんので、そちらの利用を検討するのも良いでしょう。 npm create vuetify@latestを利用する場合、当記事で紹介した設定以外にも様々設定が加えられ、最適化されているようです。

当記事は学習目的でvuetypescripでプロジェクトを開始した際に上記でハマったのが投稿のモチベーションだったりします。

2 小話
Vue x StoryBookは環境構築が難しいと聞いたことがあるのですが、だいぶやりやすくなっているみたいです。先人達に感謝です。

参考

Vuetify

『Vuetify公式』プロジェクトへの導入
https://vuetifyjs.com/ja/getting-started/installation/#section-30a430f330b930c830fc30eb

『Vuetify公式』 不要コードの削除(Tree Shaking)
https://vuetifyjs.com/ja/features/treeshaking/

『NPM』 vite-plugin-vuetify
https://www.npmjs.com/package/vite-plugin-vuetify

StoryBook

『StoryBook公式』 VuetifyとStorybookを統合する
https://storybook.js.org/recipes/vuetify

『StoryBook公式』 StoryBook with Vite
https://storybook.js.org/docs/get-started/frameworks/vue3-vite?renderer=vue

『StoryBook公式』 StoryBook Component Vue
https://storybook.js.org/docs/get-started/frameworks/vue3-vite?renderer=vue

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?