run-codegen

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Run codegen (build_runner)

运行 codegen(build_runner)

A deterministic, low-freedom runbook: regenerate all annotation-driven code in one pass, then analyze. Run the pinned command exactly as written — do not modify it, add flags, or hand-edit generated files. Applies whenever a source file carries a codegen annotation (
@freezed
,
@JsonSerializable
,
@riverpod
,
@DriftDatabase
, a drift table) and its
*.g.dart
/
*.freezed.dart
/
*.drift.dart
part is missing or stale.
这是一份确定性且严格受限的操作手册:一次重新生成所有由注解驱动的代码, 然后执行 analyze。严格按原样运行固定命令——不要修改它、添加 flags,或 手动编辑生成文件。只要一个 source file 带有 codegen 注解(
@freezed
、
@JsonSerializable
、
@riverpod
、
@DriftDatabase
、drift table),且它的
*.g.dart
/
*.freezed.dart
/
*.drift.dart
part 缺失或过期,就适用本流程。

Non-negotiable rules

不可违反的规则

  1. Run codegen BEFORE
    flutter analyze
    .
    A fresh clone, branch switch, or freshly edited annotated file has no generated part on disk. Analyzing that tree produces misleading "missing part file" and undefined-class errors that describe the missing output, not a real code defect — regenerate, then analyze.
  2. Use the pinned command verbatim, always with
    --delete-conflicting-outputs
    .
    Without it, build_runner refuses to overwrite an output it did not write this run and fails with a wall of "conflicting outputs" text. That is a stale-file collision, not a bug — do not go hunting for one.
  3. Never hand-edit a generated file. The next build silently reverts it and takes your edit with it. Change the annotated source — the drift table, the freezed class, the Notifier, the ARB — and rerun.
  4. Never
    git add -f
    a generated file.
    Whether generated code is committed or gitignored is one decision owned by
    codegen-and-toolchain
    ; whichever the repo chose, never force-add an artifact past the ignore rules or commit one the current source would not reproduce.
  5. watch
    is a local-dev convenience, never CI or a pre-commit hook.
    CI and the pre-analyze step always use the one-shot
    build
    .
  6. Fix hand-written source first. The generator reads a resolved AST; it cannot generate from source that does not analyze. An unrelated error anywhere in
    lib/
    can block generation of a table or provider — clear those before blaming codegen.
  1. 先运行 codegen,再运行
    flutter analyze
    。
    全新 clone、切换分支或 刚编辑过带注解的 file 时,磁盘上还没有对应的生成 part。此时分析该代码树 会产生误导性的 “missing part file” 和 undefined-class 错误;这些错误描述的 是缺失的输出,而不是真实的代码缺陷——应先重新生成,再执行 analyze。
  2. 逐字使用固定命令,并始终加上
    --delete-conflicting-outputs
    。
    如果省略它,build_runner 会拒绝覆盖本次运行未写入的生成产物,并因大量 “conflicting outputs” 文本而失败。这是 stale-file 冲突,不是 bug—— 不要为此四处查找问题。
  3. 绝不手动编辑生成文件。 下次 build 会在无提示的情况下将其还原, 你的编辑也会随之消失。修改带注解的 source——drift table、freezed class、 Notifier、ARB——然后重新运行。
  4. 绝不对生成文件执行
    git add -f
    。
    生成代码是提交到 repo 还是由 gitignore 忽略,这项决策由
    codegen-and-toolchain
    统一负责;无论 repo 选择了哪一种,都不要绕过 ignore 规则强制 add artifact,也不要提交当前 source 无法重新生成的 artifact。
  5. watch
    只是本地开发的便利功能,绝不能用于 CI 或 pre-commit hook。
    CI 和 pre-analyze 步骤始终使用一次性的
    build
    。
  6. 先修复手写的 source。 generator 读取的是解析完成的 AST;它无法基于 无法通过 analyze 的 source 生成代码。
    lib/
    中任何位置的无关错误都可能 阻断 table 或 provider 的生成——先解决这些问题,再去怀疑 codegen。

The canonical command

固定命令

