Dart: Dart 包管理 — pub 生态与依赖管理
依赖管理是项目的供应链 — 管好依赖,项目才稳。
1. 你将学到
- pubspec.yaml 完整配置:dependencies / dev_dependencies / dependency_overrides
- 版本约束语法:^ / >= / any 与语义化版本
- pub.dev 搜索、评估与选包标准
- 私有包托管与 git 依赖
- Bob 场景:DataPipeline 的依赖配置
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,保证兼容性。
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) 收益
- 版本约束让依赖升级安全可控
- pub.dev 的 pub points 评估体系帮助选高质量包
- dependency_overrides 临时解决版本冲突
3. pubspec.yaml 完整配置
(1) 配置结构
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:完整 pubspec.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) 语义化版本
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:版本约束语法
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 |
- 修订版本 | 向后兼容 bug 修复 | 1.2.3 → 1.2.4 |
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:版本冲突与解决
# 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 | 支持的平台 | 视需求 |
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:DataPipeline 选包
# 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 依赖
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:Git 依赖
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
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:本地路径依赖
# 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 依赖配置
▶ 示例
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
:完整的项目依赖
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 依赖管理
// ============================================
// 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);
}
> **输出:** 在本地 DartPad 或 `dart run` 执行。Dart 课程所有示例基于 Dart 3.x / Flutter 3.x,运行结果会因 SDK 版本略有差异。
输出(
dart run bin/main.dart -i orders.csv -o report.json -V):
=== 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 上的版本化包。
📖 小节
- pubspec.yaml 是项目的配置中心:管理依赖、版本、元信息
- 版本约束用
^语法最安全,限制在大版本内自动升级 - pub.dev 的 pub points 评估体系帮助选高质量包
- git 依赖用于未发布/私有包,path 依赖用于本地开发
- dependencies vs dev_dependencies 区分运行时和开发时依赖
📝 作业
- 基础题(难度⭐):用
dart create创建一个项目,添加args和path依赖,运行dart pub get,检查 pubspec.lock 文件内容。 - 进阶题(难度⭐⭐):在 pub.dev 上搜索
http包,记录其 pub points、likes、最新版本和支持平台。写一份选包评估报告。 - 挑战题(难度⭐⭐⭐):创建一个包含 git 依赖和 path 依赖的 pubspec.yaml,模拟 monorepo 开发场景。用 dependency_overrides 解决一个假设的版本冲突。