✨JavaScriptでKintoneが進化！カスタマイズ開発の最新トレンド🚀

こんにちは😊
[株式会社プロドウガ](https://qiita.com/organizations/prodouga-com)の@YushiYamamotoです！
[らくらくサイト](https://rakuraku-site.prodouga.com/)の開発・運営を担当しながら、React.js・Next.js専門のフリーランスエンジニアとしても活動しています❗️

Kintoneは、プログラミングの知識がなくても業務アプリを簡単に作成できるサイボウズ社のクラウドサービスです。しかし、その真価はJavaScriptによるカスタマイズによって、さらに大きく引き出されます。本記事では、Kintoneカスタマイズの基本から、イマドキのフロントエンド技術を取り入れた最新トレンドまで、具体的なコード例を交えながら分かりやすく解説します！

## 🤔 Kintoneとは？ なぜJavaScriptカスタマイズ？

Kintoneは、ドラッグ＆ドロップでデータベース型アプリを構築できるプラットフォームです。顧客管理、案件管理、日報など、様々な業務アプリをノンプログラミングで作成できます。

**標準機能のイメージ:**
![Kintone標準機能](https://kintone.cybozu.co.jp/assets/img/product/image_product_summary.png)
*(画像はサイボウズ株式会社 Kintone公式サイトより引用)*

しかし、標準機能だけでは手が届かない、以下のような「もっとこうしたい！」という要望が出てくることがあります。

*   入力された値に応じて、別のフィールドの表示/非表示を切り替えたい
*   複雑な計算処理を自動で行いたい
*   外部サービスと連携してデータを取得・表示したい
*   よりリッチなユーザーインターフェースを実現したい

これらを解決するのが**JavaScriptによるカスタマイズ**です。JavaScriptを使うことで、Kintoneの標準機能を拡張し、より業務にフィットした、使いやすいアプリケーションへと進化させることができます。

## 🛠️ Kintone JavaScriptカスタマイズの基本

KintoneのJavaScriptカスタマイズは、特定のイベントが発生したタイミングで処理を実行するのが基本です。

**主なイベントの種類:**
*   レコード一覧画面表示時 (`app.record.index.show`)
*   レコード詳細画面表示時 (`app.record.detail.show`)
*   レコード作成画面表示時 (`app.record.create.show`)
*   レコード編集画面表示時 (`app.record.edit.show`)
*   フィールド値変更時 (`app.record.create.change.<フィールドコード>`, `app.record.edit.change.<フィールドコード>`)
*   保存実行前 (`app.record.create.submit`, `app.record.edit.submit`)

これらのイベントをトリガーにして、独自の処理を記述します。

### サンプル：フィールド値に応じて表示を切り替える

例えば、「ステータス」フィールドが「完了」になったら、「完了日」フィールドを入力必須にする、といったカスタマイズを考えてみましょう。

**フィールド設定:**
*   ステータス (ドロップダウン): フィールドコード `status`
*   完了日 (日付): フィールドコード `completion_date`

```javascript
(function() {
  'use strict';

  // レコード作成画面と編集画面の表示イベント
  const events = [
    'app.record.create.show',
    'app.record.edit.show',
    'app.record.create.change.status', // ステータスフィールド変更時 (作成画面)
    'app.record.edit.change.status'    // ステータスフィールド変更時 (編集画面)
  ];

  kintone.events.on(events, function(event) {
    const record = event.record;
    const statusValue = record.status.value;

    // フィールド要素の取得 (KintoneのAPIで推奨される方法)
    const completionDateElement = kintone.app.record.getFieldElement('completion_date');

    if (statusValue === '完了') {
      kintone.app.record.setFieldShown('completion_date', true); // 表示する
      // Kintoneの仕様上、setFieldShownだけでは必須にならないため、
      // 保存時のチェックなどで対応するか、DOM操作で視覚的に必須マークを付けることも検討
      if (completionDateElement) {
        // ここでは視覚的な工夫の例 (実際の必須化は保存前イベントで)
        completionDateElement.style.backgroundColor = 'lightyellow';
      }
      // 実際の必須化は保存実行前イベントで行うのが確実
    } else {
      kintone.app.record.setFieldShown('completion_date', false); // 非表示にする
      // 値もクリアする
      record.completion_date.value = null;
      if (completionDateElement) {
        completionDateElement.style.backgroundColor = '';
      }
    }
    return event;
  });

  // 保存実行前イベントで必須チェック
  const submitEvents = [
    'app.record.create.submit',
    'app.record.edit.submit'
  ];
  kintone.events.on(submitEvents, function(event) {
    const record = event.record;
    if (record.status.value === '完了' && !record.completion_date.value) {
      event.error = 'ステータスが「完了」の場合、完了日は必須です。';
    }
    return event;
  });
})();
```

このコードをKintoneアプリのJavaScriptカスタマイズ設定画面でアップロードすると、ステータスに応じて完了日フィールドの表示が切り替わり、必須入力制御も行われます。

:::note info
KintoneのJavaScript APIでは、`kintone.app.record.setFieldShown()` でフィールドの表示/非表示を制御できます。しかし、これだけでは入力必須の制御はできません。入力必須の制御は、`event.error` を使って保存実行前イベント (`app.record.create.submit`, `app.record.edit.submit`) で行うのが一般的です。
:::

## 🚀 Kintoneカスタマイズの最新トレンド

Kintoneカスタマイズは、基本的なDOM操作やイベント処理だけでなく、モダンなJavaScript技術を取り入れることで、さらに高度で洗練された開発が可能になります。

### 1. モダンJavaScript (ES6+) の活用

もはや当たり前ですが、`let`/`const`、アロー関数、Promise、`async/await` などのES6以降のモダンなJavaScript構文を利用することで、可読性が高く、メンテナンスしやすいコードを書けます。

```javascript
// ES6+ を使った非同期処理の例
(async () => {
  'use strict';

  kintone.events.on('app.record.detail.show', async (event) => {
    try {
      // 外部APIからデータを非同期で取得するイメージ
      const userId = kintone.getLoginUser().id;
      const response = await fetch(`https://api.example.com/user/${userId}`);
      if (!response.ok) {
        throw new Error(`API Error: ${response.status}`);
      }
      const userData = await response.json();

      // 取得したデータをKintoneのスペースに表示
      const spaceElement = kintone.app.record.getSpaceElement('my_space_field');
      if (spaceElement) {
        spaceElement.innerHTML = `
          <p>外部APIから取得したユーザー名: ${userData.name}</p>
          <p>メールアドレス: ${userData.email}</p>
        `;
      }
    } catch (error) {
      console.error('Error fetching data:', error);
      const spaceElement = kintone.app.record.getSpaceElement('my_space_field');
      if (spaceElement) {
        spaceElement.textContent = 'ユーザーデータの取得に失敗しました。';
      }
    }
    return event;
  });
})();
```

### 2. フロントエンドライブラリ/フレームワークの導入 (React, Vue.jsなど)

複雑なUIや状態管理が必要な場合、ReactやVue.jsといったライブラリ/フレームワークをKintoneカスタマイズに導入するケースが増えています。これにより、コンポーネントベースでUIを構築でき、開発効率とメンテナンス性が向上します。

**Mermaid図：ReactコンポーネントをKintoneに表示する流れ**
```mermaid
graph TD
    A[Kintoneイベント発火] --> B{レコード詳細画面表示など};
    B --> C[JavaScriptカスタマイズファイル実行];
    C --> D[Reactコンポーネントを生成];
    D --> E[ReactDOM.renderで特定のスペース要素に描画];
    E --> F[Kintone画面にReactコンポーネントが表示される✨];
