aui-build declaration output still differs between identical builds

Author: okisdevCreated Sep 18, 2026Updated Sep 18, 2026
Labelsbugpkg/x-buildutils

problem

#7592 has two independent causes. the entry ordering one is fixed (tsdown fed rolldown an unsorted tinyglobby crawl, so every chunk's import order moved between builds). the declaration one is not: .d.ts output still differs between two builds of the same commit.

with the entry list sorted, eight consecutive builds of packages/core and packages/react-generative-ui:

  • .js plus .js.map: 1 distinct hash each. deterministic.
  • .d.ts plus .d.ts.map: 3 distinct hashes for core, 4 for react-generative-ui.

two shapes show up:

diff
-  get role(): "assistant" | "system" | "user";
+  get role(): "system" | "user" | "assistant";
diff
-export declare const subscribeToTitleGeneration: (...) => Unsubscribe;
+export declare const subscribeToTitleGeneration: (...) => () => void;

the first is union member order, which TypeScript prints by type id, and type ids are assigned in creation order. the second is whether a type alias was still visible when the printer reached it.

mechanism

rolldown-plugin-dts emits declarations per module from a transform hook, against one lazily checked TypeScript program (DEBUG=rolldown-plugin-dts:* shows running tscEmit <file> once per module). that per module emit order is rolldown's transform completion order, and it is not stable: over three builds of packages/core the 285 emit lines moved by roughly 190 positions each time, with the entry list already sorted. whichever module is checked first creates the string literal types first, so the union order and the alias visibility follow the race.

so this is not fixable by ordering anything we own. the emit order belongs to rolldown's transform scheduling, and the resulting type ids belong to the TypeScript checker.

direction

report it to rolldown-plugin-dts with the z.enum reproduction from packages/react-generative-ui/src/vocabulary/alert.tsx, and check whether emitting declarations in a fixed module order (or checking the whole program up front instead of lazily per module) is something the plugin can offer.

the variants stay equivalent and the api-surface snapshots normalize them away, so this is about being able to diff published output across a toolchain change without rebuilding several times.

Track in Rupic

Source: assistant-ui/assistant-ui