【Flutter】肥大化したimport文を整理する方法3選

## はじめに
本投稿は[Flutter Advent Calendar 2024](https://qiita.com/advent-calendar/2024/flutter)の8日目の記事です🎄

もうすぐ年末ということで、大掃除のシーズンも近づいてきましたね。
部屋もそうですが、Flutterプロジェクトが散らかったままの方もいらっしゃるかもしれません。
特に、import文が散らかっていて「お母さんに叱られてしまった」という経験を持つエンジニアの方は多いのではないでしょうか。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017091/e609111d-17f7-4d17-64ec-c6c890858294.png" width="400">

*お母さんに叱られる例*

年末にお母さんから叱られるのを防ぐには、あらかじめimport文をお掃除しておく必要がありそうですね...。

## 未整理のimport文の例
以下は、未整理のimport文の例です（テキトーに用意した極端な例ですが...）。
```dart
import 'package:flutter/material.dart';


import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'dart:convert';
import 'package:project_name/components/component_a.dart';
import 'package:project_name/components/component_b.dart';
import 'package:project_name/components/component_c.dart';
import 'dart:io';

import 'package:intl/intl.dart';
import 'package:project_name/components/component_d.dart';
import 'package:project_name/components/component_e.dart';
import 'package:project_name/constants/constants.dart';
import 'package:project_name/models/model_a.dart';
import 'package:project_name/models/model_b.dart';
import 'package:project_name/models/model_c.dart';
import 'package:project_name/providers/my_home_notifier.dart';
import 'package:project_name/utils/util.dart';
import 'dart:math';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:project_name/models/model_d.dart';
import 'package:project_name/models/model_e.dart';
```

このコードには、次のような問題点があります。
- 不要な空行がある
- 種類がバラバラ
- 数が多い

などなど。

この記事では、上記のコードを改善しながらimport文を整理する3つの方法を紹介していきます。

## 1. Formatterを使う方法
まず、一番オーソドックスなFormatterを使う方法について紹介します。

Dartには、標準でコードを整形してくれる機能が用意されています。
以下のコマンドを実行してみましょう（ファイル名で`lib`を指定するとlib全体のコードが整形されます）。
```
$ dart format [ファイル名]
```
すると、ファイル名で指定したファイルのコードが自動で整形され、煩雑だったimport文を以下のように綺麗に並び替えることができました。
```dart
import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:project_name/components/component_a.dart';
import 'package:project_name/components/component_b.dart';
import 'package:project_name/components/component_c.dart';
import 'package:project_name/components/component_d.dart';
import 'package:project_name/components/component_e.dart';
import 'package:project_name/constants/constants.dart';
import 'package:project_name/models/model_a.dart';
import 'package:project_name/models/model_b.dart';
import 'package:project_name/models/model_c.dart';
import 'package:project_name/models/model_d.dart';
import 'package:project_name/models/model_e.dart';
import 'package:project_name/providers/my_home_notifier.dart';
import 'package:project_name/utils/util.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
```

ただ、毎回コマンドを実行してコードをフォーマットするのは大変です。
そのため、ファイル保存時に自動でコードをフォーマットすることをおすすめします。
Android Studioでは、[Android Studio]→[Preferences]→[Language & Frameworks]→[Flutter]を開き、`Format code on save`にチェックを入れると設定できます。
VSCodeでも自動フォーマットの方法はあると思うのでぜひ調べてみてください。

Formatterを用いることによってimport文を自動で整形することができます。
こちらの方法は、既に導入されている方が多いとは思いますが、Flutterを始めたばかりの方はつい忘れがちな設定なので、これを機に設定しておきましょう（import文以外のコードも整理してくれるのでかなりオススメ）。

## 2. import_sorterを使う方法
続いて、import_sorterを使ってimport文を整理する方法について紹介します。

import_sorterとは、Dart/Flutterのimport文を自動で整理してくれるpackageです。
import_sorterを使うと、通常のformatterのようにimport文を並び替えてくれるだけでなく、import文の種類によってまとめてくれます。

https://pub.dev/packages/import_sorter

では、実際にimport_sorterを使ってimport文を整理してみましょう。

まず、import_sorterのpackageをプロジェクトに追加します。
以下のコマンドを実行してください（またはyamlから直接追加）。
```
flutter pub add import_sorter
```

import_sorterがプロジェクトに追加できたら、以下のコマンドを実行してください。

```
flutter pub run import_sorter:main
```

すると、以下のようにimport文がimportの種類ごとに分類されるようになりました。
```dart
// Dart imports:
import 'dart:convert';
import 'dart:io';
import 'dart:math';

// Flutter imports:
import 'package:flutter/material.dart';

// Package imports:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';

// Project imports:
import 'package:project_name/components/component_a.dart';
import 'package:project_name/components/component_b.dart';
import 'package:project_name/components/component_c.dart';
import 'package:project_name/components/component_d.dart';
import 'package:project_name/components/component_e.dart';
import 'package:project_name/constants/constants.dart';
import 'package:project_name/models/model_a.dart';
import 'package:project_name/models/model_b.dart';
import 'package:project_name/models/model_c.dart';
import 'package:project_name/models/model_d.dart';
import 'package:project_name/models/model_e.dart';
import 'package:project_name/providers/my_home_notifier.dart';
import 'package:project_name/utils/util.dart';
```

## 3. Barrel File使う方法
最後に、Barrel Fileを用いた方法について紹介します。

Barrel Fileとは、複数のファイルを1つのファイルにまとめてexportするファイルのことです。

早速ですが、実際にBarrel Fileを作成してみましょう。
以下のように`components`ディレクトリのファイルをまとめて1つのimport文でimportしたい場合について考えてみます。
```
lib
└── components
    ├── component_a.dart
    ├── component_b.dart
    ├── component_c.dart
    ├── component_d.dart
    └── component_e.dart
```
まず、Burrel Fileとして`component.dart`を以下のように追加します。
```
lib
└── components
    ├── component.dart (←Barrel Fileを追加)
    ├── component_a.dart
    ├── component_b.dart
    ├── component_c.dart
    ├── component_d.dart
    └── component_e.dart 
```

次に、`component.dart`の中にexport文を記述します。
以下のように、まとめてimportできるようにしたい対象のファイルをexport文で指定します。
```dart
export 'component_a.dart';
export 'component_b.dart';
export 'component_c.dart';
export 'component_d.dart';
export 'component_e.dart';
```

すると、作成した`component.dart`を以下のようにimportします。
```dart
import 'package:project_name/components/component.dart';
```

5行もあったcomponentのimport文が1行になりました！

同様に、`models`でもBarrel Fileとして`model.dart`を作成すると、model関連のimport文も1つにまとめることができます。

そして、componentsやmodelsにBarrel Fileを導入した結果、import文を以下のように書くことができます。

```dart
// Dart imports:
import 'dart:convert';
import 'dart:io';
import 'dart:math';

// Flutter imports:
import 'package:flutter/material.dart';

// Package imports:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';

// Project imports:
import 'package:project_name/components/component.dart';
import 'package:project_name/constants/constants.dart';
import 'package:project_name/models/model.dart';
import 'package:project_name/providers/my_home_notifier.dart';
import 'package:project_name/utils/util.dart';
```

最初と比較してimport文の数が減ってスッキリしましたね。
このように、Barrel Fileを用いることで、import文の数を減らし、importの処理をスッキリさせることができます。

## ビフォーアフター
改めて、最初のimport文である「Before」と1〜3の方法で整理したimport文である「After」を比較してみましょう。

Before
```dart
import 'package:flutter/material.dart';


import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'dart:convert';
import 'package:project_name/components/component_a.dart';
import 'package:project_name/components/component_b.dart';
import 'package:project_name/components/component_c.dart';
import 'dart:io';

import 'package:intl/intl.dart';
import 'package:project_name/components/component_d.dart';
import 'package:project_name/components/component_e.dart';
import 'package:project_name/constants/constants.dart';
import 'package:project_name/models/model_a.dart';
import 'package:project_name/models/model_b.dart';
import 'package:project_name/models/model_c.dart';
import 'package:project_name/providers/my_home_notifier.dart';
import 'package:project_name/utils/util.dart';
import 'dart:math';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:project_name/models/model_d.dart';
import 'package:project_name/models/model_e.dart';
```

After
```dart
// Dart imports:
import 'dart:convert';
import 'dart:io';
import 'dart:math';

// Flutter imports:
import 'package:flutter/material.dart';

// Package imports:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';

// Project imports:
import 'package:project_name/components/component.dart';
import 'package:project_name/constants/constants.dart';
import 'package:project_name/models/model.dart';
import 'package:project_name/providers/my_home_notifier.dart';
import 'package:project_name/utils/util.dart';
```

なんということでしょう！
最初と比較してimport文が綺麗に整頓されましたではありませんか！

## まとめ
Flutterでimport文を整理する方法として、「1. Formatterを使う方法」、「2. Barrel File使う方法」、「3. 3. import_sorterを使う方法」の3つをご紹介しました。
個人的には、1のファイルは必須で、2と3は必要に応じて導入するのが良いのかなと思いました。
ぜひ、これらの方法を駆使してimport文を整理し、Flutterプロジェクトを綺麗に大掃除してみてください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017091/e203b3f7-f023-eae3-9b97-b84313f716ea.png" width="400">

*import文が綺麗になれば、お母さんも喜んでくれるはず*