Dartで開発するときのディレクトリ構成

Dartで開発する上で`pub`は欠かせないツールですが、`pub`を利用するプロジェクト（以後 **pubパッケージ** と呼ぶ）内のディレクトリ構成に大きく依存しています。これは自分の作ったパッケージをpubに公開する、しないにかかわらず重要なポイントなので、一度きちんとおさらいしておこうと思います。  

この記事では公式ドキュメントの[Pub Package Layout Conventions](https://www.dartlang.org/tools/pub/package-layout.html)に書かれている内容を和訳して注釈を入れつつまとめていきます。

# 基本構成
pubパッケージの最小構成は以下になります。

```
enchilada/
  pubspec.yaml
  pubspec.lock
```

`pubspec.yaml`さえあれば一応pubに公開することが出来ます。他にも`LICENSE`や`AUTHORS`等のファイルはこの階層（トップレベル）においておくことが推奨されます。

# README.md
pubに公開するパッケージにはMarkdown形式のREADMEを含めることが推奨されています。

```
enchilada/
  ...
  README.md
```

トップレベルに置かれた`README.md`は[pub.dartlang.org](https://pub.dartlang.org)で見ることができるので、なるべくパッケージの内容や使い方がすぐに分かるような内容を心がけるといいですね。ちなみにAngularDartのREADMEは[このように](https://pub.dartlang.org/packages/angular)なっています。

# CHANGELOG.md
READMEと同様に、CHANGELOGもpubのページで見ることができるので、ぜひ書きましょう。

```
enchilada/
  ...
  CHANGELOG.md
```

ちなみに`unittest`パッケージのCHANGELOGは[こちら](https://pub.dartlang.org/packages/unittest)

# 公開ライブラリ
公開ライブラリは以下のように`lib`ディレクトリ内に配置します。

```
enchilada/
  lib/
    enchilada.dart
    tortilla.dart
```

## 公開ライブラリとは？
公開ライブラリとは、そのパッケージを`pub install`で導入した後、`import`文で読み込むことが出来るdartファイル群のことを指します。AngularDartであれば`angular/angular.dart`等が公開ライブラリに含まれています。  

## どう使えばいいの？
### ライブラリとして公開する
そのままですが、pubにライブラリを公開する際は、公開ライブラリとして配置しなければなりません。

### シンボリックリンクの生成に利用する
こちらのほうが実は重要で、`pub get`を実行すると、`pubspec.yaml`に書かれた依存関係を解決するだけでなく、 **『公開ライブラリとして配置された`lib`以下のコードへのシンボリックリンクを`packages`以下に貼り、擬似的にpubでインストールしたように見せる』** ことができます。これが何を意味するかというと、ライブラリ用のパッケージと、ユニットテスト用のパッケージを分けることができるということです。テストに関する配置に関してはまた後述します。

# リファレンス用パッケージ
公開したアプリケーションのデモ用のページを含めることがよくあります。pubパッケージでは次のように配置します。

```
myapp/
  example/
    one/
      sub/
        index.html
```

`example`に配置するのはあくまでライブラリの動作サンプル等であり、Webアプリケーションは後述する`web`ディレクトリ内で開発します。

# 公開アセット
pubに公開されているのはdartライブラリだけではなく、[boostrap_for_pub](https://pub.dartlang.org/packages/bootstrap_for_pub)のように、cssやhtml、jsのセットだけを提供しているものも多くあります。そのようなdartファイル以外のものを **アセット** と呼びますが、ライブラリとして公開したいアセットは以下のように`lib`ディレクトリに配置します。

```
enchilada/
  lib/
    guacamole.css
```

このように配置されたアセットを利用する場合は次のようにhtmlから参照可能です。

```
<link href="packages/enchilada/guacamole.css" rel="stylesheet">
```

# 実装ファイル（非公開コード）
公開ライブラリとして公開しているコードではimportしているが、外部からはされたくないということはよくあることです。以下のように`lib/src`内に配置したdartファイルは`lib`内でのみ公開されます。

```
enchilada/
  lib/
    src/
      beans.dart
      queso.dart
```

# Webファイル
Webアプリケーションを作る際はhtml等を以下のように`web`ディレクトリ内に配置します。

```
enchilada/
  web/
    index.html
    main.dart
    style.css
```

`web`ディレクトリ内に配置されたファイル群は`pub build`や`pub serve`のビルド対象になります。

# コマンドラインアプリ
コマンドラインで直接実行するタイプのアプリケーションを公開する際は以下のように`bin`ディレクトリに実行ファイルを配置します

```
enchilada/
  bin/
    enchilada
```

# テスト・ベンチマークコード
テストコードは以下のように`test`ディレクトリ内に配置します。

```
enchilada/
  test/
    enchilada_test.dart
    tortilla_test.dart
```

`test`ディレクトリから読み込むことが出来るのは`packages`ディレクトリだけなので、テストを行いたいコードは、先述の`lib`ディレクトリに配置して`pub get`でシンボリックリンクを生成しておく必要があります。逆に言うと、 **`lib`フォルダ以外に置いたdartファイルはテスト出来ません。** 

また、テスト用のファイルは`テスト対象のファイル_test.dart`にするのが慣例です。   

ベンチマーク用のコードは以下のように`benchmark`以下に配置します。

```
enchilada/
  benchmark/
    make_lunch.dart
```

## 余談
テストに用いる`unittest`パッケージは有名ですが、ベンチマーク用にもDart開発チームが`benchmark_harness`というパッケージを公開しています。使い方は[こちら](http://www.dartdocs.org/documentation/benchmark_harness/1.0.4/index.html#benchmark_harness)で、同じコードを10回実行した時の平均時間をレポートしてくれたりとけっこう便利なパッケージのようです。

# ドキュメント
ドキュメントファイルは以下の用に`doc`ディレクトリ内に配置します。

```
enchilada/
  doc/
    getting_started.md
```

ちなみにDartSDKには`docgen`というツールが内蔵されていて、`$ docgen`を実行すると`docs`ディレクトリ内に`lib`以下のコードをドキュメントにしたjsonファイルが発行されますが、`doc`ディレクトリのものとは別なので注意してください。`doc`ディレクトリに置くのはdocgenで吐き出されるAPIリファレンスを補足するためのチュートリアルやガイド、その他手書きのドキュメントです。

# サンプルコード
Dartライブラリの使い方としてサンプルコードを公開する際は以下のように`example`ディレクトリ内に配置します。

```
enchilada/
  example/
    lunch.dart
```

# 内部ツール・スクリプト
開発に使うツールやスクリプトは以下のように`tool`ディレクトリ内に配置します。

```
enchilada/
  tool/
    generate_docs.dart
```

`bin`ディレクトリとの違いは、`tool`ディレクトリはパッケージ開発者向けであって、外部に公開されるものではないということです。

----

これでpubパッケージのディレクトリ構成についての解説は全てです。実際に使うのは`lib`、`web`、`test`くらいのもので、全部を使うことはないと思いますが、覚えておくといざというときに役に立つと思います。