JSに似て読み書きしやすいシンタックスに加え、型推論やジェネリクスなど魅力的な機能を備えたDart。JavaScriptに変換する仕組みがある点や、iOS、Android、Webの3大Clientで使える言語を目指して設計されている点を踏まえると、DartでのWebフロントエンド開発も夢ではないように感じます。

ただ、言語がよければすぐに使えるというわけではなく、使いやすさや開発環境も大切な要素の1つです。
昨今のWebフロントエンドはできることが増え、それに伴いエコシステムもとても進歩していて、複雑で大規模な開発でもスムーズに行えるようになってきている印象です(1番最初の環境構築が大変とよく言われますが、その大変さも徐々に緩和されてきていると思います)。

そこで、DartでのWebフロントエンド開発がどの程度現実的なのかを「エコシステム」という観点でまとめてみました。各々のツールの簡単な使い方も併記しています。

1. Dart SDK

Dart SDK はDartの開発に必要なライブラリ群とCLIツールです。執筆時点では安定版の1.24.3と、プレリリース版の2.0.0-dev.69.2が存在します。

2018/08/08 追記

Dart2.0.0が正式にリリースされ安定版となりました。記事内でDart1.xへの言及がところどころありますが、これからDartを使い始める場合はDart2.xを利用するのが良いと思います。
$ brew tap dart-lang/dart
$ brew install dart         # 安定版をインストールする場合
$ brew sintall dart --devel # プレリリース版をインストールする場合

なお、Web開発のためにDartをインストールする場合は、インストール時に--with-dartium --with-content-shellオプションをつけるよう推奨されることがありますが、これらはDart1.xでのみ利用するものです。DartiumはDartVMを内蔵するブラウザで、content shellは同じくDartVMを内蔵するテスト用のヘッドレスブラウザですが、Dart2.xでは開発環境が大幅に変わりこれらが不要となったためです(開発環境の詳細は後述します)。

2. パッケージ管理ツール pub

DartSDKをインストールすると併せてpubというパッケージ管理ツールがインストールされます。パッケージの依存関係とバージョン情報を載せたファイルを用意してコマンドで一発インストール、というnpmでもお馴染みのものです。

pubspec.yaml

依存するパッケージそのバージョン情報などを記しておくファイルです。package.jsonのような役割をします。npmと使い方が似ているので、とっつきやすくてありがたいですね。

name: Sample
version: 1.0.0
description: Sample project
author: Aloerina
environment:
  sdk: '>=2.0.0-dev.68.0 <3.0.0'
dependencies:
  bootstrap_sass: ^4.1.2
dev_dependencies:
  build_web_compilers: ^0.4.0
  test: '>=0.6.0 <0.12.0'

強いて言うなら、依存パッケージを追加するときにエディタで直接修正する必要があるのは少し面倒だと思いました。Dart Packagesでインストールしたいパッケージを調べpubspec.yamlへの記述方法を確認しコピペする…というのはやはり手間です。

den

そこで助かるツールがdenです。pubspec.yamlの初期化や依存関係の追記をしてくれるCLIツールです。npm initnpm install -S <package名>に相当するツールですね。

$ pub global activate den   # denのインストール
$ den spec                  # pubspec.yamlの生成
$ den install <package名>   # 依存関係の追加

pubの基本コマンド

pub get

pubspec.yamlに書かれている依存ライブラリを一括インストールしローカルにキャッシュします。同時に、初回であればpubspec.lock.packagesが作成されます。前者は名前の通りバージョンのロックファイルで、後者はローカルのどのディレクトリにキャッシュしたかを記すファイルです。ローカルキャッシュから再インストールする場合は--offlineオプションを使います。

pub global activate

npm install -gと同じです。パッケージをグローバルにインストールします。

pub run

pub getpub globalでインストールしたexecutable(CLIから実行可能な)packageを実行します。

$ pub run [package名]
$ pub global run [package名]
pub upgrade

依存パッケージのバージョンを最新にあげ、pubspec.lockの内容を更新します。

npmとの比較表

npm pub (den)
npm init den spec
npm install pub get
npm run [npm_script名] pub run [package名]
npm install -g [package名] pub global activate [package名]
npm install -S [package名] den install [package名]
npm install -D [package名] den install –dev [package名]
npm upgrade pub upgrade
npm ls pub deps

pub用語

npmと同じ感覚でドキュメントを読み進めていくと齟齬が出る(出た)用語をピックアップしておきます。詳細は公式の用語集からどうぞ。

Application package / Library package

Application packageとLibrary packageは対義語です。Application packageとはコマンドラインやブラウザから直接呼び出させるpackageを指し、Library packageはApplication packageからライブラリとして利用されるpackageです。

Entrypoint

意味合い的にはJavaScriptを実装するときと同じなのですが、Dartにおいては一般的にmain()が実装されている.dartファイルがエントリーポイントとなります。

3. projectの雛形構築ツール stagehand

stagehandというツールを利用してDartのプロジェクトの雛形を作ることができます。Reactでいうcreate-react-appやVueでいうvue-cliのようなものです。グローバルにインストールして雛形を作りたいディレクトリで実行します。

$ pub global activate stagehand
$ mkdir first_project
$ cd first_project
$ stagehand [template名]

Templateは現時点で6種類ありますが、Webアプリ開発用は

の2つです。web-simpleでプロジェクトを作ってみたところ、HelloWorld的なHTML/CSS/Dartファイルとpubspec.yamlなどが用意されました。雛形が用意されたあとは依存するpackageをインストールしてローカルサーバを立ち上げればブラウザで確認できます。このあたりもnpm installからのnpm startと同じ流れなので理解しやすいしお手軽でした。