Run from the package root (single-package app) or the workspace root (multi-package repo):
bash
dart run build_runner build --delete-conflicting-outputs
This is the first step in every CI lane and on every fresh clone, before format and analyze.
从 package 根目录(单 package app)或 workspace 根目录(多 package repo)运行:
bash
dart run build_runner build --delete-conflicting-outputs
在每条 CI lane 和每次全新 clone 后,都必须先执行这一步,再执行 format 和 analyze。

Standard sequence on a fresh clone, pull, or branch switch

全新 clone、pull 或切换分支后的标准流程

  1. flutter pub get
    (resolve dependencies).
  2. dart run build_runner build --delete-conflicting-outputs
    (regenerate).
  3. Only then
    flutter analyze
    .
Skipping step 2 is the single most common cause of a red analyzer on a clone whose code is actually fine.
  1. flutter pub get
    (解析 dependencies)。
  2. dart run build_runner build --delete-conflicting-outputs
    (重新生成)。
  3. 之后才运行
    flutter analyze
    。
跳过步骤 2,是代码本身完全正常的 clone 出现 analyzer 变红的最常见原因。

Dev iteration (optional watch)

开发迭代(可选 watch)

For an active edit loop on annotated sources, run the watcher instead of a one-shot build; it rebuilds affected outputs on save:
bash
dart run build_runner watch --delete-conflicting-outputs
Stop the watcher before running the one-shot
build
— two concurrent build_runner processes over the same tree race on outputs.
对带注解的 source 进行高频编辑时,可以运行 watcher 代替一次性 build; 保存时会重新构建受影响的 outputs:
bash
dart run build_runner watch --delete-conflicting-outputs
运行一次性
build
前先停止 watcher——两个 build_runner 进程同时操作同一 代码树时,会在 outputs 上产生竞态。

When multi-package (workspace)

多 package(workspace)时

build_runner runs per-package: one invocation regenerates the current package plus its path-dependency packages, not automatically every sibling in the workspace. So running the single command at the workspace root covers the root package and its path dependencies in one pass, but a coordinator-style root that does not itself depend on every member will not regenerate those siblings. For full multi-package regeneration, use the repo-level fan-out wrapper (e.g.
melos run gen
) that runs the command over every workspace member; prefer it when the workspace is bootstrapped. To deliberately scope one package during development, run the same command from that package's directory. Builder scoping (which files each builder reads) lives in each package's
build.yaml
, owned by
codegen-and-toolchain
.
build_runner 按 package 运行:一次调用会重新生成当前 package 及其 path-dependency packages,但不会自动重新生成 workspace 中的所有 sibling packages。因此,在 workspace 根目录运行这条单一命令,可以一次覆盖根 package 及其 path dependencies;不过,若根 package 采用 coordinator 形式,并且自身不 依赖所有成员,就不会重新生成那些 sibling packages。
若要完整重新生成多 package 内容,请使用 repo 级 fan-out wrapper(例如
melos run gen
),它会对每个 workspace member 运行该命令;如果 workspace 已完成初始化,应优先使用这种方式。开发期间如需明确限定到某个 package, 请从该 package 的目录运行相同命令。Builder scoping(每个 builder 读取哪些 文件)记录在各 package 的
build.yaml
中,由
codegen-and-toolchain
负责。

When codegen and the analyzer disagree

codegen 与 analyzer 不一致时

The analyzer reads files on disk; build_runner writes them. A disagreement almost always means the disk is behind, not that the code is wrong.
SymptomDo this
Analyzer flags an undefined class/getter that codegen should produceRerun the pinned build, then restart the analysis server. Do not "fix" the call site.
Errors reported inside a
*.g.dart
/
*.freezed.dart
/
*.drift.dart
file
The file is stale or the analyzer excludes are wrong. Regenerate first; never hand-edit generated output.
build_runner fails with analyzer errors in hand-written sourceFix the hand-written source — the generator cannot resolve an unanalyzable AST.
"Conflicting outputs" wall of textRe-run with
--delete-conflicting-outputs
; it clears stale outputs from renamed/deleted sources.
analyzer 读取磁盘上的文件;build_runner 则负责写入。二者不一致几乎总是 说明磁盘内容落后,而不是代码有误。
症状应执行的操作
Analyzer 标记了 codegen 应生成的 undefined class/getter重新运行固定 build,然后重启 analysis server。不要去“修复”调用点。
错误报告在
*.g.dart
/
*.freezed.dart
/
*.drift.dart
文件内部
文件已过期,或 analyzer excludes 配置有误。先重新生成;绝不手动编辑 generated output。
build_runner 因手写 source 中的 analyzer 错误而失败修复手写 source——generator 无法解析无法通过 analyze 的 AST。
出现大量 “Conflicting outputs” 文本使用
--delete-conflicting-outputs
重新运行;它会清除由重命名或删除 source 产生的过期 outputs。

