Flutter Webの現状と課題 (2021年11月時点)

先日、実験的にFlutter Webを使い数ヶ月かけて開発を進め、最終的に、結局パフォーマンスの問題からReactにすべて書き換えたことがあった。

同じ失敗をする人ができるだけ少ないように、現状のFlutter Webの課題点について、主に以下のIssueから引用して共有しておこうと思う。

https://github.com/flutter/flutter/issues/87182

前提として、Flutterはとても積極的に更新が行われているので、上記Issueで挙げられている問題点は徐々に解決すると思う。現状ではまだ関連IssueはOpenのままで、少なくともここ数ヶ月は変わりなく、執筆時点で最新版のFlutter 2.5.3ではまだ未解決な問題点を挙げていく。

## 初期読み込みが非常に重い

https://github.com/flutter/flutter/issues/46589

実際に `flutter build web --release`をしてアプリをデプロイしてみると分かるけれど、どんなに小さいアプリを作っても、`main.dart.js`のサイズがめちゃくちゃ大きい。

マテリアルデザインだと、これにアイコンフォントの読み込みも入り、読み込んだあとの処理も加わるので、実用的なアプリだと初期読み込みに10秒くらいはザラでかかる。

現状では、関連リソースをgzipで圧縮したり、軽いレンダラーのhtmlレンダラーを使うなどの方法もあるものの、htmlレンダラーには見た目上の問題点もあり、完全に解決することは難しい。

たとえば初期化時に読込中表示を出すなどして対応する方法もあるけれど、将来的には根本的に解決してくれたらいいなぁと思う。

https://qiita.com/funatsufumiya/items/bd276485852372c01c3b

## モバイル版ブラウザではパフォーマンス問題が多数

https://github.com/flutter/flutter/issues/59332

https://github.com/flutter/flutter/issues/56257

こちらは、バージョンが上がる度に少しずつ改善されているように思うけれど、執筆時点では未だに実用的なレベルにはなっていない。

特にモバイルSafariやモバイルChromeでのパフォーマンスは深刻で、iOS/AndroidアプリではなくWeb版をモバイルで表示させるというのはあまり現実的ではない。

ListViewを使ったり、スクロールしたり、アニメーションしたりと、基本的な操作がとても重くなるケースが未だに存在していて、かつブラウザごとに微妙にパフォーマンスに差異があるため、デバッグも簡単ではない。

## テキストフィールドに文字がうまく打てない

https://github.com/flutter/flutter/issues/78550

これが個人的にはかなり厄介で、特に日本語入力は全然うまく打てない印象。記号を打つとフリーズしたり、入力途中の文字がダブって２つ入ってしまったりと、使っていてとてもイライラする。

とはいえ、コピペして入力すれば一応打てるし、全く文字が打てないわけではないので、だましだまし使うことが一応できるのは不幸中の幸い。

この現象はモバイル版に限らず通常のChromeでも発生し、特にCanvasKitレンダラーで深刻。

## PCブラウザでも、パフォーマンス問題は大きい

前述のIssueでは、モバイル版ブラウザにおけるパフォーマンス問題が中心に取り上げられていたものの、PCブラウザでもパフォーマンスの問題は大きい。

実際にWindows/Mac/Linux用のアプリとして書き出すとパフォーマンスの違いに驚いたりするし、特に複雑なUIや通信が発生してくるとパフォーマンス問題はどんどんと深刻になってくる。

デバッグにおいても、iOS/Androidエミュレータでは使えるはずのFlutterのパフォーマンスビューがWebでは使えず、パフォーマンス改善やデバッグに相当苦戦を強いられる。Webでは通常使えるはずのDevToolも、CanvasKitレンダラーを基調にしているとうまく使えないし、Dartとjsのソースマップもうまくいかなかったりして、Flutter Webのパフォーマンス改善はとにかく辛い。

