Skip to content

Pull out internal RenderDriver trait, remove suspense special casing#5634

Open
ealmloff wants to merge 16 commits into
mainfrom
devin/1781646203-render-driver-trait
Open

Pull out internal RenderDriver trait, remove suspense special casing#5634
ealmloff wants to merge 16 commits into
mainfrom
devin/1781646203-render-driver-trait

Conversation

@ealmloff

Copy link
Copy Markdown
Member

Suspense has different diffing behavior for diffing child scopes in the background which is currently implemented with logic built into the core diffing engine to check if the scope is suspense before creating, diffing and removing suspense scopes.

That logic can easily get out of date as diffing code changes and doesn't scale well as more specialized components like Portal are introduced.

This PR pulls out an internal RenderDriver trait that is implemented for both suspense and function components and moves the specialized suspense logic into the suspense trait implementation.

To make this trait boxable, it switches to &mut dyn MutationsWriter internally instead of passing around generics. This doesn't appear to have any noticeable performance impact on the js framework microbenchmark outside of noise

This was pulled out of #5554

devin-ai-integration Bot and others added 8 commits June 16, 2026 22:16
Replace the type-erased AnyProps (BoxedAnyProps / Box<dyn AnyProps>)
approach with a trait-based RenderDriver abstraction for component
lifecycle dispatch.

Key changes:
- New render_driver.rs: RenderDriver trait + BodyDriver (plain
  components) + DynWriter (sized wrapper bridging dyn WriteMutations
  into the generic diff pipeline)
- VComponent now holds Rc<dyn RenderDriver> instead of BoxedAnyProps
  + render_fn
- ScopeState no longer stores props directly; the driver owns them
- scope_arena: new_scope() takes an Rc<dyn RenderDriver>;
  run_scope_with() replaces the old props-based run_scope()
- diff/component.rs: create/diff/remove dispatch through the driver
- suspense/component.rs: SuspenseDriver implements RenderDriver for
  suspense boundaries
- Deleted any_props.rs

Co-Authored-By: Evan Almloff <evanalmloff@gmail.com>
- Add SuspenseBoundary variant to SuspenseLocation enum so boundary
  scopes properly report should_run_during_suspense() = true
- Set SuspenseBoundary location on the boundary scope during creation
- Move dirty_scopes.remove() in BodyDriver::create inside the
  new-scope-only branch to prevent premature removal of child scopes
  during suspense resolution's replace path
- Make suspense_location field a RefCell to allow post-creation updates
- Fix formatting issues

Co-Authored-By: Evan Almloff <evanalmloff@gmail.com>
- Convert RenderDriver from trait object (dyn RenderDriver) to enum with
  Body(Rc<dyn BodyProps>) and Suspense(Rc<SuspenseDriver>) variants
- Remove DynWriter entirely; methods are now generic over M: WriteMutations
- Move suspense_boundary ownership from Scope into SuspenseDriver
  (SuspenseContext is now owned by the driver, not an optional field on every scope)
- Scope::suspense_boundary() now delegates to RenderDriver::suspense_context()
- BodyProps trait handles type erasure for generic component functions
- All call sites use direct generic Option<&mut M> instead of DynWriter::erase()

Co-Authored-By: Evan Almloff <evanalmloff@gmail.com>
…s, remove DynWriter

- RenderDriver is now a trait (Rc<dyn RenderDriver>) instead of an enum
- Methods take Option<&mut dyn WriteMutations> directly, no DynWriter wrapper
- Added blanket impl WriteMutations for &mut T where T: WriteMutations + ?Sized
  to allow passing &mut dyn WriteMutations through generic call chains
- SuspenseDriver implements RenderDriver trait with suspense_context() method
- suspense_boundary lives in the driver, not as an optional field on Scope
- Call sites cast inline: to.map(|m| m as &mut dyn WriteMutations)

Co-Authored-By: Evan Almloff <evanalmloff@gmail.com>
@ealmloff ealmloff requested a review from a team as a code owner June 17, 2026 14:13
@ealmloff ealmloff added the core relating to the core implementation of the virtualdom label Jun 17, 2026
@ealmloff ealmloff marked this pull request as draft June 17, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core relating to the core implementation of the virtualdom

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant