ナウい kintone カスタマイズ (2) アプリ構築・設定編

# 目次

[(1) 環境構築編](https://qiita.com/iShinkai/items/caac0b60e882ff452512)
(2) アプリ構築・設定編（この記事）
[(3) アプリ実装編 part1](https://qiita.com/iShinkai/items/e2c808767b74451ab1b0)
[(4) アプリ実装編 part2](https://qiita.com/iShinkai/items/5ffedbe041741e541d1e)
[(5) ユニットテスト編](https://qiita.com/iShinkai/items/aab151b012bd96325812)

一連のソースは [GitHub](https://github.com/iShinkai/kintone-vue-ts-lead-management) で公開しています。

# 前置き

[前回](https://qiita.com/iShinkai/items/caac0b60e882ff452512) の記事では、 **kintone** カスタマイズで `Vue.js`、`TypeScript`、`Pug`、`SCSS` などのモダンな開発環境を利用しますよと言う趣旨で解説を始めましたが kintone ぜんぜん関係ないじゃんむしろただの **Vue CLI で TypeScript プロジェクト作ります** って話だったじゃんと言う展開でした。
今回はいよいよちゃんと kintone の話題です。

# 前提

以下の環境で作業しています。

- macOS Catalina
- Homebrew 2.1.16
- Node.js 13.1.0
- VisualStudio Code 1.40.1

[(1) 環境構築編](https://qiita.com/iShinkai/items/caac0b60e882ff452512) の記事で、以下をセットアップしました。

- Vue.js 4.0.5
- TypeScript 3.5.3
- vue-cli-plugin-pug 1.0.7

他、プロジェクト作成時の流れで `Sass / SCSS` や `ESLint`、`Prettier`、`Jest` などがセットアップされています。

# 今回のゴール

今回は、 kintone のアプリを作り、前回作ったプロジェクトでそのアプリのカスタマイズスクリプトを開発を進め、その成果を kintone カスタマイズに適用する繋ぎ込みの部分を中心に説明していきます。

- kintone アプリを作成する
- kintone 関連ライブラリをインストールする
- カスタマイズを kintone に適用する
- もう少し楽に開発を進める

# (2) アプリ構築編

## kintone アプリを作成する

既にある程度 kintone 利用経験がある方にとっては言わずもがなでしょうが、もし kintone 触った事ないですって方は事前に [cybozu developer network](https://developer.cybozu.io/hc/ja) で kintone 開発者ライセンスを取得しておいてください。

今回はカスタマイズの説明が目的なので、アプリの作成そのものは特に解説しません。
話を簡単にするため、 kintone 側で用意している雛形アプリの中から「**案件管理**」アプリを使いましょう。
<img width="737" alt="resized-01-001-lead-management.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/985403ee-969e-23a7-8700-7da285ea4c69.png">

アプリ作成の際、「サンプルデータを含める」のチェックを付けてください。
これでデータがある程度格納されている状態でアプリが新規作成されます。
<img width="472" alt="resized-01-002-contains-data.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/7b02f8a8-111c-bf65-a200-e3f12e400084.png">
<img width="737" alt="resized-01-003-records-list.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/b267fb33-5103-8936-a269-b429a0dccd76.png">

作成されたアプリはフィールドコードが「`文字列__1行_`」など分かりづらい内容になっています。
カスタマイズではフィールド名よりもフィールドコードの方が重要なので、**各フィールドのフィールドコードをフィールド名と合わせておく**とこの先のカスタマイズが楽になります。
サイボウズさんこの辺までちゃんとしといてくれれば良いのにとは思いますが。
<img width="737" alt="resized-01-004-change-field-code.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/b8c7fc48-1486-316e-73e1-addd1624651f.png">

とりあえずこれで一旦アプリの準備は終了です。

## kintone 関連ライブラリをインストールする

kintone カスタマイズを便利に進めるためのライブラリ類をインストールします。

[前回](https://qiita.com/iShinkai/items/caac0b60e882ff452512) の記事で作成したプロジェクト **kintone-vue-ts** で作業します。
プロジェクトを VS Code で開いてください。

### kintone JS SDK

まずは [kintone JS SDK](https://github.com/kintone/kintone-js-sdk/) をインストールします。
ターミナルで以下のようにします。

```bash
% yarn add @kintone/kintone-js-sdk
```

`kintone JS SDK` は、従来のカスタマイズでは冗長な記述になりがちだったレコードの全件取得や複数登録更新など、面倒な API 操作を良い感じに巻き取ってくれる SDK です。
[ドキュメント](https://kintone.github.io/kintone-js-sdk/latest/) も（英語ですが）平易で体系的にまとまっていますので、着実な工数削減が見込まれます。

### kintone dts-gen

`TypeScript` では **d.ts ファイル**（型定義ファイル）のあるなしが開発効率に大きく影響します。
[kintone dts-gen](https://github.com/kintone/dts-gen) はこの型定義ファイルの作成を支援してくれるツールで、よほどカスタマイズの規模が小さくない限りは `TypeScript` で kintone 開発を行うなら必須と言えるものです。
kintone 公式ドキュメントでは[こちら](https://developer.cybozu.io/hc/ja/articles/360023293091-TypeScript%E3%81%A7kintone%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E9%96%8B%E7%99%BA%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86)で解説されています。

> @kintone/dts-genはkintoneのJavaScriptカスタマイズ用の関数定義に加えて、指定したアプリからフィールド情報を取り出すコマンドラインツールが同梱されています。

との通りで、これをインストールする事により、

- エディタ上でコード補完が有効になる
- 型の誤りや関数に渡す引数の誤りなどと言った実装ミスを機械的に指摘してくれる

などの効果がもたらされ、開発効率の向上に多大に寄与してくれます。

インストールそのものは非常に簡単です。

```bash
% yarn add -D @kintone/dts-gen
```

で、

```bash
% npx kintone-dts-gen --help
```

と実行してヘルプがずらずらっと出て来れば OK です。

### アプリのフィールド定義情報を取得する

では、インストールした `dts-gen` を使い、先ほど作成した案件管理アプリの `d.ts` ファイルを取得してみましょう。
コマンドのフォーマットは以下の通りです。

```bash
% npx kintone-dts-gen --host https://(サブドメイン).cybozu.com \ 
                      -u (ユーザー名) \ 
                      -p (パスワード) \ 
                      --app-id (アプリID) \ 
                      --namespace (名前空間プレフィクス) \ 
                      -o (ファイル出力先)
```

と言うフォーマットになっています。
例えば、

```bash
% npx kintone-dts-gen --host https://example.cybozu.com \ 
                      -u kintone-taro \ 
                      -p ******** \ 
                      --app-id 101 \ 
                      --namespace leadManagement.types \ 
                      -o src/lead-management.fields.d.ts
```

と言った具合です。
実行すると案件管理アプリのフィールド情報が格納された `src/lead-management.fields.d.ts` ファイルが作成されます。

```json:lead-management.fields.d.ts
declare namespace leadManagement.types {
  interface Fields {
    確度: {
      type: "RADIO_BUTTON";
      value: string;
      disabled?: boolean;
      error?: string;
    };
    単価: {
      type: "NUMBER";
      value: string;
      disabled?: boolean;
      error?: string;
    };
    先方担当者: {
      type: "SINGLE_LINE_TEXT";
      value: string;
      disabled?: boolean;
      error?: string;
    };

    (省略)

  }
  interface SavedFields extends Fields {
    $id: {
      type: "__ID__";
      value: string;
    };
    $revision: {
      type: "__REVISION__";
      value: string;
    };

    (省略)

  }
}
```

`Fields` インターフェイスがアプリに固有のフィールドに関する定義、`SavedFields` インターフェイスはレコード ID や作成者・更新者などどのアプリでも必ず存在するフィールドに関する定義が含まれます。
先ほどアプリ作成後にフィールドコードを分かりやすくなるよう修正しましたが、その結果がここに現れて来るわけです。

### 型定義ファイルの参照を指定する

`d.ts` ファイルを取得しただけでは、まだエディタ上でその効果を発揮させることはできません。
これを `TypeScript` で参照可能にするために、プロジェクトの直下にある `tsconfig.json` を編集します。
 
```diff:tsconfig.json 
+  "files" : [ 
+    "./node_modules/@kintone/dts-gen/kintone.d.ts", 
+    "./src/lead-management.fields.d.ts" 
+  ], 
  "exclude": [ 
    "node_modules" 
+    "dist" 
  ] 
``` 

併せて `exclude` にビルドしたファイルが格納される `dist` を加えておくと良いでしょう。

コード補完の動作の様子は先ほども紹介した[公式ドキュメント](https://developer.cybozu.io/hc/ja/articles/360023293091-TypeScript%E3%81%A7kintone%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E9%96%8B%E7%99%BA%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86)でも確認できます。

## カスタマイズを kintone に適用する

これで一通り準備は整いましたので、いよいよ開発を進めていきます。

### カスタマイズビューで Vue.js のマウントポイントを作成する
`Vue.js` は DOM の特定の要素にインスタンスをマウントさせるところから始まりますが、kintone では **カスタマイズビュー** で DOM を定義してやるのが一般的でしょう。

**案件管理** アプリの設定で「一覧」から＋ボタン（一覧の追加）をクリックし、「レコード一覧の表示形式」で「**カスタマイズ**」を選択します。
「HTML」のボックス内に、とりあえずシンプルに以下のように書いて、

```html
<div id="lead-management"></div>
```

そのあと左上の「保存」をクリックし、アプリの設定も保存してください。
ここで記述した `lead-management` が、これから実装する `Vue.js` のマウントポイントになるわけです。
<img width="400" alt="resized-02-001-customize-view.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/16fa121b-c315-0520-f035-e23869ff5ec2.png">

### カスタマイズビューに `Vue.js` インスタンスをマウントする

当然ですが、この時点で「一覧1」ビューを見ても何も表示されません。
<img width="486" alt="resized-02-002-no-records.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/05abb0c2-f737-6df7-4a3d-ebccdd3d19d6.png">

kintone カスタマイズの流儀に則り、レコード一覧イベント発生時に動作するよう実装していきます。

#### main.ts 
現在のビューがカスタマイズビューであり、マウントポイントが存在し、インスタンスが未マウントである場合にマウント処理を実行すると言う流れにします。
`main.ts` を以下のように修正します。

```typescript:main.ts
import Vue from "vue"; 
import App from "./App.vue"; 
 
Vue.config.productionTip = false; 
 
// マウントポイント 
const mountPount: string = "lead-management"; 
 
// インターフェイス 
interface KintoneEvent { 
  offset: Number; 
  records: leadManagement.types.SavedFields[]; 
  size: Number; 
  type: string; 
  viewName: string; 
  viewType: string; 
} 
 
/** 
 * イベント処理 
 */ 
kintone.events.on(["app.record.index.show"], (e: KintoneEvent) => { 
  // カスタマイズビューでないなら何もしない 
  if (e.viewType !== "custom") { 
    return e; 
  }
 
  // マウントポイントが存在するなら
  if (
    document.querySelector(`#${mountPount}`) ||
    document.querySelector("#app")
  ) {
    // 未マウントならマウント実行
    if (!document.querySelector("#app")) {
      vm = new Vue({
        render: h =>
          h(App)
      }).$mount(`#${mountPount}`);
    }

    // レコードをセット
    Vue.set(vm.$children[0], "records", e.records);
  }
});
```

上記のポイントとしては、

- `kintone.events.on()` で受け取るイベントオブジェクトをインターフェイスとして定義しておく
- そのインターフェイスの `records` オブジェクトの型として、先ほど `dts-gen` で作成した型定義の配列 `leadManagement.types.SavedFields[]` を指定してやる
- マウントポイントに `App` コンポーネントがマウントされていなければマウントを実行する
- イベントオブジェクトで受け取ったレコードを `Vue.set()` 関数で `App` コンポーネントに渡してやる

と言った点が挙げられます。
このイベントは最初にアプリのページを開いた時だけでなく、フィルタの設定を変更したりページャーでページを切り替えたりするたびに呼ばれるため、その都度下位コンポーネント（`vm.$children[0]` で特定可能）にレコードを引き渡してやらなければなりません。
それを受け持つのが `Vue.set` 関数と言うわけです。

#### App.vue

次に、そのレコードを受け取って表示する側の `App.vue` を実装します。

```vue:App.vue
<template lang="pug">
  #app
    table
      thead
        tr 
          th 会社名
          th 先方担当者
          th 見込み時期
          th 確度
          th 製品名
          th 単価
          th ユーザー数
          th 小計
      tbody
        tr(v-for="record in records")
          td {{record.会社名.value}}
          td {{record.先方担当者.value}}
          td {{record.見込み時期.value}}
          td {{record.確度.value}}
          td {{record.製品名.value}}
          td {{record.単価.value}}
          td {{record.ユーザー数.value}}
          td {{record.小計.value}}
</template>

<script lang="ts">
// デコレーター
import { Component, Vue } from "vue-property-decorator";

// コンポーネント
@Component

// クラス本体
export default class App extends Vue {
  // [データ] 表示対象のレコード
  recordData: leadManagement.types.SavedFields[] = [];

  // [算出プロパティ] 表示対象のレコード
  get records() {
    return this.recordData;
  }
  set records(value) {
    this.recordData = value;
  }
}
</script>

<style scoped lang="scss">
#app {
  table {
    th,
    td {
      border: 1px solid #9cf;
      padding: 2px 10px;
    }
    thead {
      tr {
        background-color: #dfd;
      }
    }

    tbody {
      tr {
        background-color: #fff;
        &:nth-child(even) {
          background-color: #dff;
        }
      }
    }
  }
}
</style>
```

`main.ts` から受け取った `records` は setter でローカルの `data` である `recordData` に格納します。
同時にこれは getter として `recordData` をそのまま返却するようにしており、これを使って `v-for` で 1 つずつテーブルに出力します。

#### ビルドしてカスタマイズを適用する

このように実装した `.ts` ファイルや `.vue` ファイルをそのまま kintone のカスタマイズに適用する事は当然ながらできません。
kintone カスタマイズで利用可能なように、 `JavaScript` ファイルにコンパイルしてやります。
VS Code のターミナルで、以下のように実行します。

```bash
% yarn build
```

すると、プロジェクト直下に `dist` ディレクトリが作成され、その下に `js` とか `css` とかのディレクトリ、そして `.js` や `.css` ファイルが作成されるはずです。
<img width="250" alt="resized-02-003-dist.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/82c9ae53-7829-34a2-53b7-9264c0910463.png">

ここで作成されたファイルを案件管理アプリの JavaScript / CSS カスタマイズに適用してやります。
<img width="320" alt="resized-02-004-apply-js-css.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/b0558759-e89f-5819-0051-9f0ae68ff6e2.png">

改めて「一覧1」を表示すれば、レコード一覧が出力されるのが確認できます。
<img width="769" alt="resized-02-005-record-table.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/dfa12465-f93d-5781-b08a-db2213e115e3.png">

## もう少し楽に開発を進める

一連の開発の流れを説明して来ましたが、コードにちょっと手を入れるたびに `build` して kintone アプリに適用して・・・なんてことをやっていては効率が悪いことこの上ありません。
最終ビルド時は仕方ないとしても、開発中はソースの変更を保存したらすぐにブラウザ上で確認したいですよね。
しかしながら、このような用途で使われる `yarn serve`（`vue-cli-service serve`）では実ファイルが作成されないため（メモリ上に展開されるため）、そのままでは kintone のカスタマイズに適用する事はできません。
そこで、VS Code の拡張機能の1つである **[Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)** を利用します。
Live Server 自体のインストールや基本的な設定、HTTPS の設定は[こちら](https://developer.cybozu.io/hc/ja/articles/360026502091-Visual-Studio-Code-Live-Server-Extension%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6kintone%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E9%96%8B%E7%99%BA%E5%8A%B9%E7%8E%87%E3%82%92%E3%81%82%E3%81%92%E3%82%88%E3%81%86-)を参考にしてください。

Live Server をインストールしたら、`package.json` に以下のように設定します。

```diff:package.json
  "scripts": { 
    "serve": "vue-cli-service serve", 
+    "devel": "vue-cli-service build --mode development", 
+    "watch": "vue-cli-service build --mode development --watch", 
    "build": "vue-cli-service build", 
    "test:unit": "vue-cli-service test:unit", 
    "lint": "vue-cli-service lint" 
  }, 
``` 

さらに、`.vscode/settings.json` も以下のようにしておきます。

```json:.vscode/settings.json
{
    "liveServer.settings.root": "/dist/",
    "liveServer.settings.https": {
      "enable": true, 
      "cert": "(フルパス)",
      "key": "(フルパス)"
    }
}
```

kintone のアプリ設定では以下のように設定します。
<img width="320" alt="resized-03-001-localhost.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/f721ddd0-9de4-3a5b-d1a2-1cc12b167bc7.png">

で、VS Code のターミナルで

```bash
% yarn watch
```

と実行し、エディタ右下の `Go Live` をクリックします。
これで、

- ソースコードを編集すると自動的にビルドが実行される
- ローカルの `dist/js/*.js` ファイルを `https://localhost:5500/*.js` としてブラウザで閲覧可能

となります。

アプリの閲覧結果も先ほどと同じ結果になるのが確認できるはずです。
<img width="769" alt="resized-02-005-record-table.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/162138/dfa12465-f93d-5781-b08a-db2213e115e3.png">



# 次回は

というわけで、今回は `Vue.js` と `TypeScript` で開発するプロジェクトを kintone にはめる一連の流れを見ていきました。
ここから先はもう普通に kintone のカスタマイズの流儀に則って進めればいいだけですが、せっかくですので、このアプリをもう少しいい感じに育てていきたいかと思います。
今回触れなかった `kintone JS SDK` の話にも触れていければと思います。