vue-docgen-cliを使ってみた 〜Vue.jsでコンポーネント一覧（スタイルガイド）を作成〜

プロジェクトでコンポーネント一覧作成のため、vue-docgen-cliを検証したので、使い方の備忘録。

# 対象読者
vueの基本的な知識をご存知の方であれば問題ありません。
具体的には、下記を満たす方であれば余裕で理解できる内容かと思います。

・vueを使用しているプロジェクトでコンポーネントを作成、修正した経験がある。あるいは入門書籍を読破した、個人で動かしたことがあるなど。
・props、events、slot、methodsを定義したことがある。

# 導入
```
yarn add -D vue-docgen-cli
```

# 使い方
使い方を解説します。
前提として、プロジェクト構成は以下とします。
```
root
├── src
├──├── components
├──├──├── atoms
├──├──├──├── TestButton.vue
├──├──├──├── TestInput.vue
├──├──├── molecules
├──├──├──├── TestSearch.vue
├──├──├── organisms
├──├──├──├── TestHeader.vue
├──├──├── pages
├──├──├──├── TestPage.vue
├──├──├── templates
├──├──├──├── TestDefaultTemplate.vue
```
## 注意点
### コメントの書き方について
ドキュメントにコンポーネントの(Props、Methods、Events、Slotsなどの)詳細を反映する為にはコメントを記載する必要があるのですが、コメントの書き方は以下のようなコメントの書き方でないとドキュメントに反映されないようです。
```
/** 
 * (ここにコメントを記載)
 */
```

### ドキュメントへのmethodsの反映について
Props、Events、Slotsについては各コンポーネントのVueファイル内で定義があればドキュメントに反映されますが、methodsについては、メソッドの定義の直前の行に`@public`のコメントがなければ反映されないようです。

## コンポーネント一覧を作成する
プロジェクトのルートで以下のコマンドを実行します。
```
yarn vue-docgen src/components docs
```
プロジェクトのルートにdocsというフォルダが作成され、その配下に各コンポーネントのマークダウンファイルが生成されます。
```
docs
├── src
├──├──components
├──├──├── atoms
├──├──├──├── TestButton.md
├──├──├──├── TestInput.md
├──├──├── molecules
├──├──├──├── TestSearch.md
├──├──├── organisms
├──├──├──├── TestHeader.md
├──├──├── pages
├──├──├──├── TestPage.md
├──├──├── templates
├──├──├──├── TestDefaultTemplate.md
```
各マークダウンファイルをプレビューしてドキュメントを表示します。ここではVSCodeでプレビューします。
```
// VSCodeでのプレビューのやり方
コマンドパレット： ［Markdown: プレビューを横に表示］（Markdown: Open Preview to the side）
キーボード： ［Ctrl］＋［K］→［V］（Win／Linux）、 ［Command］＋［K］→［V］（macOS）
```
TestHeader.mdをプレビューしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/122d1e2c-d9d0-e5a3-0dd4-6652df1b42d1.png)
TestHeaderコンポーネントのドキュメントが描写されました。
TestHeaderのコードは以下です。
```
<template>
  <header>
    <h1>{{ testTitle }}</h1>
    <slot name="slot" :item="item"></slot>
    <TestSearch/>
  </header>
</template>

<script>
import TestSearch from '@/components/molecules/TestSearch'

export default {
  name: 'TestHeader',
  components: {
      TestSearch
  },
  props: {
    testTitle: {
        type: String,
        default: 'test'
    }
  },
  methods: {
    /**
     * @public
     */
    testMethod(test) {
        alert(test);
    },
    testEvent() {
        this.$emit('test', true);
    },
  }
}
</script>

<style scoped>
</style>
```

## ドキュメントを生成するコマンドの引数を省く
ドキュメントを生成するコマンドを実行する際に、毎回引数を指定するのは手間だと思うかもしれません。
構成ファイルをプロジェクトのルート直下に作成して、必要な引数の設定をあらかじめ定義しておけばこれを回避することが出来ます。
構成ファイルをプロジェクトのルート直下に作成します。ファイル名は`docgen.config.js`となります。
このファイルを作成すると、`--config`を除くすべてのコマンドライン引数は、docgen.config.jsファイルの設定に置き換えることができます。
今回は下記のように設定してみます。
```
const path = require('path')
module.exports = {
  outDir: 'docs',
  componentsRoot: 'src/components',
  components: '**/[A-Z]*.vue',
}
```
outDirは文字通り、出力されるパスの設定になります。今回の例では、この記事の最初にドキュメントを出力した時と同じく、プロジェクトのルート直下にdocsフォルダを生成して、その配下にドキュメントを配置するように設定しています。

componentsRootはコンポーネントの検索を開始するフォルダを指定出来ます。今回の設定では、`src/components`を起点に対象ファイルを検索するようにしています。

componentsはドキュメント生成対象となるファイルを指定出来ます。今回の例では、componentsRootで指定したパス以下の全てのvueファイルとしています。

以上の設定により、最初の例でdocsフォルダを作成した際はパスが`docs/src/components/(atoms、molecules...)/`のようになりましたが、`src/components`の部分が省かれ、`docs/(atoms、molecules...)`のようなパスになります。
以下のコマンドを実行すると結果を確認出来ます。
```
yarn vue-docgen
```

