跪拜 Guibai
← All articles
Frontend · Android · Flutter

Dart 3.13 Shrinks Native Binaries and Preps Dynamic Module Loading

By 恋猫de小郭 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Native tree shaking closes a long-standing gap where Dart's aggressive dead-code elimination stopped at the FFI boundary, forcing apps to ship entire native libraries for a handful of used functions. Combined with the dynamic modules experiment, Dart is laying groundwork for both smaller binaries and more flexible deployment models on locked-down platforms like iOS.

Summary

Dart 3.13 graduates primary constructors to stable, letting developers declare a class and its fields in a single line. A new `new` keyword inside classes replaces repetitive constructor names, and the formatter now groups imports by source and handles method chains more cleanly. On the documentation side, `dartdoc` can embed real, runnable example code directly from the `example/` directory.

Native tree shaking is the release's most impactful change. By annotating FFI bindings with `@RecordUse` and wiring a link hook into the build, Dart AOT now tells the native linker exactly which C/Rust symbols are reachable. A library exposing 300 APIs where only 20 are called can have the other 280 stripped from the final binary, and entirely unused native libraries can be dropped altogether.

An experimental dynamic modules feature also appears, aimed at letting AOT-compiled Dart code load new Dart modules at runtime. The immediate target is faster internal prototyping on iOS where JIT is unavailable, though the team explicitly states production server-driven UI is not a current priority.

Takeaways
Primary constructors are now stable: `class Point(final int x, final int y);` defines both fields and the constructor in one line.
Inside a class body, `new` replaces the class name for generative and factory constructors, reducing repetition.
`@RecordUse` annotation on FFI bindings lets Dart AOT record which native symbols are actually called.
A link hook consumes that recorded-use data and instructs the native linker to keep only those symbols, stripping the rest.
Unused native libraries can be excluded from the final app bundle entirely.
`dart2wasm` now supports deferred loading via `--enable-deferred-loading`, splitting deferred code into separate Wasm modules.
An experimental Dynamic Modules feature explores runtime loading of Dart code in AOT mode, initially for development workflows.
`dartdoc` can embed real code from `example/` using `{@example}` and hide boilerplate with `#hide`.
pub.dev switched to a two-level hash index, cutting documentation rendering latency for packages with 100k+ generated files.
`dart format` now groups `dart:`, `package:`, and project imports with blank lines and improved method-chain wrapping heuristics.
Conclusions

Native tree shaking reconnects two build pipelines that previously operated in isolation, meaning package authors can expose large native APIs without forcing consumers to pay the binary-size cost for unused functions.

The dynamic modules experiment, while framed as a developer-workflow feature, signals that the Dart team is willing to relax the closed-world assumption that has defined AOT compilation, which could eventually enable forms of code push on iOS.

Stabilizing primary constructors alongside a batch of lints and automated refactors shows the team is willing to push syntax modernization aggressively rather than letting new features languish as optional curiosities.

The `dartdoc` example-embedding feature addresses a real maintenance problem: documentation examples drifting out of sync with runnable example code, a pain point in many ecosystems beyond Dart.

Concepts & terms
Primary Constructors
A Dart language feature that allows declaring a class's constructor parameters and instance fields together in the class header, e.g., `class Point(final int x, final int y);`.
Native Tree Shaking
A Dart 3.13 feature that extends dead-code elimination across the FFI boundary. Annotations and link hooks let the Dart AOT compiler tell the native linker which C/Rust symbols are actually used, so unused native code can be stripped from the final binary.
Dynamic Modules
An experimental Dart runtime feature that allows AOT-compiled Dart programs to dynamically load additional Dart code at runtime, relaxing the traditional closed-world assumption of Dart AOT compilation.
Code Assets
A Flutter/Dart initiative to standardize how Dart packages carry, compile, and bind native C/C++/Rust code, making native dependencies as portable as pure Dart packages.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