個人的に特に困ったのが、最悪デスクトップアプリとして使えればいいやと思っていると、Web固有の機能がアプリ版では使えなかったり、iOS/Android/Web向けにpub.devから提供されているパッケージが、デスクトップアプリにはなかったりする。(特にWebカメラ周りや、iframe埋め込みのライブラリがWindows/Mac用は皆無なのが個人的に辛いところ…。)

## …一方で、Flutterで良かった点

…とこんな感じで多数のパフォーマンス問題があり、自分が抱えていたプロジェクトでは最終的にはReactに書き換えたわけだけれど、Flutterで書き始めたメリットもいくつかあった。

- マテリアルデザインを基調に組んでいたので、移植後もUIはほぼ変わらなかった

これはコーティング上も見た目上もメリットは大きく、最初にマテリアルデザインを基準にして開発を進めたのは良かった。HTML5でもマテリアルデザインはほぼそのまま使えるので、Reactに移植しようと決めたあともほぼ迷いなくそのまま移植でき、見た目のデザイン的にも、コードの全体像もほとんど変わりなく移植できた。

初期開発のプロセスとしても、マテリアルデザインという"補助輪"のおかげでサクサクとシンプルにUIが作れたのは嬉しかった。もし最初から素のHTMLだったら、選択肢が多くてこうはいかなかったと思う。

- FlutterとReactは類似点が多いので、移行がスムーズ

これが個人的に嬉しかったポイントで、特にReact HooksとFlutterのRiverpodがよく似ていて、移植が簡単にできた。

また、`Promise`と`Future`、`dynamic`と`any`、FlutterのNull-SafetyとTypeScriptのundefined/null check、Optional Chainingまわりなど、DartとTypeScriptの類似点が非常に多く、移植するのはそんなに難しいことではなかった。

若干の演算子の違いがあったり、Flutterでは`List<Widget>`を返すところがReactでは`<React.Fragment>`で返せる点など、多少の違いはあるものの、両者は互いによく似ていて、ある程度抽象化していればほぼ同じコードが使えるのは嬉しい。

ただ、名前付きパラメータの扱いや、JSX記法との違いなど、移植に悩む点はところどころあるものの、互換の記法はすぐ見つかるので、そこまで悩まずに済んだ。（この点は別の記事でまとめたい。）

一方で、デバイス固有の処理を使っている場合は、やはり移植するには注意が必要。例えば永続化まわりなど、LocalStorageなどのブラウザ本来の機能で代替できる場合もあるし、そうでない場合もある。

- プラットフォーム間の差異がほとんどない

これはReactに書き換えて改めて実感したのだけれど、Flutterは独自のレンダラーを基盤にしているだけあって、プラットフォーム間の差異を自動で吸収してくれる。前述の問題点の大半はそれゆえに起こっているのだけれど、これはReact/React Nativeに対する大きなメリットで、Flutterからの移植後には、いろんなプラットフォームでUIが崩れていないか確認したりする作業が必要になってしまう。これはFlutterの今後に期待したい。

## まとめ

ということで、Flutter自体は非常に楽しくて是非今後も使っていきたいフレームワークなのだけれど、Flutter Webを実践投入するのは、2.5.3の現時点でもまだ時期尚早という印象。

本文中にも書いたように、デスクトップアプリ版ではまだ提供されていないパッケージも多い（特にWebカメラやiframe埋め込みなどデバイス・Webまわり）ので、最悪デスクトップアプリで書き出せばいいや、ともいかないので注意が必要。

ただ、Flutter Webのおかげで[DartPad](https://dartpad.dev/)のようにすぐに書いたコードを共有できたり、エミュレータを使わなくても開発が進められたりとメリットもあるので、iOS/Android開発のオトモとしてFlutter Webを使うのはアリだと思う。

もしFlutterで作り始めて、あとからWeb版が欲しくなっても、Reactとの類似点は非常に多くあるので、思い切って移植するのもそんなに苦ではないというのは一応安心。でもデバイス固有の機能を使っている場合は注意。