ViteベースなVueコンポーネントライブラリのビルドで型定義(d.ts)ファイルを出力する
はじめに
TL;DR
vite-plugin-dts
を使うと、Vite ベースで開発している Vue コンポーネントライブラリの型定義ファイルを出力できる。
概要と対象読者
本記事では、Vite 環境において Vue コンポーネントライブラリを作っている場合に型定義ファイルを出力する方法をご紹介します。ご紹介するのは、筆者が作っている BabyuewJSというライブラリで実際に使っている方法です。
本当は npm パッケージとしての設定などにも触れたかったのですが、時間が無かったので割愛します。ちゃんとしたコンポーネントライブラリを公開したい場合は、npm のドキュメントなどを合わせてご参照ください。
Vite や Vue、Web フロントエンド開発についてはある程度理解している方向けの説明となっていますのでご了承ください。
検証環境
- Windows 10 Home
- Node.js 20
- pnpm 8
- Vue 3.3.8
- Vite 5.0.0
- vite-plugin-dts 3.6.4
Vueコンポーネントのビルド時にd.tsファイルを出力する
プロジェクトの作成
本記事で想定しているような Vite ベースの Vue プロジェクトを作るところからやっていきましょう。
下記のようにpnpm create vite@latest
によって Scaffolding します。途中で質問されるので、Vite,TypeScript と回答します。
❯ pnpm create vite@latest
../../.pnpm-store/v3/tmp/dlx-16248 | +1 +
../../.pnpm-store/v3/tmp/dlx-16248 | Progress: resolved 1, reused 1, downloaded 0, added 1, done
√ Project name: ... vue-test
√ Select a framework: » Vue
√ Select a variant: » TypeScript
プロジェクトの整理
create-vite によって Scaffold されたプロジェクトを修正して、とても簡単なコンポーネントとエントリポイントだけに整理しましょう。目指すディレクトリ構成は次の通りです。
/
├─ dist/
├─ src/
│ ├─ assets/
│ │ └─ main.scss
│ ├─ components/
│ │ ├─ HelloMessage.vue
│ │ └─ index.ts
│ ├─ App.vue
│ ├─ index.ts
│ └─ main.ts
├─ index.html
├─ package.json
└─ vite.config.ts
テンプレートがベースになっており、不要なアセットやコードを削除した感じになります。
src/components/
ディレクトリにはコンポーネントが 1 つ入っており、今回はこのコンポーネントをパッケージとして配布する想定です。.vue ファイルを直接インポートするとコンポーネントの名前を好きに指定できてしまうので、src/components/index.ts
で名前付き export しています。
HelloMessage
コンポーネントはApp.vue
で参照されてトップページで表示されます。また、App.vue
は Web ページのエントリポイントであるmain.ts
でdiv#app
にマウントされます。
src/
以下にmain.ts
とindex.ts
があり少し紛らわしいですね。この構成は必須でないので変えてもいいのですが、ライブラリ開発やビルドの時に都合が良いです。
次に主要なファイルのコード内容を示します。
<script setup lang="ts">
interface Props {
name: string
}
const props = defineProps<Props>();
</script>
<template>
<div class="hello-container">
<p class="hello-message">Hello, {{ props.name }}!!</p>
</div>
</template>
<style scoped lang="scss">
/* 中略 */
</style>
import HelloMessage from './HelloMessage.vue'
export { HelloMessage }
<script setup lang="ts">
import { HelloMessage } from "./components"
</script>
<template>
<HelloMessage name="World" />
</template>
import './assets/main.scss'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
export * from './components'
ここまでの状態で開発者サーバーを立ち上げると次のようなページが表示されました。
lib modeによるビルド
ライブラリとして提供したいコンポーネントができ、それが手元で動いていることも確認できましたが、このままだとpnpm build
した時に Web ページが生成されてしまいます。
コンポーネントライブラリなので、そのコンポーネントをビルドしたものがdist/
以下に生成される状態へ持っていきたいですね。
Vite には lib mode というモードがあり、設定をするとビルド時にエントリポイントから依存をたどってライブラリをビルドするようになります。とはいえ設定自体はすごい簡単なので実際にやってみましょう。
vite.config.ts
を開いて、build オプションを加えます。
Vue のテンプレートを利用しているので元からvite.config.ts
がありましたが、なかった場合は作成してください。ファイルの中を編集して次のようにします。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
+ import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
+ build: {
+ lib: {
+ entry: resolve(__dirname, 'src/index.ts'),
+ name: 'vue-component-dts',
+ fileName: 'index',
+ formats: ['es', 'umd']
+ }
+ }
})
build.lib フィールドの中にいくつか設定していますね。
フィールド名 | 説明 |
---|---|
entry | パッケージのエントリポイントとなるファイル |
name | パッケージ名。任意 |
filename |
dist/ 以下に出力されるファイルの名前。型定義ファイルとの対応も考えてindexにした |
formats | 出力されるフォーマットの種類。ESM形式とUMD形式を指定した |
これらを指定したうえでビルドしてみると、ESModule 用と UMD 用の JS ファイルが生成されました。
src/index.ts
の意味
もともと Vite で作成した Vue プロジェクトのテンプレートにはmain.ts
というエントリポイントがありましたが、新たにindex.ts
というエントリポイントを追加作成したのは次のような理由があります。
- ライブラリのエントリポイントとするため
- 提供するライブラリを無駄なく指定できる
- 開発時は普通の Web フロントアプリとしてデバッグできるように
main.ts
をライブラリのエントリポイントとしても使ってしまうと、main.ts の依存はすべてエクスポートされてしまいますし、pnpm dev
の時とpnpm build
の時でmain.ts
の内容を変えないといけません。
この問題を解決するためにエントリポイントを分けました。これは筆者のやり方ですので、より良い方法がありましたら教えていただけると嬉しいです。
vite-plugin-dtsを使う
ライブラリとして出力されましたが、JS ファイルのみが出力されただけで型定義ないため、TypeScript で使えない状態です。型定義を生成する方法はいくつかあるようで、tsc のオプション指定などでも可能ですが筆者はvite-plugin-dts
というプラグインを使いました。
使い方は簡単で、vite.config.ts
のプラグインに指定するだけです。まずは次のコマンドでプラグインをインストールしましょう。
pnpm add -D vite-plugin-dts
次にvite.config.ts
を編集します。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
+ import dts from 'vite-plugin-dts'
// https://vitejs.dev/config/
export default defineConfig({
+ plugins: [vue(), dts({ exclude: ['src/main.ts'] })],
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'vue-component-dts',
fileName: 'index',
formats: ['es', 'umd']
}
}
})
やったこととしてはプラグインをインポートしてdts()
を設定しただけです。
引数にmain.ts
を除外する設定をしていますが、筆者の環境ではindex.ts
から参照されていないもののなぜか d.ts ファイルが生成されてしまっていたのでこのようにしています。
実際にビルドしてみると、型定義ファイルが生成されているのがわかります。
d.tsファイルが生成された
おわりに
まとめ
本記事では Vite で作成した Vue3 プロジェクトのコンポーネントをライブラリとしてビルドし、最終的に型定義ファイルを生成するまでをご紹介しました。同じような内容の記事はいくつかあるので n 番煎じですが、本記事の内容がご参考になれば幸いです。最後まで読んでいただきありがとうございました。
参考文献
Discussion