ntaoo blog

主にDart, Flutter, AngularDartについて書いていきます。ときどき長文。日本語のみ。Twitter: @ntaoo

Flutter Webの現状調査

Web特有の事情はどう解決するのかに興味があって内部構造などを調べていた。 開発が進むにつれて実装はどんどん進化して問題解決されていくだろうし、現段階のこの情報の正確性も保証しない。個人のメモを公開しているだけなので鵜呑みにはしないようにしてほしい。

あと、Preview版が公開された後にFAQが追加されているので読んでおくほうがいい。

https://github.com/flutter/flutter_web/blob/master/docs/faq.md

ニュース

まとめ

https://medium.com/flutter/a-roundup-of-flutter-news-at-google-i-o-453bb3249981

Flutter Webの開発体験とPreview版段階の技術的制約についての解説

https://medium.com/flutter-nyc/under-the-hood-with-flutter-for-web-bc0d5ce1c11e

Tech Preview

  • 現段階の一時的な措置として、Web用に名前空間を分けている。flutter_web/packages/flutter_webは、flutter/packages/flutter/からコードをコピーされている。flutter_web/lib/io.dartのように、dart.io環境を前提としたコードをwebで動かすための一時対応コードもある。

  • Flutter向けpackageは、たとえネイティブAPIとの通信をしていなくとも、FlutterとFlutter Webのpackage名が分かれているので、Flutter Webではまだ使えない。たとえばpackage:providerはFlutterに依存があるためpackageの依存解決ができない。

  • ChromeSafariは対応済みだがEdgeとFirefoxはテストカバレッジが低いので未対応という状態。

  • 現段階では、さまざまな制約が存在する。上記のNYTimesのゲームアプリの作成を通じたFlutter Webの解説記事から引用。

  • Web-specific code that requires the html package. Keeping separate web/mobile/desktop branches is tricky.
  • No native debugger. While Chrome DevTools is great, working with the IDE debugger is a superior experience.
  • Offline persistent storage that works across web & mobile.
  • Dart isolates are not supported in Flutter for web. Javascript is single-threaded.
  • Text input does not yet match platform conventions.
  • Selecting/copying of text is not yet supported.
  • The browser back button works just like the Android back button, but the forward button is not supported yet.
  • Making Flutter for web more SEO-friendly.
  • Printing with a @media stylesheet isn’t yet supported.

エンジン

Under the hood, Flutter for web draws most elements to the canvas directly except text, which is rendered by the browser

https://medium.com/flutter-nyc/under-the-hood-with-flutter-for-web-bc0d5ce1c11e

すべてのUIをFlutter Widgetで書き、Web用にcompileする。

https://css-tricks.com/the-css-paint-api/

  • flutter_web_ui/lib/src/ui/ <-> pkg/sky_engine/lib/ui/

  • flutter_web/packages/flutter_web_ui が、Webプラットフォームに依存したモジュール。ui/dart:uiのコードがコピーされて、一部にWeb対応のための改造がされている。engine/が、Web版Flutter Engine。ネイティブ版はC++Dartで書かれているもの。Web版はもちろんJavaScriptではなくDartですべて書かれている。

flutter_web_ui/libsrc/engine/dom_renderer.dart DOM操作に使用するサブセットを定義している?

  • flutter/engineへのflutter web用エンジンの統合作業が始まっている。

https://github.com/flutter/engine/pull/8891

レンダリング

  • テキスト以外はほとんどCanvasレンダリングしている。Custom ElementとCanvasのカタマリ。位置はabsolute positionやtransformなどで調整。

  • Chromeのdev toolでelementsタブを見ても構造の把握はほぼできない。代わりに、Dart Dev Toolsを開いてネイティブ開発と同様にFlutter専用の開発ツールを使う。

f:id:ntaoo:20190522151648p:plain

  • CSS Paint APIレンダリングするオプションもあるが、ブラウザーのサポート率がまだ低いので、まだ先の話だろう。

  • UIに関しては完全にFlutter frameworkによってDOM APIが隠蔽されている。AngularのDOM APIを拡張する思想とは対照的。

ジェスチャー

JavaScriptのGestureライブラリを使っているわけではなく、あくまでFlutter frameworkのGestureコード(flutter/lib/gestures.dart)をWeb用にコンパイルするようだ(実装は追っていない)。

Widgets

(プラットフォーム依存コードが含まれていなければ)既存のWidgetをそのまま再利用できる。HTML, CSS, JavaScriptのDOM APIを意識することはなく、完全に隠蔽されている。

ルーティング