$ pub get       # 依存packageのインストール
$ webdev serve  # ローカルサーバの起動

サーバの起動に使っているwebdevについては後述します。

4. コンパイラとビルド環境

Dartで作られたWebアプリを実行するには、DartVMが搭載されたブラウザで直接実行するか、JavaScriptにコンパイルしてから標準ブラウザで実行するか、の2つの方法があります。開発やテストといった過程では前者でも十分ですが、リリースするには後者の方法をとる必要があるため、用途に応じてコンパイラや実行環境を使い分ける必要があります。

Dartのコンパイラにはどんなものがあるのかと、それぞれのDartバージョンでどのようにそれらを使えばよいかをまとめておきます。

2つのコンパイラ dart2js と DDC

Dart-to-JavaScript Compiler(dart2js)はDart1.xから存在するコンパイラです。コードの最適化をしたりminifyなどのオプションがあったりと本番用のコンパイルができるだけでなく、問題のある箇所をワーニング表示したりと開発用に利用することもできます。

Dart Development Compiler(DDC)はDart2.xで登場したコンパイラです。その名の通り開発用に特化しており、差分ビルドホットリロードに対応しています。

Dart1.xでのビルド環境

dart1.xでは、開発時はDartVMを搭載したDartiumcontent shellを利用し、リリース時にはdart2jsでコンパイルしてjsを生成します。それぞれpubコマンドを利用して行えます。

  • pub serve … ローカルサーバを起動します。Dariumで確認することができます。
  • pub build … dart2jsを実行します。

Dart2.xでのビルド環境

Dart2.xではDartVMを一切使わずに開発できます。そのためDartiumもcontent shellも必要なくなります。
またDart2.xではbuildやserveのコマンドを、pubの代わりにwebdevというCLIツールを使って行います。webdevはpubからインストールして使います。

$ pub global activate webdev

コマンド名はpubでビルドするときと同じなのでDart1.xから2.xへマイグレーションした場合も気楽そうです。

  • webdev serve … DDCを実行しローカルサーバを起動します。標準ブラウザで確認することができます。
  • webdev build … dart2jsを実行します。

まとめ

  for release for development
Dart1.x pub build
dart2jsでjsを生成
pub serve
Dartium, content shell などのDartVM上で直接実行
Dart2.x webdev build
dart2jsでjsを生成
webdev serve
DDCでコンパイルしたものを標準ブラウザで実行

build_runner を使ったビルドのカスタマイズ

webdevを使えば特別な設定なくすぐにビルドを行えますが、build_runnerを使ってビルドをカスタマイズすることも可能です。簡単に言うとタスクランナーのようなものです。

まずはインストール方法から。pubspec.yamlにdependencyを追記してpub getします。

dev_dependencies:
  build_runner: ^0.9.0
  build_web_compilers: ^0.4.0

次にコンフィグファイルを用意します。build_runnnerはデフォルトでbuild.yamlという名前のファイルを読み込んで実行しますが、build.hoge.yamlと命名すればオプションをつけて指定することができます。

$ pub run build_runner build                # build.yamlを読み込む
$ pub run build_runner build --config hoge  # build.hoge.yamlを読み込む

webpackの設定ファイルを本番用と開発用で分ける時にwebpack.config.prod.js/webpack.config.dev.jsとするケースがありますが、同じような感覚で使えそうです。

あとはコンフィグファイルの中身次第でビルドをカスタマイズできますが、詳しい設定の仕方については情報が多いのでいずれ別記事にて。

sassのビルド

DDCを使えばホットリロードに対応できると書きましたが、sassも同様にあるべきです。これは公式のツールでは(原時点では)対応できないのでライブラリを利用します。sass_builderpub getして、build_runnerで実行するよう設定します。

pubspec.yaml

dev_dependencies:
    sass_builder: ^2.0.0

build.yaml

targets:
  $default:
    builders:
      sass_builder:
        options:
          outputStyle: compressed

これでwebdev serveをすればsassのビルドも実行されます。

別の方法として、sassは今まで通りnode-sassなどを使うというのもアリだと思います。それなら既存のビルド環境を引き継いで使えますし、無理に全部Dartに寄せなくてもいいかもしれませんね。

5. 感想

一通り触りながら簡単な実装をしてみた感想は「それなりに揃っている」でした。npmなどと比較してみても必要なものは最低限あるし、簡単に利用するための仕組みも用意されています。本気でWebクライアント開発言語になろうとしていることを感じられました。

また、DartはWebだけでなくネイティブアプリの開発も視野に入れていて、こちらも入門しやすい仕組みが用意されていました。WebフロントエンジニアがDart × Flutterに入門した話に詳細をまとめてありますので、よければ併せてどうぞ。

一方で「productionレベルで利用できるか」については即答できなさそうです。productionで利用するには信頼のおけるライブラリや大規模アプリに向くフレームワークなども必要でしょうし、dart2jsの最適化の品質についても検証の余地があると思います。そういったことも今後検証してみようと思いますので、一緒にDart × Webフロントエンドを盛り上げていきたい!という方はぜひ@aloerina_までご感想・ご意見をお願いします。

6. おまけ 公式ドキュメントの読み方

Dartはドキュメントが豊富なのがいいところですが、体系的に理解するには何から読めばいいのか…と少し悩みました。ので、最後に私が読んだドキュメントをまとめて締めくくります。