Vite, Vue3, TypeScript, Tailwind CSS, Storybook な構成を作りたかった
結論から言うと、storybook を入れるのには失敗している (一旦諦めた)
-> やっぱりうまくいった (2021/11/21)
まずは、テンプレートからプロジェクト作成
yarn create vite vite-vue -- --template vue-ts
パッケージインストール
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.
次に、Tailwind CSS に対応する
パッケージをインストール
yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest
Tailwind用のファイルを用意する
npx tailwindcss init -p
src/index.css
を作成して以下を記載
@tailwind base;
@tailwind components;
@tailwind utilities;
src/main.ts
に以下を記載する
import './index.css'
これで、Tailwind CSS が動作する状態になる。
試しに、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}']
軽く 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 をプラグインとして指定
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 に追加
/// <reference types="vite-plugin-pages/client" />
routes について、'pages-generated'
が作ってくれるので main.ts で、それを呼び出して、routes として指定する。
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 に置いておく
<script setup lang="ts"></script>
<template>
<router-view />
</template>
<style></style>
最後に、src/pages/index.vue
を置く
<template>
<div>私のトップページです</div>
</template>
yarn run dev
で起動した開発用環境にアクセスすると、私のトップページです。が出力される。
以下のファイルを作り、http://開発環境ホスト/second
にアクセスすると、「2つ目のページです」が出力される。
<template>
<div>2つ目のページです</div>
</template>
ありがとうございます。修正しました!
さて、ここまでは 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
の型がコンフリクトしてこんな事になってしまっているらしい。
tsconfig.json をいじったり、上記のワークアラウンドにあった@types/react
を消すなどをしても対処できず、結局今は storybook を入れるのを諦めている。
どういうわけか、現時点で↑を行って、rm -fr ./node_modules/@types/react を行った場合、うまく動作した。
でのコメントの通り、
yarn add -D rimraf
のあと、prebuild hook で、
"scripts": {
"prebuild": "rimraf ./node_modules/@types/react"
}
を入れると良さげである。rimraf は、OSに依存しないディレクトリ削除コマンドのようだ。