Dart パッケージ管理 — pub エコシステムと依存関係

依存関係管理はプロジェクトのサプライチェーンである — うまく管理して初めてプロジェクトが安定する。

1. 学べること


2. 開発者のリアルな物語

(1) 課題:依存関係のバージョン競合によるビルド失敗

Alice のチームは DataPipeline プロジェクトで http: ^1.1.0 を使っていたが、別の依存関係 api_clienthttp: >=0.13.0 <1.0.0 を要求していた。バージョン制約が互換性なく、dart pub get が失敗した。さらに悪いことに、依存関係がマイナー版をサイレントに更新し、重大な変更が導入されて CI ビルドが失敗した。チームは調査に 2 日を費やした。

(2) 解決策:セマンティックバージョニング

Dart はセマンティックバージョニング(SemVer)とバージョン制約構文を使って依存関係管理を予測可能にする。^1.2.0>=1.2.0 <2.0.0 を意味し、互換性を保証する。

YAML
dependencies:
  http: ^1.2.0       # 1.x と互換、安全なマイナー/パッチ更新
  args: ^2.4.2        # 2.x と互換
  csv: ^6.0.0         # 6.x と互換

(3) 効果


3. 完全な pubspec.yaml 設定

(1) 設定構造

▶ サンプル:完全な pubspec.yaml

YAML
name: datapipeline
description: A CLI tool for e-commerce data analytics processing million-level orders
version: 1.0.0
homepage: https://github.com/bob/datapipeline
repository: https://github.com/bob/datapipeline
documentation: https://datapipeline.dev/docs

environment:
  sdk: ^3.0.0

dependencies:
  # CLI 引数解析
  args: ^2.4.2
  # API 呼び出し用 HTTP クライアント
  http: ^1.2.0
  # CSV ファイルパース
  csv: ^6.0.0
  # SQLite データベースサポート
  sqlite3: ^2.4.0
  # パス操作ユーティリティ
  path: ^1.9.0
  # ロギングフレームワーク
  logging: ^1.2.0
  # YAML 設定パース
  yaml: ^3.1.2

dev_dependencies:
  # テストフレームワーク
  test: ^1.24.0
  # コード生成ランナー
  build_runner: ^2.4.0
  # JSON シリアライゼーション
  json_serializable: ^6.7.0
  # Lint ルール
  lints: ^3.0.0

dependency_overrides:
  # 一時的:バージョン競合の解決
  # transitive: ^1.0.0

executables:
  datapipeline: datapipeline
フィールド 必須 説明
name はい パッケージ名(小文字 + アンダースコア)
description はい パッケージ説明(60-180 文字)
version いいえ セマンティックバージョン番号
environment はい SDK バージョン制約
dependencies いいえ ランタイム依存関係
dev_dependencies いいえ 開発時依存関係
dependency_overrides いいえ 特定バージョンの強制

4. バージョン制約構文

(1) セマンティックバージョニング

▶ サンプル:バージョン制約構文

YAML
dependencies:
  # キャレット構文: ^1.2.3 = >=1.2.3 <2.0.0
  package_a: ^1.2.3

  # 範囲構文
  package_b: ">=1.2.3 <2.0.0"

  # 最小バージョン
  package_c: ">=1.2.3"

  # 任意バージョン(危険!)
  package_d: any

  # 厳密バージョン
  package_e: "1.2.3"

  # Git 依存関係
  package_f:
    git:
      url: https://github.com/user/package_f.git
      ref: main

  # パス依存関係(ローカル開発)
  package_g:
    path: ../package_g
構文 意味 安全性
^1.2.3 >=1.2.3 <2.0.0 最も一般的
>=1.2.3 <2.0.0 範囲制約 精密な制御
>=1.2.3 最小バージョン リスク高
any 任意バージョン 非推奨
1.2.3 厳密バージョン ピン留め 高(柔軟性なし)

(2) バージョン解決ルール

SemVer ルール 説明
メジャーバージョン 非互換 API 変更 1.x → 2.x
マイナーバージョン 後方互換の新機能 1.2 → 1.3
パッチバージョン 後方互換のバグ修正 1.2.3 → 1.2.4

▶ サンプル:バージョン競合と解決

YAML
# シナリオ:package_a は http ^0.13.0 を要求、package_b は http ^1.0.0 を要求
# これはメジャーバージョンの競合 - 互換性なし!

