アドベントカレンダーでもなんでもないです。
とあるプロジェクトでテキストエディタの開発に1年以上に渡って携わりました。
その中でのライブラリ選定にあたり紆余曲折がありましたので記します。
要件
- シンプルにテキスト入力ができる
- データとしてプレーンテキストを取り出せる
- コピー&ペーストなどができる
- 文字装飾は一切不要
- 画像を挿入できる
この画像挿入が鬼門となります。
画像挿入を満たすため、WYSIWYGエディタライブラリを模索することとなります。
version.1 tiptap
以下の理由からtiptapを採用しました
- 要件を満たせる機能郡
- Vueライブラリである
生じた問題
実際にリリースしてみると、特定の環境や操作において以下のような問題が発生してしまいました。
- ペースト時に連続する半角スペースが1つになる
- ペースト時に全角スペースが半角スペースになる
- ペースト時に改行が消える
- 約1万文字を超えるとクラッシュする
主にiOSで多くの異常が見られました。
その他にも全角文字や改行コードの入力に関するハックが必要な事象が多く発見されました。
基本的に変換不要な英数字の基本的な入力しかサポートされてないように思われます。
version.2α
ライブラリの再選定
https://github.com/codex-team/editor.js
https://github.com/Microsoft/roosterjs
https://prosemirror.net/
https://draftjs.org/
version.2 quill
いくつかのライブラリを発見したものの、採用実績やフレームワークとの相性を加味した結果次のQuillを採用しました。
- 試験実装において前回の不具合は発生しない
- Vueライブラリではないものの、導入が容易
生じた問題
今回はversion.1における不具合を踏まえQuality Assuranceを通過したものの、新たな特定の環境や操作に依存した不具合が発生してしまいました。
- HTML形式のデータをペーストすると一部不要なスタイルの適用や改行の増加が見られる(Wordなど)
- 特定の環境・特定の位置でbackspaceするとクラッシュする
- 見た目上編集できるがインスタンス内にはデータが存在しないことがある
特にIEで問題が頻発することとなります。
クリップボード上のHTMLの加工処理の複雑さからこちらの想定するもとのプレーンなテキストをペーストをするのが困難です。
改行に関しては特に<p>
タグをコピーしていた場合、ブラウザによりテキスト+改行でとしてデータが取得されるために改行の増加が見られましいた。
また、内部の特殊なデータ構造の複雑さ・イベント処理の複雑さからオーバーライドしての処理なども困難です。
version.3α エディタ自前実装の検討
これまでの不具合を勘案し、エディタライブラリの自作という選択肢を考慮したものの以下の理由から断念することとなりました。
- メンテナーがいなくなる懸念(少人数チームのため)
-
contenteditable
のブラウザ差異を埋める実装の困難さ - WYSIWYGを作り込むのは機能過多かつ工数不足
version3. そして現在
以上を考慮し、contenteditable
を捨てることとなりました。
結局いくついたのは<textarea>
です。。。
<div v-for="(t, index) in texts" :key="index">
<div v-if="t.image">
<img :src="t.image.src"
:alt="t.image.alt"
@click="deleteImage(index)">
</div>
<div v-else>
<textarea v-model="t"
:index="index"
:ref="`text${index}`">
</div>
</div>
これに各種カーソル移動や変更のハンドラを追加したものが完成形となりました。
教訓
- 過多な機能は誤動作を巻き起こす
- ブラウザ差異の想定されるAPI(contenteditableのような)はライブラリでも解決されない場合がある
- 全角入力は想定されてない場合がある
- iOSとIEは魔境
Simple is best.