```

<details><summary>ReactコンポーネントをKintoneで表示するサンプル</summary>

```javascript
// main.js (Kintoneにアップロードするファイル)
(function() {
  'use_strict';

  kintone.events.on('app.record.detail.show', function(event) {
    // Reactコンポーネントを描画するスペース要素を取得
    const el = kintone.app.record.getSpaceElement('my_custom_react_space');
    if (!el) {
      console.warn('スペース要素 "my_custom_react_space" が見つかりません。');
      return event;
    }

    // Reactコンポーネントを描画
    // 通常はWebpackなどでバンドルしたReactのコードを読み込みます
    // ここでは簡略化のため、グローバルに関数がある前提とします
    if (typeof MyKintoneReactComponent !== 'undefined') {
      ReactDOM.render(
        React.createElement(MyKintoneReactComponent, { record: event.record }),
        el
      );
    } else {
      console.warn('Reactコンポーネント "MyKintoneReactComponent" が定義されていません。');
      el.innerHTML = '<p>Reactコンポーネントの読み込みに失敗しました。</p>';
    }
    return event;
  });
})();

// --- 別途用意するReactコンポーネントの例 (component.js) ---
// このファイルはBabelやWebpackでトランスパイル・バンドルして、
// KintoneにアップロードするJSファイルから参照できるようにします。
// もしくは、CDN経由でReactとReactDOMを読み込み、
// このコンポーネントもscriptタグで読み込む形にします。