# 解決策 1:package_a を http ^1.0.0 をサポートするバージョンに更新
# 解決策 2:dependency_overrides を使用(最後の手段)
dependencies:
  http: ^1.2.0

dependency_overrides:
  http: ^1.2.0  # 特定バージョンを強制

5. pub.dev でのパッケージ評価

(1) 評価基準

観点 メトリック 重み
Pub Points プラットフォーム対応/ドキュメント/依存関係健全性
Likes コミュニティ認知度
人気度 使用数
Pub Verified パブリッシャー認証済み
最近の更新 メンテナンス活動
プラットフォーム サポートされるプラットフォーム 必要に応じて

▶ サンプル:DataPipeline パッケージ選択

YAML
# DataPipeline パッケージ選択基準:
#
# args (pub points: 140/140, likes: 300+)
#   - 公式 Dart チームパッケージ
#   - 安定した API、よく文書化されている
#   - CLI 引数解析に最適
#
# http (pub points: 140/140, likes: 1000+)
#   - 公式 Dart チームパッケージ
#   - 標準 HTTP クライアント
#   - インターセプターとストリーミングをサポート
#
# csv (pub points: 130/140, likes: 100+)
#   - コミュニティパッケージ
#   - CSV パース/書き込みを処理
#   - アクティブなメンテナンス
#
# json_serializable (pub points: 140/140, likes: 500+)
#   - Google パッケージ
#   - JSON のコード生成
#   - 型安全、AOT 対応

6. プライベートパッケージと Git 依存関係

▶ サンプル:Git 依存関係

YAML
dependencies:
  # パブリック git リポジトリ
  custom_client:
    git:
      url: https://github.com/bob/custom_client.git
      ref: v1.0.0  # タグ、ブランチ、またはコミット

  # プライベート git リポジトリ (SSH)
  internal_sdk:
    git:
      url: git@github.com:bob/internal_sdk.git
      ref: main

  # git リポジトリ内の特定パス
  shared_utils:
    git:
      url: https://github.com/bob/monorepo.git
      path: packages/shared_utils
      ref: stable

▶ サンプル:ローカルパス依存関係

YAML
# ローカル開発とテスト用
dependencies:
  core_lib:
    path: ../core_lib

  shared_models:
    path: ./packages/shared_models
依存関係ソース 構文 適用シナリオ
pub.dev package: ^1.0.0 正式な依存関係(推奨)
Git git: url: ... 未公開/プライベートパッケージ
ローカルパス path: ../local 開発/デバッグ、モノレポ

7. Bob のシナリオ:DataPipeline 依存関係設定

▶ サンプル:完全なプロジェクト依存関係

YAML
name: datapipeline
description: E-commerce analytics CLI tool for processing million-level orders
version: 1.0.0

environment:
  sdk: ^3.0.0

dependencies:
  # CLI フレームワーク
  args: ^2.4.2
  # コンソール出力フォーマット
  cli_util: ^0.4.1
  # HTTP クライアント
  http: ^1.2.0
  # CSV パース
  csv: ^6.0.0
  # JSON シリアライゼーション
  json_annotation: ^4.8.0
  # パスユーティリティ
  path: ^1.9.0
  # ロギング
  logging: ^1.2.0
  # YAML 設定
  yaml: ^3.1.2

dev_dependencies:
  # テスト
  test: ^1.24.0
  # モック
  mockito: ^5.4.0
  # コード生成
  build_runner: ^2.4.0
  json_serializable: ^6.7.0
  # リント
  lints: ^3.0.0
  # カバレッジ
  coverage: ^1.6.0

8. 完全なサンプル:DataPipeline 依存関係管理

DART
// ============================================
// DataPipeline 依存関係管理デモ
// 主要依存関係の使い方を示す
// ============================================

import 'package:args/args.dart';
import 'package:path/path.dart' as p;

const String version = '1.0.0';

class DataPipelineCli {
  final ArgParser parser;

  DataPipelineCli()
      : parser = ArgParser()
          ..addFlag('version', abbr: 'v', negatable: false, help: 'Show version')
          ..addFlag('help', abbr: 'h', negatable: false, help: 'Show help')
          ..addOption('input', abbr: 'i', help: 'Input data source')
          ..addOption('output', abbr: 'o', defaultsTo: 'report.json', help: 'Output path')
          ..addOption('format', allowed: ['json', 'csv', 'html'], defaultsTo: 'json')
          ..addFlag('verbose', abbr: 'V', help: 'Verbose logging')
          ..addOption('batch-size', defaultsTo: '10000', help: 'Records per batch');

