• トップ
  • ブログ一覧
  • 【Flutter】Dart Code Metricsを使って不要ファイルや不要コードを抽出してみた
  • 【Flutter】Dart Code Metricsを使って不要ファイルや不要コードを抽出してみた

    広告メディア事業部広告メディア事業部
    2022.04.15

    IT技術

    Dart Code Metricsを使ってみた!

    (株)ライトコードの小林(こばやし)です!

    皆さんは「Dart Code Metrics」をご存知でしょうか?

    Dartのコードの品質を分析したり改善するのに役立つ静的分析ツールで、不要ファイルをチェックしたり、analysis_options.ymlにAnalyzer Pluginを追加して静的解析を行うことができます。

    業務の中で不要ファイルや不要コードを抽出して対応する機会があったので、今回は導入から抽出までの流れをまとめていきます。

    開発環境

    開発環境は以下の通りです。

    Flutter2.10.3

    Dart Code Metricsとは?

    「Dart Code Metrics」とはDartのコードの品質を分析したり改善するのに役立つ静的分析ツールです。

    パッケージの詳細:https://pub.dev/packages/dart_code_metrics

    ドキュメント:https://dartcodemetrics.dev/docs/cli/check-unused-code

    主な機能として下記の機能があります。

    • コードメトリクスのレポート
    • dart analyzerの追加ルールの提供
    • アンチパターンのチェック
    • 未使用の*.dartファイルをチェック
    • 未使用のl10n(ローカライズ言語)をチェック
    • CLIやanalyzer plugin、ライブラリとして使用

    今回はこの中で「未使用の*.dartファイルをチェック」する機能を使って未使用ファイル等を検出してみます。

    ※ 注意点として、2022年3月18日現在クラス内の未使用メソッドについては未対応となっています。こちらは将来のリリースで修正される予定とのことです。

    未使用ファイルや未使用コードを抽出してみる

    準備

    サンプルプロジェクトを作成し、lib配下に下記の4つのファイルを用意しました。

    main.dart

    1import 'package:flutter/material.dart';
    2
    3import 'first_page.dart';
    4
    5void main() {
    6  runApp(const App());
    7}
    8
    9class App extends StatelessWidget {
    10  const App({Key? key}) : super(key: key);
    11
    12  @override
    13  Widget build(BuildContext context) {
    14    return MaterialApp(
    15      title: 'Flutter Demo',
    16      theme: ThemeData(
    17        primarySwatch: Colors.blue,
    18      ),
    19      home: const FirstPage(),
    20    );
    21  }
    22}

    first_page.dart

    1import 'package:flutter/material.dart';
    2
    3import 'second_page.dart';
    4
    5class FirstPage extends StatelessWidget {
    6  const FirstPage({Key? key}) : super(key: key);
    7
    8  @override
    9  Widget build(BuildContext context) {
    10    return Scaffold(
    11      body: Center(
    12        child: Column(
    13          mainAxisAlignment: MainAxisAlignment.center,
    14          children: [
    15            const Text('First Page'),
    16            const SizedBox(height: 20),
    17            ElevatedButton(
    18              onPressed: () {
    19                Navigator.push(
    20                  context,
    21                  MaterialPageRoute(
    22                    builder: (context) {
    23                      return const SecondPage();
    24                    },
    25                  ),
    26                );
    27              },
    28              child: const Text('Go Second Page'),
    29            )
    30          ],
    31        ),
    32      ),
    33    );
    34  }
    35}

    second_page.dart

    1import 'package:flutter/material.dart';
    2
    3class SecondPage extends StatelessWidget {
    4  const SecondPage({Key? key}) : super(key: key);
    5
    6  @override
    7  Widget build(BuildContext context) {
    8    return Scaffold(
    9      body: Center(
    10        child: Column(
    11          mainAxisAlignment: MainAxisAlignment.center,
    12          children: [
    13            const Text('Second Page'),
    14            const SizedBox(height: 20),
    15            ElevatedButton(
    16              onPressed: () {
    17                Navigator.pop(context);
    18              },
    19              child: const Text('back'),
    20            )
    21          ],
    22        ),
    23      ),
    24    );
    25  }
    26}
    27
    28class Hoge extends StatelessWidget {
    29  const Hoge({Key? key}) : super(key: key);
    30
    31  @override
    32  Widget build(BuildContext context) {
    33    return Container();
    34  }
    35}

    third_page.dart

    1import 'package:flutter/material.dart';
    2
    3class ThirdPage extends StatelessWidget {
    4  const ThirdPage({Key? key}) : super(key: key);
    5
    6  @override
    7  Widget build(BuildContext context) {
    8    return const Scaffold(
    9      body: Center(
    10        child: Text('Third Page'),
    11      ),
    12    );
    13  }
    14}

    second_page.dartでは使用されていないクラスがあり、third_page.dartはどこからも参照されていないファイルです。

    dart_code_metricsを導入する

    まずは、dart_code_metricsパッケージを導入します。

    1dev_dependencies:
    2  dart_code_metrics: ^4.13.0

    不要コードチェックコマンドが4.11.0-dev.1から叩けるようになっているので、それ以降のバージョンを導入しましょう。

    未使用ファイルを抽出する

    それでは不要ファイルを抽出してみましょう。

    プロジェクトのルートで下記いずれかのコマンドを叩きます。

    1$ dart run dart_code_metrics:metrics check-unused-files lib
    2
    3$ flutter pub run dart_code_metrics:metrics check-unused-files lib

    すると下記のような形で出力され、未使用ファイルが抽出されました。

    1$ flutter pub run dart_code_metrics:metrics check-unused-files lib
    2⚠ unused file: lib/third_page.dart
    3
    4✖ total unused files - 1

    未使用コードを抽出する

    続けて未使用コードも抽出してみます。

    プロジェクトのルートで下記いずれかのコマンドを叩きます。

    1$ dart run dart_code_metrics:metrics check-unused-code lib
    2
    3$ flutter pub run dart_code_metrics:metrics check-unused-code lib

    すると下記のような形で出力され、未使用コードが抽出されました。

    1$ flutter pub run dart_code_metrics:metrics check-unused-code lib 
    2lib/second_page.dart:
    3    ⚠ unused class Hoge
    4      at lib/second_page.dart:28:1
    5
    6lib/third_page.dart:
    7    ⚠ unused class ThirdPage
    8      at lib/third_page.dart:3:1
    9
    10✖ total unused code (classes, functions, variables, extensions, enums, mixins and type aliases) - 2

    まとめ

    今回は「Dart Code Metrics」を使って未使用ファイルとコードを抽出してみました。

    CI/CDに組み込んで、定期的に不要なファイルやコードがないかを検知する仕組みを作るのも良さそうですね。

    簡単に導入できるので、ぜひ試してみてください!

    広告メディア事業部

    広告メディア事業部

    おすすめ記事