/*
// 例: component.jsx (Babelでトランスパイルが必要)
const MyKintoneReactComponent = ({ record }) => {
  const [count, setCount] = React.useState(0);

  return (
    <div style={{ border: '1px solid #e3e3e3', padding: '10px', borderRadius: '4px' }}>
      <h3>React Component in Kintone!</h3>
      <p>現在のレコードID: {record.$id.value}</p>
      <p>クリックカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>クリックしてね</button>
    </div>
  );
};
// window.MyKintoneReactComponent = MyKintoneReactComponent; // グローバルに公開する場合
*/
```

</details>

:::note info
ReactやVue.jsをKintoneで利用する場合、WebpackやParcelなどのモジュールバンドラーを使って、コンポーネントやライブラリを1つのJavaScriptファイルにまとめるのが一般的です。
また、Kintone環境ではグローバルスコープの汚染に注意し、即時実行関数 `(function() { ... })();` でコードを囲むのが定石です。
:::

### 3. TypeScriptの採用

大規模なカスタマイズや複数人での開発では、静的型付け言語であるTypeScriptの導入が有効です。型定義により、開発時のエラー検知やコード補完が強化され、品質向上に繋がります。

```typescript
// TypeScriptでのKintoneカスタマイズ例 (コンパイルが必要)
(() => {
  'use strict';

  // Kintoneの型定義ファイル (例: @kintone/dts-gen で生成) を利用
  kintone.events.on('app.record.detail.show', (event: KintoneTypes. wyświetlanieSzczegółówRekordu) => {
    const record = event.record;
    const customerName = record.顧客名.value; // 型があるのでプロパティ名の間違いに気づきやすい

    console.log(`顧客名: ${customerName}`);

    // 数値フィールドにアクセス
    if (record.売上金額 && typeof record.売上金額.value === 'string') {
        const salesAmount: number = parseFloat(record.売上金額.value);
        console.log(`売上金額: ${salesAmount.toLocaleString()}円`);
    }
    
    return event;
  });
})();
```
`@kintone/dts-gen` などのツールを使うと、Kintoneアプリのフィールド情報に基づいた型定義ファイルを生成でき、開発効率が格段に上がります。

### 4. ビルドツールと開発環境の整備

WebpackやParcelといったビルドツールを導入することで、以下のメリットがあります。
*   ES6+やTypeScriptのトランスパイル
*   JavaScriptファイルのバンドル（一つにまとめる）と圧縮
*   Sass/SCSSなどのCSSプリプロセッサの利用
*   開発サーバーによるホットリロード

**Mermaid図：ビルドプロセス**
```mermaid
graph TD
    subgraph "開発PC"
        A[src/index.ts（TypeScript）] --> B;
        X[src/components/MyComponent.tsx] --> B;
        Y[src/styles/style.scss] --> B;
        B[Webpack/Parcel] --> C{ビルド処理};
    end
    C --> D[dist/customization.js（バンドル&トランスパイル済み）];
    D --> E[Kintoneアプリへアップロード];
    
```

また、`kintone-customize-uploader` や `kintone-cli` といったCLIツールを使うことで、コマンドラインからKintoneアプリへのファイルアップロードを自動化でき、開発体験が向上します。

**コマンドライン例 (`kintone-cli`):**
```bash
# 設定ファイルに基づいて本番環境にアップロード
kintone-cli dev --app-id 123 --upload --watch

# customize-manifest.json (kintone-cli用設定ファイル例)
# {
#   "app": "YOUR_APP_ID",
#   "scope": "ALL",
#   "desktop": {
#     "js": [
#       "https://your-domain.com/path/to/your/bundle.js"
#     ],
#     "css": []
#   },
#   "mobile": {
#     "js": [],
#     "css": []
#   }
# }

