DartでWebアプリを

リリースした話

Me

  • https://mylexicon.io
  • Angular (Dart) : 自社プロダクトにて採用済み🤗
  • Angular (TypeScript) : お客様プロダクトにて採用済み😇
  • Dart、Angularのご相談、導入支援承ります

@ntaoo (twitter, github, etc)

アジェンダ

  • なぜDartなのか
  • Dart for WebとAngularDart
  • Flutter
  • 事例紹介: MyLexicon ( https://mylexicon.io )

なぜDartなのか

  • アプリケーション開発の大統一言語となれる潜在能力
    • Web : AngularDart, JavaScript compilers
    • Native App : Flutter for Android, iOS, and...
    • Server, Cli : dart:io
  • バランスのとれた実用的な言語仕様
  • 充実したスタンダードライブラリ
  • 各分野で、キラーフレームワーク、ライブラリが提供
  • Dart Team以外によるライブラリ開発も活発化

なぜDartなのか

  • 学習コスト低
    • Java、JavaScriptを学んだプログラマーにとって違和感がないように配慮
    • 両言語のイケてない点は引き継がず
    • 産業界での評価が確立された要素を手堅くまとめたシンプルな言語仕様
    • Dartの経験が浅くともすぐに高い生産性を出せる
    • Don't surprise the programmer

なぜDartなのか

  • DX (Developer Experience) 最高
    • 言語仕様が安定。やみくもに仕様を膨らませない強い意志
    • 安定してハイパフォーマンス
    • 環境構築が非常に楽。つまずかない
    • スタンダードライブラリのDoc Commentが充実
    • スタンダードライブラリのソースコードを読もう!
      • Dartコードのお手本

なぜDartなのか

  • DX (Developer Experience) 最高
    • 型安全性が高く、なおかつコンパイルが速い
    • Edit & Refresh開発余裕
    • Hot Reloading (Flutter)
    • Dartanalyzerによるエディタサポート
      • 静的解析による瞬時のエラーフィードバック
      • 補完、リファクタリングサポート
      • 柔軟なlint、dartfmt、etc...
      • ビルド職人不要

なぜDartなのか

  • 非常に活発なSDKの開発
  • すでに5万commits以上
  • "Dart is an ambitious, long-term project." (from https://www.dartlang.org/)

なぜDartなのか

なぜDartなのか

なぜDartなのか

  • Javaの皮を被ったSmalltalk(だった)
    • Dart1.0の言語デザイナーがSmalltalker
    • コアメンバーにSmalltalk VM研究の経歴など
    • (ほぼ)全てがObjectへのMessage送信で動く世界
    • 初期は明らかに、DartVMによってSmalltalkの世界Webにもたらそうとしていた
      • DartEditor + Debugger, ChromeDevEditor
      • Snapshot
      • Mirror based reflection
      • 動的言語 + Optional Pluggable Type System
      • Live Programming, etc...

なぜDartなのか

  • Javaの皮を被ったSmalltalk(だった)
    • ChromeへのDartVM非搭載の決定により方針変更😢
    • 型安全性とAoTコンパイル重視へ(Strong mode)
    • デプロイ後にDartVM上で動作するのは今のところServer SideおよびCliコードのみ
    • Flutterは開発時はDartVMで動作させ、リリース時にネイティブコードにAoTコンパイル
    • Web向けはdartdevc(開発)およびdart2js(リリース)

なぜDartなのか

  • JavaScriptの
    • 基礎が杜撰で混沌とした言語仕様が嫌いな人
    • さまざまな罠ともう付き合いたくない人
    • 移りかわりの激しいエコシステムに疲れた人
    • 環境構築で疲弊したくない人
  • シンプルでプラグマティックな言語が好きな人
  • Javaの経験がある人
  • プログラミング初心者

 

Dartを試してみましょう

 

なぜDartなのか

  • Dartに向かない人
    • 欠点を含めてJavaScriptを愛している人
      • JavaScriptグル
      • JavaScriptソムリエ
      • バッドノウハウ収集に妖しい魅力を感じる人
    • メジャーな言語が好きな人
      • (日本語)の情報がたくさんある
      • すぐに周りの人に聞ける (大事なことですよね)
    • ドラフト版WebAPIをいち早く評価してみたい人
      • 最近dartdevcが安定してきたので、あえてDartからinteropコードを書いて試してみるのもあり?

Dart for WebとAngularDart

Dart for Web

  • Dartdevc (DDC)
    • 開発用コンパイラ

    • ES6がコンパイルターゲット

    • 最近安定してきた

    • コンパイル速度とデバッガビリティ重視

    • 1秒から10秒ほどでコンパイル

      • AngularDartでのユースケースでもうすこし速くなって欲しい

Dart for Web

  • dart2js
    • リリース用コンパイラ

    • パフォーマンスとサイズを最適化

    • コンパイルに30秒から90秒ほどかかる

Dart for Web

  • dart:html
    • Dartから自然に扱えるように整備されたWebAPI

    • 大部分はWebIDLから生成されたJS Interop API

    • Experimentalなドラフト版WebAPIを使いたければ、自分でpackage:jsを使ってInteropコードを書く必要あり

    final div = new DivElement()
      ..id = "anElementId"
      ..classes.addAll(['aClass', 'anotherClass'])
      ..style.color = 'red'
      ..children.add(new Element.span()..text = 'The inner text.')
      ..onClick.listen(handleOnClick);
class ScrollPreventing {
  final Element _element;
  final List<int> _targetKeyCodes = const [
    KeyCode.SPACE,
    KeyCode.PAGE_UP,
    KeyCode.PAGE_DOWN,
    KeyCode.END,
    KeyCode.HOME,
    KeyCode.LEFT,
    KeyCode.UP,
    KeyCode.RIGHT,
    KeyCode.DOWN
  ];
  StreamSubscription<Event> _eventSubscription;
  bool _isPreventing = false;

  ScrollPreventing(String selector) : _element = querySelector(selector);

  bool get isPreventing => _isPreventing;

  set isPreventing(bool prevent) {
    if (prevent) {
      _eventSubscription = StreamGroup.merge<Event>([
        _element.onMouseWheel,
        _element.onTouchMove,
        _element.onKeyDown.where((e) => _targetKeyCodes.contains(e.keyCode))
      ]).listen((e) => e.preventDefault());
    } else {
      _eventSubscription?.cancel();
    }
    _isPreventing = prevent;
  }
}

Dart for Web

dart:htmlで、KeyCodeを始め

さまざまなconstantを定義済み

dart:asyncが標準でStreamを提供

package:async (from Dart Team)

Event propertyも定義済み

DOM APIとDartの自然なシナジー

ElementStream<KeyboardEvent>

Dart for Web

  • XSS対策 -- NodeValidator, NodeTreeSanitizer
    • ​ホワイトリスト方式
    • dart:htmlにて標準装備
    • AngularDartを使用してもこういった低水準DOM APIを活用するユースケースは存在
final sanitizer = new NodeTreeSanitizer(new NodeValidatorBuilder()
    ..allowHtml5()
    ..allowElement('XREF'));

element.setInnerHtml(htmlString, treeSanitizer: sanitizer);

Dart for Web

DOMを扱うのが

格段に楽になる

ほんとうに楽

AngularDart

  • もうひとつのAngular
  • 15ヶ月ほど前にAngular(TypeScript)からFork
    • AngularJS
    • -> AngularDart (ver 1)
    • -> Angular (ver 2) with TypeScript
    • -> AngularDart (ver 2~)
  • Angular または AngularDartと呼ばれる
  • 複雑な経緯

AngularDart

  • Angular (TypeScript)チームとは相互に成果を共有
  • 基本的な思想、大部分のAPIはTypeScript版と同じ
  • 最近は徐々に離れていっている印象
  • TypeScript版を知っていればDart版も分かる。逆も同じ
  • dart:htmlの基盤の上に構築
  • Dartの充実したスタンダードライブラリとエコシステムを利用
  • 既に大規模開発の実績
  • AdWords, AdSenseというGoogleの収益にとってクリティカルなアプリがAngularDartでリニューアルされた

AngularDart

  • AngularComponents : TypeScript版のmaterial2に相当
  • SSRの仕組み無し😇😇😇
    • SPAとしてのパフォーマンス向上を優先し、TypeScript版にあるような抽象化層を除去
    • Issueは上がっている

AngularDart

  • SSR 😟😤😟
  • 本質的に、必要?

    • たしかにマシンリーダブルなwebとの親和性は低くなる

    • そもそもBot側がJSを理解すべき?

    • Webアプリの起動時間が長い現在のブラウザの仕組みが貧弱なのでは

  • とはいえ、現状のwebでは需要は高い

    • 過渡期

  • SEOという、ビジネスの収益に大きな影響が出る要素

  • UXとSEOの間のジレンマ

  • 奇妙すぎる

Flutter

  • Dartによるネイティブアプリ開発フレームワーク
  •  iOS, Androidに対応
  • シングルコードベース
  • ネイティブプラットフォームのUIライブラリのバインディングでなく、Dart製独自UIライブラリを整備
  • iOSのUIの仕様追加、変更にも迅速に対応
  • Flutterチームへの信頼感がある
  • 同カテゴリにはReact Native, Xamarin, Cordova等

Flutter

  • 最高!
  • 絶賛の声が多い
  • 盛り上がっている感がある
  • まだα版

MyLexicon

  • https://mylexicon.io
  • 英語力の基礎となる語彙力、表現力等を最小の労力で増大させる学習アプリ
  • 現実世界の英文を読むことを通じ、そこで出会う分からない単語、表現等、覚えたいもののみ登録し、学習対象にする
  • SRSでリマインド
  • 主にESL(English as a Second Language) Learner 向け
  • 日本人で英語を学んでいる人ももちろん対象
  • Native Speakerでも、6〜18歳くらいの語彙を構築中の子供に刺さる可能性

MyLexicon

Webページを読んでいるときに出会う知らない単語、表現等を選択して、MyLexicon Dictionary ChromeExtensionを起動すると、その定義と例文が表示される。

さらにそれをそのコンテキスト(センテンス、ページURL、ページタイトル)と共にMyLexiconに登録する。

定義が辞書になくても、英文であればなんでも登録可能。

真似したい言い回し等覚えたいものをかたっぱしから登録しまくる。

MyLexicon

間隔を空けてReviewを繰り返し、記憶に定着させる(SRS)

MyLexicon Dictionary = 英英辞典と登録済みLexical Itemsおよびその学習状況の表示を統合

MyLexicon

  • 今後の開発予定

    • UI for Mobile Web 😅

    • Much Better landing page

    • Ads

    • Review system ver.2

    • Web push notification for the review.

    • Web payments support for the subscription service

    • Flutter (including adding a lexical item feature)

    • Web Extension for Firefox, Edge

    • Much much more...

  • 収益化をめざしてやっていく

MyLexicon

 

  • Dartを選択した理由

    • すべての領域に対応可能

      • Web, Native Mobile, Server, Cli

      • スモールスタートからダイキボ開発まで

    • 言語の統一による

      • コードの共通化

      • 言語間思考コンテキストスイッチの無さ

    • Dart自体の快適さ、高生産性。DXが最高

MyLexicon Architecture

package:

web_app

AngularDart

package:

web_extension

AngularDart

Flutter

 (予定)

package:

shared_components

AngularDart

 

Plain Dart, without dart:html

(But, still depends on Angular DI)

package:model

  • App models
  • Entities
  • Values
  • Repositories

Firebase

For Static Hosting, Authentication

package:server

On GCP

Communicate with other API services

package:

client_server

MyLexicon

  • web_appとweb_extensionでcomponentsを共有
    • MyLexicon Dictionaryの機能、UIはそれなりに複雑
    • しかしweb_appでもweb_extensionでもほぼ同じ
    • Componentsとmodelを共有したい!
    • -> package:shared_components

<mylexicon-dictionary></mylexicon-dictionary>

MylexiconDictionary componentおよび

関連modelを

web_appとweb_extensionで共有

MyLexicon

  • Flutter対応をにらみ、ViewControllerとModelを厳格に分離したい
    • -> package:modelに分離
    • しかしAngularからDI機能が分離されていないので、いまのところpackage:modelはpackage:angularに依存

MyLexicon

  • package:modelとpackage:serverでコードを共有したい
    • -> package:client_server
    • Entity schema interfaces and some methdos
    • Validation rules
    • Other constants

MyLexicon

  • Firebase最高
    • package:firebase
    • firebase APIのJS Interop
    • Dart TeamメンバーとFirebaseメンバーが協力してメンテナンス
    • firebaseのアップデートにきちんと対応してメンテナンスされている安心感
    • Flutter用firebase packageもアクティブにメンテナンスされている

MyLexicon

  • ツラミの共有 - Chrome Extension
    • package:chromeを利用してJS Interop
    • コード変更内容の反映にはpub buildが必要
      • debug buildでもbuild時間60秒。辛い
      • dartdevcは機能せず
        • dartdevcでもbuildに60秒かかる
        • DOMの構築に失敗しruntime errorになる
      • Browser ActionのAngularによるUI Component部分はあらかじめpackage:web_appで構築、確認しておくと良い

MyLexicon

  • ツラミの共有 - package:chromeのバグ
    • chrome.runtime.sendMessage, chorme.runtime.onMessageが動かない
      • browser action, event page, content script間の通信を司るクリティカルなAPI
      • かなり前からissueがopenのままfixの気配なし
      • WebIDLからinterop codeを自動生成しするワークフローのため、bug fixのcontributeが困難
      • 自力でinteropコードを書いて解決
    • package:chrome ドッグフーディングされていないのでは😅

MyLexicon

  • それでもAngularDartとpackage:chromeでChrome Extensionを作る理由
    • 型システムの支援が受けられる
    • Angular componentsの共有によりbrowser actionのUI構築が辛くない

MyLexicon

  • package:chromeはたぶんWeb Extensionに対応していない
    • 名前空間が異なる
    • いざとなったら自力でinterop codeを書く
      • そんなに難しくない
      • けっこう簡単

MyLexicon

  • Chrome Extension Inline Installationに対応するDart APIが見当たらなかった
    • Chrome専用の「ブラウザ」API
    • package:chromeは対応していない
      • chrome appおよびextension用packageなので
    • dart:htmlも対応していない
      • Chrome専用APIだから?
    • 自力でinteropコードを書いて検証した
    • 詳しくは以下の記事にまとめた
    • https://qiita.com/ntaoo/items/7b66c2448b5c47c2bbb4

MyLexicon

  • Angular UI Componentライブラリの不足
    • package:angular_components
      • AngularDart用google公式package
        • 現在もまだ基礎的なcomponentsが不足
        • コードの質は高いがいまのところStyleのカスタマイズ性が低い
          • ::ng-deepを使いまくってしのぐ😇
        • 最近まで、一年以上preview releaseのままだった

MyLexicon

  • Angular UI Componentライブラリの不足
    • package:angular_componentsが充実するまでの間は、angular/material2からcomponentを移植してしのいでいた
      • 今でもMyLexiconのcomponentにはmaterial2由来のcomponentが複数存在
      • レイアウト系componentsは安易に外せない
        • UX、Layout、Styleへのインパクトが大きいため
    • 良い勉強になった😇
    • 他、汎用UIコンポーネントを独自開発
      • そんなに難しいことはしていない

MyLexicon

  • DartiumとDartdevc
    • Dartium
      • 最新のChromeからver10くらい遅れている
      • Dartiumで動いてChromeで動かなかったり表示が崩れたりを複数回経験
      • とはいえコードの変更反映の更新は非常に速いので重宝していた
      • Dart2.0で引退予定とアナウンス済み
      • 代わりに、Dartdevcを使う

MyLexicon

  • DartiumとDartdevc
    • Dartdevc
      • 最近までやや不安定。最近やっと安定してきた印象
      • Dartiumと同等の1秒以下での更新を期待
      • MyLexiconでは現状、5~10秒かかっている
        • AngularDartでしかもpackageを分けているので依存関係が影響している?
        • もっと速くなってほしい
      • * 注)個人の印象です

まとめ

  • Dart良い
  • 過小評価されすぎ
  • 今が始めどき
  • Dartはこれから人気がでそう
  • コミュニティの盛り上がりもこれから
  • AngularDartとFlutterという2大キラーフレームワーク
  • まだ辛いところもあるけど、なんとかなる(なった)
  • 一緒にDartで楽をしましょう

AngularDartでWebアプリをリリースした話

By ntaoo

AngularDartでWebアプリをリリースした話

  • 2,584