Skip to content

Use the effect primitives Solid 2 actually kept - #247

Merged
pathscale merged 2 commits into
masterfrom
fix/solid-2-tracked-effect
Aug 16, 2026
Merged

Use the effect primitives Solid 2 actually kept#247
pathscale merged 2 commits into
masterfrom
fix/solid-2-tracked-effect

Conversation

@pathscale

Copy link
Copy Markdown
Owner

Why

@pathscale/ui@2.6.1 requires solid-js >=2.0.0-rc.0, but its components are still written against Solid 1's effect API. Solid 2 changed two rules, and the library breaks on both:

  1. createEffect gained a second parameter. The first function tracks and returns a value; the second receives it and runs untracked. A lone function is rejected with MISSING_EFFECT_FN.
  2. onCleanup is no longer allowed inside a tracked effect or a settled callback. They own teardown through the function they return, and calling it is refused with CLEANUP_IN_FORBIDDEN_SCOPE.

Either error halts the reactive system, so any page reaching one renders blank. Tabs was where promptsyntax.org hit it: the home page came up empty with MISSING_EFFECT_FN.

What changed

  • 65 createEffect(fn) call sites become createTrackedEffect(fn), the primitive that kept Solid 1's semantics: one function, whole body tracked. This is deliberately a rename, not a rewrite. The two forms are not interchangeable, and choosing between them per site is a judgement about which reads are dependencies. Splitting them into the two-argument form is worth doing, but not in the change that makes the library run again.
  • 16 tracked effects and 8 settled callbacks return their teardown instead of calling onCleanup. Most were a trailing onCleanup that became a return. Four registered cleanup from inside a conditional or partway through a callback that then bails out early: two invert the guard, and two name the teardown and return it from each exit rather than reordering the work around it.
  • Imports follow: createTrackedEffect replaces createEffect, and onCleanup is dropped where it is no longer called.

36 files, 152 insertions, 152 deletions. No public API or prop changes.

Verification

  • bun run build succeeds. On master with the same clean tree it also succeeds, so this is a like-for-like comparison.
  • bun run lint reports the same 148 errors as master. The warning count differs by three, all in chatbubble and card generated files that this branch does not touch.
  • Built this branch and pointed promptsyntax.org (solid-js 2.0.0-rc.0, @solidjs/router 2.0.0-next.16) at the output. Every route renders with zero console errors: /, /spec, /syntax, /vignette. Tabs switch panels, the theme toggle flips light and dark, and client-side navigation works. Before this change the home page was blank with MISSING_EFFECT_FN, and after the first commit alone it still threw CLEANUP_IN_FORBIDDEN_SCOPE.

Follow-up worth tracking separately

Moving these 65 sites onto the two-argument createEffect would make dependencies explicit and is the shape Solid 2 is steering toward. It needs a per-site decision about which reads are dependencies, so it belongs in its own change with its own review.

meh added 2 commits August 16, 2026 20:46
Every effect in the library was written against Solid 1, where
`createEffect(fn)` tracked whatever the body read. Solid 2 gives that
signature a second parameter and splits the work: the first function
tracks and returns a value, the second receives it and runs untracked.
A lone function is now rejected outright with MISSING_EFFECT_FN, which
halts the reactive system, so any component reaching one of these took
its whole page down.

`createTrackedEffect` is the primitive that kept the old behaviour, so
this is a rename across the 65 call sites rather than a rewrite. The two
forms are not interchangeable, and choosing between them per site is a
judgement about which reads are dependencies; splitting them is worth
doing, but not while the library does not run.

Cleanup had to move with it. A tracked effect owns its teardown through
the function it returns, and calling `onCleanup` inside one is refused
with CLEANUP_IN_FORBIDDEN_SCOPE, so the 16 effects that registered
teardown that way now return it instead. Two of them registered cleanup
from inside a conditional, which a return cannot express, so those
invert the guard first.

Fixes the blank home page seen on promptsyntax.org, where Tabs was the
component that reached one of these first.
Same rule as the tracked effects in the previous commit: `onSettled`
owns its teardown through the function it returns, and calling
`onCleanup` inside one is refused with CLEANUP_IN_FORBIDDEN_SCOPE.
Eight callbacks still registered cleanup that way.

Six were a trailing `onCleanup` and became a return. The other two
registered it partway through a callback that then goes on to bail out
early, so those name the teardown and return it from each exit rather
than reordering the work around it.
@pathscale
pathscale merged commit 95c3622 into master Aug 16, 2026
1 check passed
@pathscale
pathscale deleted the fix/solid-2-tracked-effect branch August 16, 2026 14:11
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.

1 participant