# kintone-customize-uploader の場合
# npx kintone-customize-uploader --base-url https://example.kintone.com --username user --password pass manifest.json
```

:::note warn
ビルドツールやCLIツールを導入する場合、Node.jsやnpm/yarnの知識が必要になります。最初は少し学習コストがかかりますが、長期的に見ると開発効率が大幅に向上します。
:::

### 5. Kintone REST API Clientの活用

KintoneのデータをJavaScriptから操作する場合、`@kintone/rest-api-client` という公式のライブラリが便利です。Promiseベースで設計されており、`async/await` との相性も抜群です。

```javascript
import { KintoneRestAPIClient } from '@kintone/rest-api-client';

(async () => {
  try {
    const client = new KintoneRestAPIClient(); // 自動で認証情報を利用

    // レコード取得の例
    const params = {
      app: kintone.app.getId(), // 現在のアプリID
      query: 'ステータス = "未処理" order by 作成日時 desc limit 10',
      fields: ['$id', '顧客名', '対応内容']
    };
    const resp = await client.record.getRecords(params);
    
    console.log(`${resp.records.length}件の未処理レコードが見つかりました。`);
    resp.records.forEach(record => {
      console.log(`ID: ${record.$id.value}, 顧客名: ${record.顧客名.value}`);
    });

  } catch (error) {
    console.error('Kintone REST APIエラー:', error);
  }
})();
```
このライブラリを使うことで、煩雑なAPIリクエストの処理を簡潔に記述できます。

### 6. プラグイン開発へのシフト

再利用性の高いカスタマイズや、複数のアプリで共通して使いたい機能は、Kintoneプラグインとして開発するのも良い選択肢です。プラグイン化することで、設定画面を通じてユーザーが挙動を調整できるようになり、より汎用的なソリューションを提供できます。

## まとめ 🌟

Kintoneは、JavaScriptによるカスタマイズでその可能性を大きく広げることができます。
基本的なイベント処理から始まり、モダンなJavaScript構文、React/Vueのようなフロントエンドライブラリ、TypeScript、ビルドツールの導入といったトレンドを取り入れることで、より高度で使いやすい業務アプリケーションを構築できます。

最初は難しく感じるかもしれませんが、小さなカスタマイズから少しずつ試していくことで、必ずスキルアップできます。本記事が、皆さんのKintoneカスタマイズ開発の一助となれば幸いです！

Happy Kintone Hacking! 💻

---

# 最後に：業務委託のご相談を承ります
私は業務委託エンジニアとしてWEB制作やシステム開発を請け負っています。最新技術を活用したレスポンシブなWebサイト制作、インタラクティブなアプリケーション開発、API連携など幅広いご要望に対応可能です。

「課題解決に向けた即戦力が欲しい」「高品質なWeb制作を依頼したい」という方は、お気軽にご相談ください。一緒にビジネスの成長を目指しましょう！

<a href="https://github.com/YushiYamamoto">
<img src="https://img.shields.io/badge/　GitHub-181717?style=for-the-badge&logo=github&logoColor=white" alt="GitHub">
</a>

<a href="https://yushi.prodouga.com/" target="_blank" rel="noopener">
<img src="https://img.shields.io/badge/　ポートフォリオ-FF5500?style=for-the-badge&logo=react&logoColor=white" alt="ポートフォリオ">
</a>
  
<a href="https://qiita.com/YushiYamamoto" target="_blank" rel="noopener">
<img src="https://img.shields.io/badge/　Qiita-55C500?style=for-the-badge&logo=qiita&logoColor=white" alt="Qiita">
</a>

<a href="https://codepen.io/yamamotoyushi" target="_blank" rel="noopener">
<img src="https://img.shields.io/badge/　Codepen-000000?style=for-the-badge&logo=codepen&logoColor=white" alt="Codepen">
</a>
<br>
<a href="https://prodouga.com/" target="_blank" rel="noopener">
<img src="https://img.shields.io/badge/　株式会社プロドウガ-FF0000?style=for-the-badge&logo=firefox&logoColor=white" alt="株式会社プロドウガ">
</a>
<a href="https://rakuraku-site.prodouga.com/" target="_blank" rel="noopener">
<img src="https://img.shields.io/badge/　らくらくサイト-4285F4?style=for-the-badge&logo=rocket&logoColor=white" alt="らくらくサイト">
</a>