  Future<void> run(List<String> arguments) async {
    try {
      final results = parser.parse(arguments);

      if (results['help'] as bool) {
        _printHelp();
        return;
      }

      if (results['version'] as bool) {
        print('DataPipeline v$version');
        return;
      }

      final input = results['input'] as String?;
      final output = results['output'] as String;
      final format = results['format'] as String;
      final verbose = results['verbose'] as bool;
      final batchSize = int.parse(results['batch-size'] as String);

      if (input == null) {
        print('Error: --input is required');
        _printHelp();
        return;
      }

      // path パッケージをクロスプラットフォームパスに使用
      final inputPath = p.normalize(input);
      final outputPath = p.normalize(output);
      final ext = p.extension(inputPath);

      print('=== DataPipeline v$version ===');
      if (verbose) {
        print('Input:      $inputPath (${ext.isEmpty ? "unknown" : ext})');
        print('Output:     $outputPath');
        print('Format:     $format');
        print('Batch size: $batchSize records');
        print('SDK:        ${_getSdkInfo()}');
      }

      print('Processing: $inputPath → $outputPath ($format)');
    } on FormatException catch (e) {
      print('Argument error: ${e.message}');
      print(parser.usage);
    }
  }

  void _printHelp() {
    print('DataPipeline - E-commerce analytics CLI tool');
    print('');
    print('Usage: datapipeline [options]');
    print(parser.usage);
  }

  String _getSdkInfo() {
    // 実際のプロジェクトでは dart:io Platform を使用
    return 'Dart 3.x';
  }
}

void main(List<String> arguments) async {
  final cli = DataPipelineCli();
  await cli.run(arguments);
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

出力(dart run bin/main.dart -i orders.csv -o report.json -V):

TEXT
=== DataPipeline v1.0.0 ===
Input:      orders.csv (.csv)
Output:     report.json
Format:     json
Batch size: 10000 records
SDK:        Dart 3.x
Processing: orders.csv → report.json (json)

❓ よくある質問

Q: dependenciesdev_dependencies の違いは何ですか? A: dependencies はランタイムに必要なパッケージで、dev_dependencies は開発中(テスト、コード生成、リント)にのみ必要です。パッケージを公開する際、dev_dependencies はユーザーに渡されません。

Q: ^>= の違いは何ですか? A: ^1.2.0>=1.2.0 <2.0.0 と同等で、メジャーバージョン内の更新に制限します。>=1.2.0 には上限がありません。^ の方が安全で推奨されます。

Q: dart pub upgradedart pub get の違いは何ですか? A: dart pub get は pubspec.yaml の制約内で依存関係を取得します。dart pub upgrade はそれらの制約内で最新バージョンへのアップグレードを試みます。

Q: pubspec.ロック はバージョン管理にコミットすべきですか? A: アプリケーションプロジェクト(CLI、Flutter App)では、チームが同じバージョンを使用することを保証するために、はいです。ライブラリプロジェクト(パッケージ)では、ユーザーが最新の互換バージョンを取得できるように、いいえ。

Q: pub.dev でパッケージを選ぶには? A: pub points(≥130 が良好)、likes、最近の更新時刻、パブリッシャーが認証済みかを確認してください。公式 Dart/Google パッケージを優先してください。

Q: いつ dependency_overrides を使うべきですか? A: 通常のバージョン制約では競合が解決できない場合のみ一時的に使用してください。長期使用は根本的な問題を隠します。問題が解決したらすぐに削除してください。

Q: Git 依存関係は本番環境で安全ですか? A: 推奨されません。Git 依存関係にはバージョン保証がなく、ref を強制プッシュできます。正式なリリースには pub.dev のバージョン付きパッケージを使用してください。


📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐)dart create を使ってプロジェクトを作成し、argspath 依存関係を追加して dart pub get を実行し、pubspec.ロック ファイルの内容を調べてください。
  2. 中級(難易度 ⭐⭐):pub.dev で http パッケージを検索し、pub points、likes、最新バージョン、サポートされるプラットフォームを記録してください。パッケージ選択評価レポートを書いてください。
  3. 挑戦(難易度 ⭐⭐⭐):git 依存関係とパス依存関係を含む pubspec.yaml ファイルを作成し、モノレポ開発シナリオをシミュレートしてください。dependency_overrides を使って仮のバージョン競合を解決します。

← 前のレッスン | 次のレッスン →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%