任意のファイルをkintoneのカスタマイズそのものに埋め込む

この記事はQiita kintone Advent Calendar 2024参加の記事です。よろしくお願いいたします。

今年はErakisというkintoneのカスタマイズ環境を作りました。

https://qiita.com/IshigiwaKenichiro/items/99d15e9b00dc87bd777f

今回はErakisの機能を利用して、kintoneのカスタマイズに、任意のファイルを埋め込んでみます。（カスタマイズそのものに、ファイルを埋め込む）

Erakisを使わなくても、parcelなら同じ要領で実現できます。webpackのurl-loader,viteなどでも、バンドラに合わせたやり方で実現できます。


# やりたいこと
kintoneのカスタマイズでは、通常CSSとJSファイルを作成し、アプリにアップロードして用います。ホスティングできるのはその2種類なので、画像・ファイル、その他をカスタマイズ内容そのものに埋め込むことはできません。

でも、カスタマイズに固定的にファイルを埋め込みたい場合があります。

例えば・・・
- カスタマイズ内容に対応した、配布用のExcelファイルのテンプレートシートをダウンロードさせたい（外側にファイル管理アプリなどを作りたくない。）
- プラグインに対応したアプリテンプレートをダウンロードさせたい。

こんなケースが思いつきますね。

なので、今回は、任意のバイナリファイルをカスタマイズに埋め込んで利用してみようと試みます。

画像を埋め込む方法については、下記記事をごらんください。

https://qiita.com/IshigiwaKenichiro/items/9945038163878200def0

# 実際につくるもの
kintoneのマニュアルをユーザーがダウンロードできるようにしてあげましょう。

![adv-2024.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/f6c0719c-7755-84bc-ecdb-4862a9235eae.gif)

案件では、アプリの利用方法などを提供できると良いですね😊


# 実装
それでは作っていきましょう。

## kintoneアプリを作る
適当なkintoneアプリを作って、アプリのURLを控えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/64353bde-eb34-862f-b4dc-c09a2f5baaeb.png)

**アプリID**を控えておきます。

## 開発環境を作る
Erakisを利用しない方は、この内容は飛ばしていただいて大丈夫です。

適当なディレクトリを作って、そこで以下のコマンドを実行します。

```bash
# 初期化
npm init -y

# parcelの導入
npm i parcel

# erakisの導入
npm i erakis

# erakisによるプロジェクトの初期化
npx erakis init

```
初期化に成功すると、.erakisディレクトリが作成されます。

### プロファイルの作成
```bash
npx erakis profile list
```
でアクセスプロファイルを探します。もし、さきほど作成したkintoneアプリのアクセス情報（プロファイル）がない場合は、作成する必要があります。

```bash
npx erakis profile add
```

### 開発サーバーの秘密鍵の作成
```bash
npx erakis genkey
```
で、開発サーバーをHTTPS化します。

mkcertの機能を利用しています。うまくいかない方は、こちらの記事を見てみてください。

https://qiita.com/IshigiwaKenichiro/items/99d15e9b00dc87bd777f

### アプリをプロジェクトに結合する
```bash
npx erakis app connect
```
いくつかの質問に答えて、カスタマイズを作成します。
give me your app urlには、アプリのトップページ（一覧画面）のURLを与えます。

#### devとproduction
開発と本番を登録して管理する機能がErakisにはあります。
今回は分けませんので、開発と本番で同じ情報を与えます。

一度設定した環境を再定義するには、同じ名前のcustomizationを入れてあげれば大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/15e7e564-9474-3b58-91f7-fc1df970ff40.png)
👆こんな感じで「上書きするけどいい？」って聞いてくれます。

### ファイルを確認する。
アプリの設定が終わると、TSファイルが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/89c04c51-a9ec-4312-9d01-fa046a4aa676.png)

src/app/[customization名]にできあがります。

TSファイルになっています。TypeScriptを書きたくない人はJSファイルに拡張子を変えてあげてください。

以上で開発環境の構築はおわりです。

では、プログラムを書いていきましょう。

## PDFファイルをダウンロードするボタンを作る。
今回はKUC(KintoneUIComponent)ライブラリを利用します。
```bash
# インストール
npm install kintone-ui-component
```

実際のカスタマイズを行うファイルを作成します。
src/app/[customization名]/entry.customize.tsxを作成。


kintoneのマニュアルはサイボウズ社のサイトで配布されているものを、今回は利用してみます。
https://kintone.cybozu.co.jp/material/pdf/kintone.pdf

src/app/[customization名]にkintone.pdfファイルを置きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/7ef1e728-7f2e-0c4d-e788-77482f88d9c1.png)

ファイルを作り終わると、こんな感じです。(customization名="adv")

