🌩️

Vite を利用して kintone カスタマイズ開発をする

2022/12/01に公開約8,500字

kintone アドベントカレンダー 2022 Vol.2 の 2 日目の記事です。

はじめに

この記事では、Vite で kintone kintone カスタマイズのファイルをビルドしてみたという内容を紹介しています。

Vite とは

Vite は、JavaScript 向けのビルドツールです。
webpack や Percel などのビルドツールと同じく、複数の JavaScript のモジュールを 1 つのファイルにまとめることができます。
The State of JS 2021 のビルドツール部門でも、満足度と興味が 1 位であり、2022 年現在注目されているツールのひとつです。

この記事で扱う kintone カスタマイズ

「郵便番号」フィールドに郵便番号を入力したら、該当する住所がフィールドにセットされるカスタマイズです。
郵便番号から住所を取得する方法として、郵便番号データ配信サービスである zipcloud を利用します。

手順

STEP1:kintone アプリの作成

kintone のアプリを作ります。
フォームには、次のフィールドを追加します。

フィールド名 フィールドの種類 フィールドコード
郵便番号 文字列(1行) zipcode
都道府県 文字列(1行) address1
市区町村名 文字列(1行) address2
町域名 文字列(1行) address3

STEP2:カスタマイズプロジェクトの作成

カスタマイズプロジェクトを作成します。
今回は npm init のコマンドでプロジェクトを作成したり、必要なパッケージをインストールしたりします。
Vite をセットアップするコマンドを使ったプロジェクトの作成では、kintone カスタマイズには不要なファイルが生成されるためです。

$ mkdir kintone-customize-sample; cd $_
$ npm init -y

STEP3:TypeScript の導入

TypeScript と、kintone アプリの型定義を生成できる @kintone/dts-gen をインストールします。

$ npm install -D typescript @kintone/dts-gen

kintone アプリの型定義ファイルを生成します。

$ npx kintone-dts-gen --base-url https://example.cybozu.com \
        --username USERNAME --password PASSWORD \
        --app-id APP_ID \
        --output types/fields.d.ts

types ディレクトリ以下に、次の内容で fields.d.ts が生成されます。

types/fields.d.ts
declare namespace kintone.types {
  interface Fields {
    zipcode: kintone.fieldTypes.SingleLineText;
    address3: kintone.fieldTypes.SingleLineText;
    address2: kintone.fieldTypes.SingleLineText;
    address1: kintone.fieldTypes.SingleLineText;
  }
  interface SavedFields extends Fields {
    $id: kintone.fieldTypes.Id;
    $revision: kintone.fieldTypes.Revision;
    更新者: kintone.fieldTypes.Modifier;
    作成者: kintone.fieldTypes.Creator;
    レコード番号: kintone.fieldTypes.RecordNumber;
    更新日時: kintone.fieldTypes.UpdatedTime;
    作成日時: kintone.fieldTypes.CreatedTime;
  }
}

ディレクトリの直下に tsconfig.json を作成し、次の内容を保存します。

tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "ESNext",
    "strict": true,
    "isolatedModules": true,
    "lib": ["DOM", "ES2022"],
    "skipLibCheck": true
  },
  "includes": ["src/**/*.ts"],
  "exclude": [
    "dist",
  ],
  "files" : [
    "./node_modules/@kintone/dts-gen/kintone.d.ts",
    "./types/fields.d.ts"
  ],
}

STEP4:カスタマイズファイルの作成

src ディレクトリを作成し、その下に main.tszipcode.ts の 2 つのファイルを作成します。

src/main.ts
import { searchAddressByZipcode, validateZipcode } from "./zipcode";

interface KintoneEvent {
  record: kintone.types.SavedFields;
  error: string;
}

(() => {
  "use strict";
  kintone.events.on(
    ["app.record.create.submit", "app.record.edit.submit"],
    async (event: KintoneEvent) => {
      try {
        const record = event.record;
        const zipcode = record.zipcode.value;

        // 郵便番号の書式が正しいかをチェックする
        const isValid = validateZipcode(zipcode);
        if (!isValid) {
          record.zipcode.error =
            "郵便番号はハイフンなしの7桁の数字で指定してください。";
          return event;
        }
        const addressList = await searchAddressByZipcode(zipcode);
        // 複数の住所候補が取得できる場合もあるが、サンプルなので最初の1件目を採用する
        record.address1.value = addressList?.[0]?.address1 || "";
        record.address2.value = addressList?.[0]?.address2 || "";
        record.address3.value = addressList?.[0]?.address3 || "";
        return event;

      } catch (error) {
        event.error = error.message;
        return event;
      }
    }
  );
})();
src/zipcode.ts
type ZipcloudResult = {
  zipcode: string | null;
  address1: string | null;
  address2: string | null;
  address3: string | null;
};

/**
 * 郵便番号の書式をチェックする(ハイフンなし7桁の数字)
 */
export const validateZipcode = (zipcode: string): boolean => {
  const regex = new RegExp("^[0-9]{7}$");
  return regex.test(zipcode);
};

/**
 * 郵便番号から住所を検索する
 */
export const searchAddressByZipcode = async (
  zipcode: string
): Promise<Array<ZipcloudResult>> => {
  try {
    const resp = await fetch(
      `https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipcode}`
    );
    const { message, results } = await resp.json();
    if (message) {
      throw new Error(message);
    }
    return results;
  } catch (err) {
    console.log(err);
    throw err;
  }
};