Anti-patterns

反模式

  • Running
    flutter analyze
    before codegen on a fresh tree
    — you chase phantom missing-part errors that regeneration erases.
  • Dropping
    --delete-conflicting-outputs
    — the first rename or deletion fails the whole run on a stale-output collision.
  • Editing a
    .g.dart
    /
    .freezed.dart
    /
    .drift.dart
    by hand
    — the next build reverts it; the fix belongs in the annotated source.
  • git add -f
    on a gitignored generated file
    — bypasses the repo's committed-vs-gitignored decision and ships a possibly-stale artifact.
  • build_runner watch
    in CI or a pre-commit hook
    — non-deterministic; CI must use the one-shot
    build
    .
  • 在全新代码树上先运行
    flutter analyze
    ,后运行 codegen
    ——你会追查 重新生成后便会消失的虚假 missing-part 错误。
  • 省略
    --delete-conflicting-outputs
    ——第一次发生重命名或删除时, 整个运行就会因 stale-output 冲突而失败。
  • 手动编辑
    .g.dart
    /
    .freezed.dart
    /
    .drift.dart
    ——下次 build 会将其 还原;正确的修复位置是带注解的 source。
  • 对被 gitignore 的生成文件执行
    git add -f
    ——这会绕过 repo 关于 generated code 提交与忽略的决策,并交付可能已过期的 artifact。
  • 在 CI 或 pre-commit hook 中运行
    build_runner watch
    ——不具备确定性; CI 必须使用一次性的
    build
    。

Definition of done

完成标准

  • The pinned
    dart run build_runner build --delete-conflicting-outputs
    ran at the package/workspace root without "conflicting outputs" errors.
  • It ran before
    flutter analyze
    , which is now green.
  • No generated file was hand-edited or force-added.
  • No
    build_runner watch
    process is wired into CI or hooks.
  • 固定的
    dart run build_runner build --delete-conflicting-outputs
    已在 package/workspace 根目录运行完成,且没有 “conflicting outputs” 错误。
  • 它在
    flutter analyze
    之前运行,且现在 analyze 已通过。
  • 没有手动编辑或强制 add 任何生成文件。
  • 没有将任何
    build_runner watch
    进程接入 CI 或 hooks。

Related skills

相关 skills

  • See
    codegen-and-toolchain
    for the knowledge behind this runbook:
    build.yaml
    builder scoping, the commit-vs-gitignore-generated-code decision, SDK pinning, and analyzer/coverage excludes for generated files.
  • See
    run-migration
    for the drift schema-snapshot and migration ritual that wraps
    drift_dev make-migrations
    around this codegen pass.
  • See
    ci-pipeline-and-gates
    for the CI freshness gate that reruns this command and diffs the tree.
  • See
    lint-and-style-config
    for the analyzer excludes that keep generated files out of lint scope.
  • 有关本手册背后的原理,请参阅
    codegen-and-toolchain
    :
    build.yaml
    builder scoping、generated code 提交与 gitignore 的决策、 SDK pinning,以及 generated files 的 analyzer/coverage excludes。
  • 有关 drift schema-snapshot 和 migration 的完整流程,请参阅
    run-migration
    ; 该流程将
    drift_dev make-migrations
    编排在此 codegen pass 前后。
  • 有关会重新运行此命令并对代码树执行 diff 的 CI freshness gate,请参阅
    ci-pipeline-and-gates
    。
  • 有关将 generated files 排除在 lint scope 之外的 analyzer excludes,请参阅
    lint-and-style-config
    。

References

参考