ElectronからTauriに移行しようとしてD&Dで詰んだ話

相当ニッチな状況の話なので、ニーズがあるかわからないが、
もしかしたら１人でも検索にかかって無為な時間を過ごす時間を減らせたならば幸甚ということでまとめておく。
なお、この情報は現在(2022-08-24)のtauri最新バージョン`1.0.5`を元にしたものであり、今後は解消するかも知れないことは注意。
特に例えばvscodeやnotion、slack等、今Electronで出来ている多くのアプリにおいて、これが解消しないかぎり移行はまず出来ないので、tauriがシェアを伸ばしたいのであれば解消に向けた対応はされると思われる。
解消したらここに追記したいと思う。

対象は
- 個人、企業問わず、Electornで作られたアプリ開発を行っているか、考えている。
- Tauriが小さく、速いということで気になっていて移行、もしくは最初からTauriによる開発を考えている。
- そのアプリでは、ファイルのDrag&Drop(D&D)によりローカルのファイルを受け取り、そのフルパスをもとに何らかの処理を行う機能がある。
- そのアプリでは、DOM要素のD&Dにより画面上で並び替える、位置を変えるなどの機能がある。
- Windowsが動作環境に含まれている

これらを全て満たす場合において、この記事は多分役に立つ。

## ElectronでファイルのフルパスをD&Dで受け取る方法
Electronで、ローカルのファイル(またはディレクトリ)のフルパスをD&Dで受け取る方法は非常に簡単で、
FileAPIが独自に拡張されているため、Dropイベントで受け取ったファイルオブジェクトに`path`プロパティが追加されているのでこれだけでいい。
[参考](https://www.electronjs.org/ja/docs/latest/api/file-object "Electron Doc")
```ts
function dropped( ev ){
  const [file] = ev.dataTransfer.files
  console.log(file.path)
  //=> /absolute/path/example.txt
}
```
言うまでもないかもしれないが、一応言及しておくと、通常のブラウザではこのオブジェクトにファイル名(`name`)はあるがディレクトリは含まれない。
あなたのパソコンのディレクトリ構造がそこから漏れることになるからだ。
その昔、IEでは～という話は長くなるのでよしておこう。

デスクトップアプリを作る基盤としてのElectronがこの拡張を行うことは自然であり、ファイルのD&Dを通常のWebアプリ開発で触ったことのある人であれば直感的に扱えるという点も良い。大変スマートな設計であると思う。

ちなみに私は個人で、簡単に言うと所謂ランチャーを作っており、受け取ったファイルパスをストアしている。

## TauriでファイルのフルパスをD&Dで受け取る方法
一方Tauriでは前出のFileAPIの拡張は行われていない。(各OSのWebViewを利用するtauriの設計上そもそも難しそう。)
同じようにしても、undefinedになるだけだ。
Tauriではウインドウ自体にファイルがD&Dされたときのイベントが定義されるので、それをsubすることでファイルパスを取得できる。
```ts
import { appWindow } from "@tauri-apps/api/window"
appWindow.onFileDropEvent( (ev) => {
  if( ev.payload.type !== 'drop' ){
    return
  }
  const [filepath] = ev.payload.paths// as string[]
  console.log(filepath)
  //=> /absolute/path/example.txt
})
```

Electronのやり方とくらべて若干の泥臭さを感じるのと特定の要素へのDropとして絞ることも出来ないのもつらみがあるが、
まぁ工夫次第でなんとかなる範囲ではあろう。
ここまではよしとしたい。

## FileDropを許可するTauriの設定
前記のFileDropイベントは、デフォルトで有効になのだが、設定により無効とすることができる。
`tauri.conf.json`に、以下の設定を入れるとイベントが発火しなくなる。
```json:tauri.conf.json
  "windows":[
    { "fileDropEnabled": false }
  ]
```
意味は読んでの通りだ。trueがデフォルトなので、あえて設定しない限りファイルのD&Dが可能。

## FileDropが有効だと、draggable要素が動かない
ここからが問題。
通常であれば、要素にdraggable属性をつければ、その要素をドラッグする事ができる。
以下はdraggableを使って、要素を並び替える様子。使われている文字はランダム生成したものである。

![f.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474381/e879f316-253e-8148-cadb-51bacefa253f.gif)

これが、FileDropを有効にしたTauriでは動作しない。
![f2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474381/7090c043-94b3-5e3e-fc79-59d74326d897.gif)

[Tauriの公式](https://tauri.app/v1/api/js/interfaces/window.windowoptions/#filedropenabled "Tauri API")に以下のような記載がある。散々唸ってここに行き着いた私の絶望を想像して欲しい。
> Disabling it is required to use drag and drop on the frontend on Windows.

Windowsでは、FileDropを有効にした場合、フロントエンドでのDrag&Dropが無効になるというのだ。

## 要するに
つまり、TauriのWindowsでの動作において、ファイルをD&Dで受け取るのであれば、設定でFileDropを有効にしないといけないが、
FileDropを有効にすると、画面上での要素のdraggableが効かなくなる、両方の機能が必要であれば詰みである。＼(^o^)／

## 本当にどうしようもないのか
めちゃくちゃ頑張れるのであれば、draggableの動作をmousedown->mousemove->mouseupで再発明する方法はあると思う。
私は申し訳ないがそこまでやる気にならないし、冒頭でも触れた通り、そのうち解消されると思うので今は多少重量級なのが玉に瑕のElectronとイチャイチャしておこうと思う。

## 他にも
細かいことを言うと、Electronが用意してくれているファイルのアイコン取得APIやNativeImageなどそのアプリで実現したい機能によっては他にも詰みポイントはある。(それも全部Rustで頑張れないことはないだろうが)
今回はその中でもそこそこ可能性の高そうなD&Dに触れてみた。
世界の誰かの役に立つことを祈っている。