Skip to content

Claude/modernize swift flutter deps h2k3w2 - #1520

Closed
crochik wants to merge 6 commits into
Sub6Resources:masterfrom
crochik:claude/modernize-swift-flutter-deps-h2k3w2
Closed

crochik wants to merge 6 commits into
Sub6Resources:masterfrom
crochik:claude/modernize-swift-flutter-deps-h2k3w2

Conversation

@crochik

@crochik crochik commented Sep 1, 2026

Copy link
Copy Markdown

No description provided.

claude and others added 6 commits September 1, 2026 14:41
Modernizes the toolchain and dependency set so the repo builds and tests
cleanly on the current Flutter stable release.

- Bump Dart/Flutter SDK constraints per package to match what the upgraded
  dependencies actually require, and raise dependency floors (flutter_lints 6,
  meta 1.19, melos 8, video_player 2.14, webview_flutter 4.14, flutter_svg 2.3,
  chewie 1.16, flutter_layout_grid 2.0.8, html 0.15.7).
- Migrate the monorepo from the legacy melos.yaml layout to Dart pub
  workspaces, which Melos 8 requires: the root pubspec now declares the
  workspace members plus a `melos:` config block, and each member declares
  `resolution: workspace`. Scripts are ported to the Melos 8 `exec.command`
  schema.
- Fix StyledElement.matches for html 0.15.7, which no longer exposes a
  top-level `matches(Element, String)`. The selector is now parsed with csslib
  and evaluated through SelectorEvaluator.
- Fix a semantics assertion that made <details> crash on current Flutter. The
  ExpansionTile's semantics config conflicted with the sibling text fragments
  of the enclosing paragraph; marking it as its own semantics container keeps
  it out of that merge group.
- Replace repeated `_` parameters with wildcards for the new
  unnecessary_underscores lint, and reformat with the Dart 3.7+ tall style so
  the CI format check passes.

Verified on Flutter 3.47.2: melos analyze --fatal-infos is clean across all
nine packages, all 242 tests pass, and dart format reports no changes.
…latforms

The example app's native projects had drifted years behind the Flutter
templates: the iOS project was objectVersion 50 with a deployment target of
9.0 and a mixed ObjC/Swift Runner, Android was on Gradle 6.5/AGP 4.1.1 with
the shut-down jcenter repository, and the checked-in Podfile.lock still
referenced the long-removed wakelock plugin. None of it builds under current
Flutter, so the platform directories are regenerated from the Flutter 3.47.2
templates.

Swift Package Manager is the default in Flutter 3.47, so the regenerated iOS
and macOS projects carry a FlutterGeneratedPluginSwiftPackage local package
reference instead of a Podfile. Both Podfiles and Podfile.locks are gone, and
the obsolete Flutter.podspec ignore rule with them. All four Darwin plugins
the example pulls in (package_info_plus, video_player_avfoundation,
wakelock_plus, webview_flutter_wkwebview) ship a Package.swift, so nothing
needs a CocoaPods fallback.

Alongside that, the regeneration brings iOS 15 / macOS 12 deployment targets,
a Swift-only Runner with SceneDelegate, the Kotlin DSL Android build with
Kotlin 2.4 and JDK 17, and the flutter_bootstrap.js web loader.

The two genuine customizations in the old projects are re-applied on top: the
Android INTERNET permission and the macOS network client entitlement, both of
which the example needs to render network images, video and web content. The
macOS release entitlements previously lacked the network client, so sandboxed
release builds could not load them at all.

Also fixes two web bugs uncovered while verifying the build:

- flutter_html_iframe used ui.platformViewRegistry through a local dart:ui
  shim. platformViewRegistry now lives in dart:ui_web, so the shim is deleted
  and the web implementation imports dart:ui_web directly.
- The conditional import selected the web implementation on dart.library.html,
  which is false under Wasm. Wasm builds therefore fell back to the
  "unsupported" stub and silently rendered no iframes. It now keys off
  dart.library.js_interop, which is true for both dart2js and Wasm.

Verified on Flutter 3.47.2: `flutter build web` and `flutter build web --wasm`
both succeed for the example, analysis is clean across all nine packages, and
all 242 tests pass. The iOS/macOS projects are verbatim Flutter 3.47.2 template
output, so they could not be compiled here (no macOS/Xcode); the Linux desktop
build was likewise not exercised because GTK development headers are not
installed in this environment.
Adds a SessionStart hook so Claude Code on the web sessions come up with a
working toolchain instead of starting from a container with no Flutter at all.
The hook pins Flutter 3.47.2 to match the revision in .metadata, installs it
only when it is missing or the wrong version, puts it on PATH for the rest of
the session via CLAUDE_ENV_FILE, resolves the pub workspace, and warms the web
artifacts so that download lands in the cached container image rather than
mid-session. It exits immediately outside the remote environment, so local
checkouts keep using whatever Flutter the developer already has.