### コーディング
entry.customize.tsxを以下のように記述します。
```typescript
import fileUrl from 'data-url:./kintone.pdf';
import * as KUC from 'kintone-ui-component';

declare const kintone: any;
export function customize(isMobile: boolean) {

    const $$button = new KUC.Button({
        text: 'マニュアルをダウンロードする',
    })

    $$button.id = `download-button`;

    $$button.addEventListener('click', () => {        
        const $$a = document.createElement('a');
        $$a.download = "kintone.pdf";
        $$a.href = fileUrl;
        $$a.click();
    });

    kintone.events.on([
        'app.record.index.show',
        "mobile.app.record.index.show"
    ], async (ev: any) => {
        const $$menu: HTMLDivElement = isMobile ? kintone.mobile.app.getHeaderSpaceElement() : kintone.app.getHeaderMenuSpaceElement();

        if (!$$menu.contains($$button)) {
            $$menu.appendChild($$button);
        }
        return ev;
    });
}
```

### ちょっとだけ解説
ソースコードの内容を解説してみます。

#### ファイルの埋め込み
```typescript
import fileUrl from 'data-url:./kintone.pdf';
```
これは、fileUrlという文字列変数に、kintone.pdfをdata-url(Base64変換したバイトコード)として読み込む命令です。

Erakisはparcelをバンドラに利用していますが、parcelのbundle-inlining機能を利用して、ソースコード内にファイルを埋め込んでいます。

data-url:[相対ファイルパス]

という文字列で指定することができます。

#### ダウンロード
```typescript
$$button.addEventListener('click', () => {        
    const $$a = document.createElement('a');
    $$a.download = "kintone.pdf";
    $$a.href = fileUrl;
    $$a.click();
});
```
ここは、ボタンを押下したときの動作です。
HTMLAnchorElementを作って、それを押下したときの動作を疑似的に起こしています。
$$a.hrefにURL(DataURL)を埋め込んでいるので、ダウンロードリンクとして動作しています。

## エラーが気になる・・・
VSCodeで開発していると、以下のようにエラーを提示してきますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/e17150a7-ad34-9651-f980-886c0b2084d2.png)

"モジュール 'data-url:./kintone.pdf' またはそれに対応する型宣言が見つかりません。"

そのままでも構いませんが、気になるので解消してあげます。

このエラーはtypescriptで通常読み込めないファイルが指定されているため、表示されています。なので、「このファイルはtypescriptで読み込めるよ」と教えてあげます。

実際の読み込みはparcelが実施するので、typescriptは知らなくてもいいわけです。

src/index.d.tsファイルを作成し、内容を下記のようにします。

```typescript
declare module '*.pdf';
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/bc4c751c-db74-21df-1f9c-0b090332c659.png)

👆エラーが消えました😊

## カスタマイズに組み込む
entry.cutomize.tsxを作ったので、エントリーポイントになっているファイルに埋め込みましょう。エントリーポイントは以下の２つです。

- src/app/adv/customize.desktop.ts
    - PC用カスタマイズのソース
- src/app/adv/customize.mobile.ts
    - モバイル用カスタマイズのソース

ここにentry.customize.tsxで記述した、customize関数を呼び出してあげます。

src/app/adv/customize.desktop.ts
```typescript
import { customize } from "./entry.customize";

customize(false);
```

src/app/adv/customize.mobile.ts
```typescript
import { customize } from "./entry.customize";

customize(true);
```

上記のように設定することで、PCとモバイルで同じcustomize関数を読み込むことができました。

## 動かしてみる
Erakisの開発サーバーを動作させるコマンドは以下です。
```bash
npx erakis start
```

起動させると、ブラウザが立ち上がり、カスタマイズ対象のアプリへのリンクが示されます。

![スクリーンショット 2024-12-03 142211.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/f961bd86-0a3e-1159-e991-748afe5ef4a0.png)

リンクをたどってみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/96ba3495-1f2f-781c-0122-6616cd99ce5f.png)

マニュアルをダウンロードするボタンがありますね！


![adv-2024.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712902/f6c0719c-7755-84bc-ecdb-4862a9235eae.gif)

マニュアルがダウンロードできることを確認してみてください。

# まとめ
- data-urlを指定して、Bundle Inlining機能を呼び出せる
- data-urlはBase64でエンコードされる
- ファイルのダウンロードリンクにそのまま利用できる

ファイル埋め込みは結構便利な機能です。みなさんもいろいろ埋め込んでみてください😆

ただし、**kintoneのJSファイルのアップロード制限は20MBまで**なので、制限値には注意してご利用ください。(ファイルを分割できるといい感じです)


---
この記事は以上です。ありがとうございました。

https://www.pulsar-works.jp/

kintoneのプラグイン開発や研修などを行っています。
お仕事のお話はこちらまで。