## ドキュメントにコンポーネントの説明を記載する
複数人で開発している場合、作成済みのコンポーネントがどのような役割か、どこでどのように使われるか、説明が記載されていると開発済みの(使い回し出来る)コンポーネントの把握、共有がしやすいと思います。
`export default`の直前に、コメントを記載するとコンポーネントの説明が記載されます。
実際に説明を記載してみます。
引き続き、TestHeader.vueを例にして書き方を紹介します。
以下のコメントをTestHeader.vueの`export default`直前に記載します。
```
/**
 * 全画面共通のヘッダコンポーネント
 */
```
TestHeader.vueをプレビューします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/a35fc904-d2ac-d801-b8fb-32b62d8b2a87.png)
TestHeaderに説明が記載されました。

## Props、Methods、Events、Slots、それぞれの詳細の書き方
引き続き、TestHeader.vueを例にして書き方を紹介します。
### Props
testTitleの定義の直前に、下記のようにコメントします。
```
/**
　　* ヘッダのタイトル
　　* @values testTitleのvalues
　　*/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/4867ae11-ac0c-2ad7-7011-efc8c4641c33.png)

### Methods
testMethodの定義の直前に、下記のようにコメントします。
```
/** 
 * テスト用の関数
 * @public
 * @param {string} 引数はtestです
 */
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/592555d6-0287-953e-c2d5-e16ddbff5214.png)

### Events
イベント(`this.$emit('test', true);`)の直前に、以下のようにコメントします。
```
/**
 * テスト用のイベント
 * 引数はbooleanです
 * @property {boolean} test testのプロパティ
 */ 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/422e514d-e8c3-d16a-5e62-7720e7aac94d.png)

### Slots
slotのタグの直前に、下記のようにコメントします。
```
<!--
  @slot ヘッダのスロット
  @binding {string} item itemはスロットプロパティ
-->
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/37087f02-89d3-cfdf-b9eb-eb732abc7c2c.png)

最後に、ここまでのTestHeader.vueのコードは以下です。
```
<template>
  <header>
    <h1>{{ testTitle }}</h1>
    <!--
      @slot ヘッダのスロット
      @binding {string} item itemはスロットプロパティ
		-->
    <slot name="slot" :item="item"></slot>
    <TestSearch/>
  </header>
</template>

<script>
import TestSearch from '@/components/molecules/TestSearch'

/**
 * 全画面共通のヘッダコンポーネント
 */
export default {
  name: 'TestHeader',
  components: {
      TestSearch
  },
  props: {
    /**
     * ヘッダのタイトル
     * @values testTitleのvalues
     */
    testTitle: {
        type: String,
        default: 'test'
    }
  },
  methods: {
    /** 
     * テスト用の関数
     * @public
     * @param {string} 引数はtestです
     */
    testMethod(test) {
        alert(test);
    },
    testEvent() {
        /**
         * テスト用のイベント
         * 引数はbooleanです
         * @property {boolean} test testのプロパティ
         */ 
        this.$emit('test', true);
    },
  }
}
</script>

<style scoped>
</style>
```

## コンポーネントをグループ化する
ここまでの例では、ドキュメントを生成すると各コンポーネントごとにマークダウンファイルが作成されていますが、コンポーネントの種類によってグループ化してまとめたいと思うかもしれません。
docgen.config.jsにpagesオプションを設定するとドキュメントをグループ化することが出来ます。
この記事では、アトミックデザインの考え方を参考にしてプロジェクトを作成しており、コンポーネントの種類によってディレクトリ単位で分類しているので、ディレクトリの単位でグループ化しようと思います。
docgen.config.jsを下記のように修正します。
```
const path = require('path')

module.exports = {
  outDir: 'docs',
  componentsRoot: 'src/components',
  pages: [
    {
      components: 'atoms/**/[A-Z]*.vue',
      outFile: 'atoms.md'
    },
    {
      components: 'molecules/**/[A-Z]*.vue',
      outFile: 'molecules.md'
    },
    {
      components: 'organisms/**/[A-Z]*.vue',
      outFile: 'organisms.md'
    },
    {
      components: 'pages/**/[A-Z]*.vue',
      outFile: 'pages.md'
    },
    {
      components: 'templates/**/[A-Z]*.vue',
      outFile: 'templates.md'
    }
  ]
}
```
再度、ドキュメントを再作成(`yarn vue-docgen`コマンドを実行)すると、ドキュメントがグループ化して表示されます。
|ディレクトリのイメージ|atoms.mdのプレビュー|
|---|---|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/f8b212fe-05c4-2f56-9e2c-497a4ce7e0a1.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676513/b1ba3cb4-b611-a1fc-eed0-e2b7f134cc12.png)|

## 感想
一枚の画面で全コンポーネントを確認出来ないことと、各マークダウンファイルをプレビューしないと確認出来ないことが不便に感じました。
もしこれらの解決方法があり、方法をご存知の方いらっしゃれば是非ご教示頂けますと幸いです。

## 参考
https://www.npmjs.com/package/vue-docgen-api?activeTab=readme
https://vue-styleguidist.github.io/docs/docgen-cli.html