Dart: Dart 包管理 — pub 生态与依赖管理

依赖管理是项目的供应链 — 管好依赖,项目才稳。

1. 你将学到


2. 一个开发者的真实故事

(1) 痛点:依赖版本冲突导致构建失败

Alice 的团队在 DataPipeline 中用了 http: ^1.1.0,但另一个依赖 api_client 要求 http: >=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       # Compatible with 1.x, safe minor/patch updates
  args: ^2.4.2        # Compatible with 2.x
  csv: ^6.0.0         # Compatible with 6.x

(3) 收益


3. pubspec.yaml 完整配置

(1) 配置结构

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:完整 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 argument parsing
  args: ^2.4.2
  # HTTP client for API calls
  http: ^1.2.0
  # CSV file parsing
  csv: ^6.0.0
  # SQLite database support
  sqlite3: ^2.4.0
  # Path manipulation utilities
  path: ^1.9.0
  # Logging framework
  logging: ^1.2.0
  # YAML configuration parsing
  yaml: ^3.1.2

dev_dependencies:
  # Testing framework
  test: ^1.24.0
  # Code generation runner
  build_runner: ^2.4.0
  # JSON serialization
  json_serializable: ^6.7.0
  # Lint rules
  lints: ^3.0.0

dependency_overrides:
  # Temporary: resolve version conflict
  # transitive: ^1.0.0

executables:
  datapipeline: datapipeline
字段 必填 说明
name 包名(小写+下划线)
description 包描述(60-180字符)
version 语义化版本号
environment SDK 版本约束
dependencies 运行时依赖
dev_dependencies 开发时依赖
dependency_overrides 强制覆盖版本

4. 版本约束语法

(1) 语义化版本

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:版本约束语法

YAML
dependencies:
  # Caret syntax: ^1.2.3 = >=1.2.3 <2.0.0
  package_a: ^1.2.3

  # Range syntax
  package_b: ">=1.2.3 <2.0.0"

  # Minimum version
  package_c: ">=1.2.3"

  # Any version (dangerous!)
  package_d: any

  # Exact version
  package_e: "1.2.3"

  # Git dependency
  package_f:
    git:
      url: https://github.com/user/package_f.git
      ref: main

  # Path dependency (local development)
  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

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:版本冲突与解决

YAML
# Scenario: package_a requires http ^0.13.0, package_b requires http ^1.0.0
# This is a MAJOR version conflict - incompatible!

# Solution 1: Update package_a to a version that supports http ^1.0.0
# Solution 2: Use dependency_overrides (last resort)
dependencies:
  http: ^1.2.0

dependency_overrides:
  http: ^1.2.0  # Force specific version

5. pub.dev 包评估

(1) 评估标准

维度 指标 权重
Pub Points 平台支持/文档/依赖健康度
Likes 社区认可度
Popularity 使用量
Pub Verified 发布者已验证
最近更新 维护活跃度
Platform 支持的平台 视需求

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:DataPipeline 选包

YAML
# DataPipeline package selection criteria:
#
# args (pub points: 140/140, likes: 300+)
#   - Official Dart team package
#   - Stable API, well documented
#   - Perfect for CLI argument parsing
#
# http (pub points: 140/140, likes: 1000+)
#   - Official Dart team package
#   - Standard HTTP client
#   - Supports interceptors and streaming
#
# csv (pub points: 130/140, likes: 100+)
#   - Community package
#   - Handles CSV parsing/writing
#   - Active maintenance
#
# json_serializable (pub points: 140/140, likes: 500+)
#   - Google package
#   - Code generation for JSON
#   - Type-safe, AOT compatible

6. 私有包与 git 依赖

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:Git 依赖

YAML
dependencies:
  # Public git repository
  custom_client:
    git:
      url: https://github.com/bob/custom_client.git
      ref: v1.0.0  # Tag, branch, or commit

  # Private git repository (SSH)
  internal_sdk:
    git:
      url: git@github.com:bob/internal_sdk.git
      ref: main

  # Specific path within a git repo
  shared_utils:
    git:
      url: https://github.com/bob/monorepo.git
      path: packages/shared_utils
      ref: stable

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:本地路径依赖

YAML
# For local development and testing
dependencies:
  core_lib:
    path: ../core_lib

  shared_models:
    path: ./packages/shared_models
依赖来源 语法 适用场景
pub.dev package: ^1.0.0 正式依赖(推荐)
Git git: url: ... 未发布包、私有包
本地路径 path: ../local 开发调试、monorepo

7. Bob 场景:DataPipeline 依赖配置

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。

:完整的项目依赖

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 framework
  args: ^2.4.2
  # Console output formatting
  cli_util: ^0.4.1
  # HTTP client
  http: ^1.2.0
  # CSV parsing
  csv: ^6.0.0
  # JSON serialization
  json_annotation: ^4.8.0
  # Path utilities
  path: ^1.9.0
  # Logging
  logging: ^1.2.0
  # YAML config
  yaml: ^3.1.2

dev_dependencies:
  # Testing
  test: ^1.24.0
  # Mocking
  mockito: ^5.4.0
  # Code generation
  build_runner: ^2.4.0
  json_serializable: ^6.7.0
  # Linting
  lints: ^3.0.0
  # Coverage
  coverage: ^1.6.0

8. 完整示例:DataPipeline 依赖管理

DART
// ============================================
// DataPipeline Dependency Management Demo
// Shows how to use key dependencies
// ============================================

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;
      }

      // Use path package for cross-platform paths
      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() {
    // In real project, use 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:dependencies 和 dev_dependencies 有什么区别? A:dependencies 是运行时需要的包;dev_dependencies 只在开发时需要(测试、代码生成、lint)。发布包时,dev_dependencies 不会被传递给使用者。

Q:^ 和 >= 有什么区别? A:^1.2.0 等价于 >=1.2.0 <2.0.0,限制在大版本内;>=1.2.0 没有上限。^ 更安全,推荐使用。

Q:dart pub upgrade 和 dart pub get 有什么区别? A:dart pub get 获取 pubspec.yaml 约束范围内的依赖;dart pub upgrade 尝试升级到约束范围内的最新版本。

Q:pubspec.lock 应该提交到版本控制吗? A:应用项目(CLI、Flutter App)应该提交,确保团队使用相同版本;库项目(package)不应该提交,让使用者获取最新兼容版本。

Q:如何选择 pub.dev 上的包? A:看 pub points(≥130 分较好)、likes、最近更新时间、发布者是否 verified。优先选 Dart/Google 官方包。

Q:dependency_overrides 什么时候用? A:只在无法通过正常版本约束解决冲突时临时使用。长期使用会掩盖真正的问题。解决后应尽快移除。

Q:git 依赖在生产环境安全吗? A:不推荐。git 依赖没有版本保证,ref 可能被 force-push。正式发布应使用 pub.dev 上的版本化包。


📖 小节


📝 作业

  1. 基础题(难度⭐):用 dart create 创建一个项目,添加 argspath 依赖,运行 dart pub get,检查 pubspec.lock 文件内容。
  2. 进阶题(难度⭐⭐):在 pub.dev 上搜索 http 包,记录其 pub points、likes、最新版本和支持平台。写一份选包评估报告。
  3. 挑战题(难度⭐⭐⭐):创建一个包含 git 依赖和 path 依赖的 pubspec.yaml,模拟 monorepo 开发场景。用 dependency_overrides 解决一个假设的版本冲突。

← 上一课 | 下一课 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