The CI workflow is updated for the Melos 8 / pub workspace layout. Melos is a
dev_dependency now, so `flutter pub global activate melos` and the separate
bootstrap step are gone: a single `flutter pub get` resolves every package and
installs the pinned Melos, which is then invoked with `dart run melos`. The
Flutter version is pinned to 3.47.2 with SDK and pub caching enabled, and the
format check moved into a melos script so it can be run the same way locally.

Verified locally on Flutter 3.47.2: the hook succeeds both on a clean install
into an empty prefix and on the already-installed path, and is a no-op when
CLAUDE_CODE_REMOTE is unset. Every workflow step was run by hand — analyze,
test, gen_coverage (39 source files in the combined lcov report) and
format:check all pass.
…s-h2k3w2

Reformat code to match Dart style guide conventions
Captures the things that take reading several files to work out: the five-stage
HtmlParser pipeline and why the processTree passes are ordered as they are, the
extension resolution order that lets user extensions override built-ins, the
style cascade, and the tree element hierarchy.

Also records the setup that is easy to get wrong. Melos 7+ dropped melos.yaml,
so the configuration lives under the `melos:` key in the root pubspec with the
workspace member list; Melos is a dev_dependency and must be invoked through
`dart run`. Notes the deliberate `implementation_imports` suppression in
StyledElement.matchesSelector as the thing to re-check after an `html` package
upgrade, the iframe package's dart:ui_web / dart.library.js_interop
requirement, the two hand-applied edits in the otherwise stock example platform
directories, and the fact that golden_test.dart's matchesGoldenFile calls are
commented out so a passing golden test proves nothing visual.

Every command in the file was run against Flutter 3.47.2 before writing it down.
Running the example app on current Flutter threw
`renderBoxDoingDryBaseline == null` during performLayout and then cascaded into
a dozen "RenderBox was not laid out" failures. The minimal trigger is an <img>
inside a <table>; the error names RenderSemanticsAnnotations, which is a red
herring, and the reported stack contains no dry-baseline frame at all.

The underlying problem is a Flutter framework gap: RenderImage implements
neither computeDryBaseline nor computeDistanceToActualBaseline, and the default
computeDryBaseline throws via debugCannotComputeDryLayout. That throw escapes
from inside getDryBaseline, which permanently leaves the framework's
_computingThisDryBaseline debug flag set on an ancestor, so every subsequent
layout of that subtree trips an assertion pointing at the wrong object. It
reproduces with no flutter_html involved at all:

    IntrinsicHeight(child: Text.rich(TextSpan(children: [
      WidgetSpan(alignment: PlaceholderAlignment.baseline, child: Image(...)),
    ])))

Table layout is what makes this reachable, because it sizes rows intrinsically
and so asks the baseline-aligned image placeholder for a dry baseline.

Two fixes, both needed:

- Images are replaced content. CSS aligns replaced content by its bottom margin
  edge rather than a text baseline, so PlaceholderAlignment.baseline was never
  meaningful for them; requesting it is what walks into the RenderImage gap.
  ImageBuiltIn now maps baseline to bottom for the image placeholder.

- RenderCSSBox had the same class of bug as RenderImage: computeDryBaseline
  returned a bare null while computeDistanceToActualBaseline deferred to the
  child. Flutter's _debugVerifyDryBaselines throws on exactly that mismatch. It
  now resolves the child's dry baseline against the same constraints
  performLayout uses, and returns null for replaced children, where the real
  baseline is null too. The child constraint calculation is factored out of
  _computeSize so both paths cannot drift apart.

Declaring the limitation with debugCannotComputeDryLayout was tried and does
not work here: it also throws for the caller that matters, Flutter's own
_RenderScaledInlineWidget laying out a baseline-aligned WidgetSpan with
debugCheckingIntrinsics false.

The example package's only test was a `2 + 2 == 4` placeholder, which is why CI
stayed green while the app itself could not render a frame. It now pumps the
real example page and asserts the rendering pipeline reports no errors, plus a
focused case for an image inside a table.

Verified on Flutter 3.47.2: the full example page renders with zero exceptions,
analysis is clean across all nine packages, all 243 tests pass, and dart format
reports no changes.
@crochik crochik closed this Sep 1, 2026
@crochik
crochik deleted the claude/modernize-swift-flutter-deps-h2k3w2 branch September 1, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants