Open8

Vite, Vue3, TypeScript, Tailwind CSS, Storybook な構成を作りたかった

ooharabucyouooharabucyou

結論から言うと、storybook を入れるのには失敗している (一旦諦めた)
-> やっぱりうまくいった (2021/11/21)

ooharabucyouooharabucyou

まずは、テンプレートからプロジェクト作成

yarn create vite vite-vue -- --template vue-ts
ooharabucyouooharabucyou

パッケージインストール

cd vite-vue
yarn install

そして、開発環境が起動するか確認

yarn run dev

開発用のサーバが起動する

  vite v2.6.7 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 433ms.
ooharabucyouooharabucyou

次に、Tailwind CSS に対応する

パッケージをインストール

 yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest

Tailwind用のファイルを用意する

npx tailwindcss init -p

src/index.css を作成して以下を記載

src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;

src/main.ts に以下を記載する

src/main.ts
import './index.css'

これで、Tailwind CSS が動作する状態になる。
試しに、src/App.vue などを編集してみる。

src/App.vue
<script setup lang="ts">
</script>

<template>
    <div class="text-xl">Hello</div>
</template>

この状態でも動作するが、この状態だとビルド (yarn run build) した場合に、以下のメッセージが出てしまう。

warn - Tailwind is not purging unused styles because no template paths have been provided.
warn - If you have manually configured PurgeCSS outside of Tailwind or are deliberately not removing unused styles, set `purge: false` in your Tailwind config file to silence this warning.
warn - https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css

tailwind.config.js を少し直す

- purge: []
+ purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}']
ooharabucyouooharabucyou

軽く SPA なアプリを作る前提にしたいが、vue-router を入れて、いちいち routes を書いていくのは面倒くさい。vite-plugin-pages を入れる。
これは、Nuxt.js のように、src/pages 配下に、特定のルールに従って、ファイルを配置するだけで route を作ってくれるスグレモノだ。

yarn add  -D vite-plugin-pages
yarn add vue-router@next

vite-plugin-page をプラグインとして指定

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import pages from 'vite-plugin-pages'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), pages()]
})

型のために以下を src/env.d.ts に追加

src/env.d.ts
/// <reference types="vite-plugin-pages/client" />

routes について、'pages-generated' が作ってくれるので main.ts で、それを呼び出して、routes として指定する。

src/main.ts
import {createApp} from 'vue'
import {createRouter, createWebHistory} from 'vue-router'
import App from './App.vue'
import routes from 'pages-generated'
import './index.css'

const router = createRouter({
  history: createWebHistory(),
  routes
})

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

<router-view /> を App.vue に置いておく

src/App.vue
<script setup lang="ts"></script>

<template>
  <router-view />
</template>

<style></style>

最後に、src/pages/index.vue を置く

src/pages/index.vue
<template>
  <div>私のトップページです</div>
</template>

yarn run dev で起動した開発用環境にアクセスすると、私のトップページです。が出力される。

以下のファイルを作り、http://開発環境ホスト/second にアクセスすると、「2つ目のページです」が出力される。

src/pages/second.vue
<template>
  <div>2つ目のページです</div>
</template>
ooharabucyouooharabucyou

さて、ここまでは Nuxt にも頼らず、Webpackで設定ファイルをガリガリ書くこともなく、スムーズに構成を作ることができた。非常に満足である。
しかし、storybook をインストールすると諸々問題が出てくる。

まずは、storybook を入れてみる。

npx sb init

その後、yarn run build でファイルを作ろうとすると、以下のようなエラーが出てしまう。

$ vue-tsc --noEmit && vite build
node_modules/@types/react/index.d.ts:120:51 - error TS2344: Type 'C' does not satisfy the constraint 'ElementType<any>'.
  Type 'keyof IntrinsicElements | ForwardRefExoticComponent<any> | (new (props: any) => Component<any, {}, any>) | ((props: any, context?: any) => ReactElement<...> | null)' is not assignable to type 'ElementType<any>'.
    Type 'number' is not assignable to type 'ElementType<any>'.
      Type 'C' is not assignable to type 'FunctionComponent<any>'.
        Type 'keyof IntrinsicElements | ForwardRefExoticComponent<any> | (new (props: any) => Component<any, {}, any>) | ((props: any, context?: any) => ReactElement<...> | null)' is not assignable to type 'FunctionComponent<any>'.
          Type 'string' is not assignable to type 'FunctionComponent<any>'.

120         "ref" extends keyof ComponentPropsWithRef<C>
..

これは報告にもあがっているが build するときに使っている、vue-tsc (vue SFC の中にある ts の型チェックもするためのツール) 利用時に、Vue側のチェックに必要な@vue/runtime-dom と Storybookの中で使っている @types/react の型がコンフリクトしてこんな事になってしまっているらしい。

https://github.com/storybookjs/storybook/issues/12505

tsconfig.json をいじったり、上記のワークアラウンドにあった@types/react を消すなどをしても対処できず、結局今は storybook を入れるのを諦めている。

ooharabucyouooharabucyou

どういうわけか、現時点で↑を行って、rm -fr ./node_modules/@types/react を行った場合、うまく動作した。

https://github.com/storybookjs/storybook/issues/12505#issuecomment-974238829

でのコメントの通り、

yarn add -D rimraf

のあと、prebuild hook で、

  "scripts": {
    "prebuild": "rimraf ./node_modules/@types/react"
  }

を入れると良さげである。rimraf は、OSに依存しないディレクトリ削除コマンドのようだ。