Typescriptから呼び出せるTauriおすすめPlugin紹介

[以前書いた記事](https://qiita.com/Odashikonbu/items/3818384c7cdc19121f1a)にたくさんの反響を頂きましたので、調子に乗って今回はTauriV2のプラグインでおすすめのものを紹介していきたいと思います。

### まず注意点
#### プラグイン処理は全部非同期
Tauriプラグインを介したTypescript/javascriptの処理は例外なく全て非同期処理となります。
こればっかりはrustで書かれた処理をts/jsで呼び出すという構成上仕方ないです。
例えば、「アプリ起動時にconfigファイルを参照して中の値を取り出す」という処理だけでも、実際に実装してみると以下のようなawait祭りになります。


```svelte:onMount
import { readTextFile, writeTextFile, exists, mkdir } from "@tauri-apps/plugin-fs";
import { join, resourceDir } from "@tauri-apps/api/path";
import { ref, onMounted } from 'vue'
import {parse} from 'yaml'

const ymlconfig = ref([])

const checkConfig = async() => {
  const configPath = await join(await resourceDir(), "config.yml")
  if(await exists(configPath)){
    ymlconfig = parse(await readTextFile(configPath))
  }
}

onMounted(() => {
    checkConfig()
});

```

「awaitを多用するな」とは非同期処理の実装でよく言われることですが、Tauriプラグインの処理は中身がrustというのもあって処理自体は爆速で終わるためそこまでパフォーマンス面への影響はないと思います
(**ちゃんと測ったわけじゃないので違ってたらゴメンね！**)

#### 権限スコープをちゃんと付けること

ほぼ全てのプラグインに```src-tauri\capabilities\default.json```でのスコープ設定が必要になります。
基本の```<プラグイン名>:default```で動くものもありますが、動かないものは画面上でエラーを返してきます。
とりあえず迷ったらプラグインの処理に対して以下のようなスコープ設定をする癖を身に着けておくといいと思います。

```json:default.json
"permissions": [
    {
      "identifier": "fs:allow-exists",
      "allow": [
        {
          "path": "**" ~ここはアプリの用途に合わせて都度書き換えてください。~
        }
      ]
    }
]
```
<br>

以下、私が個人的に多用しているプラグイン

### [fs](https://v2.tauri.app/plugin/file-system/)
Nodeのfsとほぼ同じ機能を提供してくれます。
引数で渡したパスの存在確認をする``exists``、
ファイルの読み書きをする``writeTextFile``, ``readTextFile``, ``writeFile``, ``readFile``あたりは個人的に必須

```typescript:fs
import { exists } from "@tauri-apps/plugin-fs";
import { writeTextFile,readTextFile,writeFile,readFile } from "@tauri-apps/plugin-fs"

//事前に権限スコープの設定をしてないとtrueでもfalseでもなくエラーを返すので注意
if(await exists('path/to/folder')){
    ...
}


const path = "path/to/file.txt"
const imgPath = "path/to/image.png"

const file = await readTextFile(path) //テキストファイル内容のstringを返す
const img = await readFile(imgPath) // ファイルのバイナリ(int8Array)を返す

await writeTextFile(path, "text") //対象ファイルをテキストで上書きする

const otherImagePath = "bbb/image.png"

await writeFile(imgPath, await readFile(otherImagePath)) //対象ファイルをバイナリで上書きする

```

### [path](https://v2.tauri.app/reference/javascript/api/namespacepath/)
こちらもnodeのpathと大体同じですが、Tauriプラグイン固有のメソッドとしてアプリの実行パスを返してくれる``resourceDir``メソッドがあり、これが物凄く便利、
パス同士を結合させる``join``と合わせて個人的に使用頻度が高いです。

```typescript:path
import { join, resourceDir } from "@tauri-apps/api/path"

const resourceDir = await resourceDir() //exeの実行パスを返す
const configDir = await join(resourceDir, "config.json") //<実行パス>/config.jsonが返ってくる

```

## [Dialog](https://v2.tauri.app/plugin/dialog/)
window.confirmなどのダイアログと同じ機能を提供します。
```typescript:dialog
import { message, confirm, open, save } from "@tauri-apps/plugin-dialog";

//OKでtrue、キャンセルでfalseが返ってくる
const confirm = await confirm(
  '続行しますか？', //確認ウィンドウに表示sれるメッセージ
  { title: '確認', kind: 'warning' }//タイトルでウィンドウ名、kindでアイコン種類を指定
);

//メッセージを出すだけ、OKを押すと消える
await message('メッセージ', { title: 'メッセージ', kind: 'error' });

//ファイルを選択するとファイルパスが、キャンセルするとnullが返ってくる
const file = await open({
  multiple: false,//複数ファイル選択
  directory: false,//trueにするとフォルダ選択メニューになる
  
  filters: [//省略可能、省略すると全ファイル選択可能になる
    {
      name: '画像',//フィルター名称
      extensions: ['png', 'jpeg'],//設定した拡張子しか選択できなくなる
    },
  ],
});

//メニューから保存をクリックすると、保存先フォルダーにファイルが置かれた過程でフルパスを返す
const path = await save({
  filters: [
    {
      name: '画像',
      extensions: ['png', 'jpeg'],
    },
  ],
});

```

## [SQL](https://v2.tauri.app/plugin/sql/)
MYSQL、PostgreSQL、SQliteの3バージョン選択可能
selectでSELECTを、executeでDELETE、INSERT、UPDATE等を使用可能。
自分はSQliteのみ使っていますが、dbファイルが無い場合のファイル新規作成までちゃんとやってくれました。
rustでわざわざDB接続のコードを書かなくてもこれ一つで事足りるのは非常に便利。

```typescript:SQL
import Database from '@tauri-apps/plugin-sql';
const path = "path/to/aaa.sqlite"

const db = await Database.load(`sqlite:${path}`);

await db.execute('INSERT INTO ...');//DELETE、INSERT、UPDATE等を実行
const result = await db.select("SELECT * FROM ...")//SELECTの戻り値を返す

```

## [Store](https://v2.tauri.app/plugin/store/)(超おすすめ)
Electronでも人気が高かった[Electron-store](https://github.com/sindresorhus/electron-store)のTauri版。

jsonファイル形式で設定値を格納できるKey-Valueストアを構築できます。
対象パスにjsonファイルが無くても自動で新規作成してくれる機能も完備。

これの便利さに気付くまでずっとfsのテキストファイル読み書きで設定ファイルの取り扱いをしていましたが、storeに切り替えてから処理の手間が一気に少なくなりました。

```typescript:Store
import { load } from "@tauri-apps/plugin-store"
import { join, resourceDir } from "@tauri-apps/api/path"

//resourceDirを使えば実行パスでストア作成も可能
const configDir = await join(await resourceDir(), "config.json"

//渡されたパスでストアの読み込み設定を確立
//(ファイルには直接アクセスしないため、config.jsonが無くてもエラーになりません。)
const store = await load(configDir, { autoSave: false });

//getでキー値を渡して値を取得する
//jsonが無いか、キーが存在しない場合はundefinedが返ってくる。
const data = await store.get<string>('data');

//ストアにキーと値を設定する時はsetを使う、この時点ではまだファイル保存はされない。
await store.set('data', "test")

//ストアとなるjsonファイルを保存する、この時点で対象パスにjsonがなければ新規作成する。
await store.save()

```