STEP5:Vite のインストールと設定

Vite をインストールします。

$ npm install -D vite

プロジェクトのディレクトリ直下に vite.config.js というファイルを作成し、次の内容を保存します。

vite.config.js
export default {
  build: {
    target: "es2021",
    rollupOptions: {
      input: {
        desktop: "src/main.ts" // main.ts を起点にビルドする
      },
      output: {
        format: "iife", // 即時関数で囲む
        dir: "dist", // 「dist」ディレクトリーの下にビルド後のファイルを生成する
        entryFileNames: "[name].js", // 生成物のファイル名は input のキー名とする
                                     // 今回は「desktop.js」というファイルが生成される
      }
    }
  },
}

この vite.config.js が Vite の設定ファイルです。
ブラウザの互換性のためにどの ECMAScript のバージョンで生成するかなどの設定ができます。
生成するファイルの名前を細かく設定したい場合には、rollupOptions に記載します。
rollupOptions の内容は、Rollup の設定 に準じて設定できます。

STEP6:カスタマイズファイルのビルド

package.json を開き、scripts の値を次のように書き換えます。
Vite でソースコードをビルドするには、vite build というコマンドを実行します。
Vite では TypeScript の型チェックが行われないため、事前に tsc --noEmit で型をチェックします。
参考:Vite - TypeScript

package.json
  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "build": "tsc --noEmit && vite build"
  },

次のコマンドで、カスタマイズファイルをビルドします。

$ npm run build

> kintone-customize-sample@1.0.0 build
> vite build

vite v3.2.4 building for production...
✓ 2 modules transformed.
dist/desktop.js   0.82 KiB / gzip: 0.47 KiB

dist ディレクトリの下に、desktop.js という名前のファイルが生成されます。
このファイルを、STEP1 で作成した kintone アプリにアップロードすることで、kintone カスタマイズを適用できます。
画面からアップロードしてもよいですが、今回は @kintone/customize-uploader を使ってカスタマイズを適用しましょう。

STEP7:カスタマイズファイルの適用

@kintone/customize-uploader をインストールします。

$ npm install -D @kintone/customize-uploader

次のコマンドで、@kintone/customize-uploader の設定ファイルを生成します。

$ npx kintone-customize-uploader init --dest-dir .

? アプリIDを入力してください: 12
? カスタマイズの適用範囲を選択してください: ALL
./customize-manifest.json を生成しました

プロジェクトのディレクトリ直下に、customize-manifest.json が生成されます。
Vite でビルドした dist/desktop.js がアップロードされるよう、customize-manifest.json を編集します。

customize-manifest.json
{
  "app": "12",
  "scope": "ALL",
  "desktop": {
-    "js": [],
+    "js": [
+      "dist/desktop.js"
+    ],
    "css": []
  },
  "mobile": {
    "js": [],
    "css": []
  }
}

package.json を開き、scripts にアップロード用のコマンドを追記します。

package.json
  "scripts": {
-    "build": "vite build"
+    "build": "tsc --noEmit && vite build",
+    "upload": "kintone-customize-uploader customize-manifest.json"
    "
  },

次のコマンドを実行して、kintone のアプリにカスタマイズファイルを適用します。

$ npm run upload

> kintone-customize@1.0.0 upload
> kintone-customize-uploader customize-manifest.json
> kintone-customize-ts@1.0.0 upload
> kintone-customize-uploader customize-manifest.json

? kintoneのベースURLを入力してください (https://example.cybozu.com): https://example.cybozu.com
? ログイン名を入力してください: username
? パスワードを入力してください: [hidden]
カスタマイズのアップロードを開始します
dist/desktop.js をアップロードしました!
JavaScript/CSS ファイルをアップロードしました!
JavaScript/CSS カスタマイズの設定を変更しました!
運用環境への反映の完了を待っています...
運用環境への反映の完了を待っています...
運用環境に反映しました!

STEP8:動作確認

kintone に 1 件のレコードを追加します。
以下が確認できれば成功です。

  • 「郵便番号」フィールドに、ハイフンありの郵便番号を保存するとエラーになる
  • ハイフンなしの 7 桁で、存在する郵便番号を入力してレコードを保存すると、住所が入力されている

おわりに(という名の所感)

Vite は設定ファイルがシンプルですね。そしてビルドがとても早いと感じました。
「これから kintone のカスタマイズ環境を作っていくぞ」というときに Vite はひとつの選択肢になりそうです。

参考情報

動作を確認したバージョン

  • Vite v3.2.4
  • TypeScript v4.9.3
  • @kintone/customize-uploader v6.0.20
  • @kintone/dts-gen v6.1.16

最終的なディレクトリの構成

この記事における最終的なディレクトリ構成は、次のとおりです。

├── customize-manifest.json
├── dist
│   └─── desktop.js // Vite でバンドルされたファイル
├── node_modules/
├── package-lock.json
├── package.json
├── src
│   ├── main.ts // kintone カスタマイズファイル
│   └── zipcode.ts // kintone カスタマイズファイルから呼び出す関数を定義したファイル
├── types
│   └── field.d.ts // kintone アプリの型定義
├──  vite.config.js // Vite の設定ファイル
└── tsconfig.json // TypeScript の設定ファイル

Discussion

ログインするとコメントできます