Flutter WebはSPAとして動作する。History API操作を抽象化するモジュールを内部で使用している。現在は、AngularDartのルーティング関連モジュールをコピーしている。Flutterのnamed routingでコードを書くと、WebではUrlにpathがつく。paramとquery paramをハンドリングする方法は分からなかった。自分のFlutter力が足りないだけの可能性もある。

  • 最悪、Flutter Web起動時の処理としてdart:htmlを使ってparamとquery paramを取得してFlutter Webに渡せばいけるだろうが、その前にquery paramsがあるとhomeにredirectされてしまう動作を観測している。

  • History push時にquery paramsを指定したい。

  • もしparamsとquery paramsをハンドリングする仕組みがまだないならば、さすがに現段階で実用的なWebアプリを作るには制約が強すぎる。

  • 404ページにする方法もまだ調べていない。

  • 当然、<a></a>tagを書くことはできない。外部リンクを開く方法は調べていない。url_launcherのような仕組みを使うのだろうか。

  • その他、Matrix Paramsのような慣習的な記法をFlutter Webはサポートするのだろうか。

アクセシビリティ

src/engine/semantics/でFlutterのSemanticsARIAコンパイルしている。まだ発展途上のようだ。

ペイロードサイズ

  • Flutter Web Hello World サンプルアプリで146KB zip。これから開発が進むにつれて削減されていくだろう。
  • アプリが大規模になれば、AngularDartのDeferred Loadingのような起動時のペイロードサイズを削減する仕組みがWebアプリでは必要になるが、いまのところそういったものはないようだ。
  • AngularDartと同様、普通のアプリならば全体で300KBから500KBくらいになるはず。

アニメーション

まだカクカクする。改善作業中とのこと。もちろん、CSSやWeb AnimationといったWeb APIを直接操作することはない。

JavaScriptライブラリの利用

  • プラグインシステムはまだ設計段階。
  • 現段階では、dart:htmlpackage:jsを使って直接操作する。

未実装API

一部のAPIは未実装のようだ。たとえばGradient APIが未実装で、実行時にUnimplemented Errorを観測した。

SEO

  • SSRも技術的には可能そうだが、アプリケーションコードをSSR対応にするために条件分岐したりstateの引き継ぎをしたりするのはとてもダルいので、可能でもやりたくないなという感想。
  • DartをJSにコンパイルすると結局EcmaScript 5になるし、Google Search Botは最新版Chromeになることが発表されたので、レンダリングに問題は起きないだろう。とはいえ、レンダリング方法がかなりアグレッシブなので、Google Botからどう見えているのか、実際にGoogle Search Consoleなどで動作テストしてみないと怖い。
  • OGPなどのhtml headに配置するメタデータは当然サーバーでレンダリングしておく必要がある(SSRではなく。ややこしい)。
  • CDNレンダリングなど、状況は変わりそう。

構造化データ

HTMLを書けないので、Schema.orgMicrodataをどうやって指定するのか。HTML埋め込み機能が必要になるのだろうか。

所感

歴史的事情が積み重なって複雑で扱いづらいHTML, CSS, JavaScriptを、Flutter Frameworkが隠蔽して古層にしてくれる。

iOS, AndroidのネイティブアプリをFlutterで開発する際でも、プラットフォームの事情を知らなければハマることもあるので、Webでも同じようにプラットフォームの知識は必要になるが、これまでのようにWeb APIの進化に精通する必要性はだいぶ薄れていくはず。Extensible Webの思想的には喜ばしいことでは。

Flutter Frameworkが隠蔽してくれる代償として、Frameworkの抽象から漏れたWebの機能を利用しづらくなりそう。(たとえば、いま話題のPortalとか。)Web Standardへの対応は進んでいくだろうけど、それまでは生のHTMLやAngularDartなどの従来型のソリューションとの併用が必要になるはず。Flutterがすべてのユースケースに対応するかについてはまだ懐疑的だけど、長期的にはなんとかしてくれそうという期待感はある。

AngularDartは、DOMを拡張する思想のフレームワークなので、Webに特有の要求仕様に対応した詳細な制御が可能。DOMを完全に隠蔽するFlutterとは対照的。詳細な制御ができるが、HTMLやCSSを扱う必要があるので、Flutterに慣れるとそれがとても面倒に感じる。UI以外はAngularDartとFlutterで共有可能なので、AngularDartでWebアプリを書きつつ、Flutter Webの適用可能範囲が広がってくればFlutterでUIの置き換えを検討する戦略。

WebにはAndroidiOSにあるような統一されたデザインガイドラインがあるわけではない。マテリアルデザインiOSデザインの採用を拒否したり理解度が低いプロジェクトではFlutterの高い生産性を発揮しにくそう。現段階では、ペライチ用途やWebサイト用途には向いていない。まずはSPA Webアプリ向け。