🍔

ViteベースなVueコンポーネントライブラリのビルドで型定義(d.ts)ファイルを出力する

2023/12/07に公開

はじめに

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.tsdiv#appにマウントされます。
src/以下にmain.tsindex.tsがあり少し紛らわしいですね。この構成は必須でないので変えてもいいのですが、ライブラリ開発やビルドの時に都合が良いです。

次に主要なファイルのコード内容を示します。

src/components/HelloMessage.vue
<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>
src/components/index.ts
import HelloMessage from './HelloMessage.vue'

export { HelloMessage }
src/App.vue
<script setup lang="ts">
import { HelloMessage } from "./components"
</script>

<template>
  <HelloMessage name="World" />
</template>
src/main.ts
import './assets/main.scss'

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
src/index.ts
export * from './components'

ここまでの状態で開発者サーバーを立ち上げると次のようなページが表示されました。

Alt text

lib modeによるビルド

ライブラリとして提供したいコンポーネントができ、それが手元で動いていることも確認できましたが、このままだとpnpm buildした時に Web ページが生成されてしまいます。
コンポーネントライブラリなので、そのコンポーネントをビルドしたものがdist/以下に生成される状態へ持っていきたいですね。

Vite には lib mode というモードがあり、設定をするとビルド時にエントリポイントから依存をたどってライブラリをビルドするようになります。とはいえ設定自体はすごい簡単なので実際にやってみましょう。

https://vitejs.dev/guide/build#library-mode

vite.config.tsを開いて、build オプションを加えます。
Vue のテンプレートを利用しているので元からvite.config.tsがありましたが、なかった場合は作成してください。ファイルの中を編集して次のようにします。

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 ファイルが生成されました。

Alt text

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というプラグインを使いました。

https://github.com/qmhc/vite-plugin-dts

使い方は簡単で、vite.config.tsのプラグインに指定するだけです。まずは次のコマンドでプラグインをインストールしましょう。

pnpm add -D vite-plugin-dts

次にvite.config.tsを編集します。

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 ファイルが生成されてしまっていたのでこのようにしています。
実際にビルドしてみると、型定義ファイルが生成されているのがわかります。

Alt text
d.tsファイルが生成された

おわりに

まとめ

本記事では Vite で作成した Vue3 プロジェクトのコンポーネントをライブラリとしてビルドし、最終的に型定義ファイルを生成するまでをご紹介しました。同じような内容の記事はいくつかあるので n 番煎じですが、本記事の内容がご参考になれば幸いです。最後まで読んでいただきありがとうございました。

参考文献

https://vitejs.dev/guide/build#library-mode

https://github.com/qmhc/vite-plugin-dts

https://qiita.com/Tukudanium/items/d429aca28619026c67a3

https://zenn.dev/s_takashi/articles/20ecebd0a42010

https://qiita.com/whopper1962/items/6eaf781b548162205b40#viteのビルド設定を定義

GitHubで編集を提案

Discussion