Commit activity
Last 12 weeks · 3 commits
Community health
4 of 6 standards met
Recent PRs & issues
Summary The router compared history events with the last committed location. During a suspended Back transition, that made Forward to the committed location look like a no-op. Compare with the pending target when one exists, and add a regression test and patch changeset. Evidence Before: the Back-to- then Forward-to- regression failed. The history was at , while the router committed after the resource resolved. After: the regression passes; the rendered location remains . : 260 tests passed; test typecheck passed. : passed. : passed. Patch policy accepted 3 text files / 70 changed lines; no binary files. Merge Danger Door: two-way Blast Radius: localized Fixes #687
Describe the bug Press Back, then press Forward before the route that Back entered has finished loading. The Forward is dropped: the address bar shows the Forward location; once the pending data resolves, the router commits and renders the Back location; reports the Back location. The app stays out of sync with the URL until the user navigates to another route or reloads. A link to the rendered route does nothing, because the router believes it is already there. The cause is that returns early when the target equals : https://github.com/solidjs/solid-router/blob/d0379e737c0feb9daa1d67cb94d132fa77638634/src/routing.ts#L487-L488 While the Back transition is pending, read outside it still holds the committed location, which is the page we were on before Back. Forward targets that same location, so treats it as a no-op, and the pending Back transition then commits. We hit this in a production app on pages whose data loads on entry. Your Example Website or App The repro is inline below, with no StackBlitz link. It is Vite + , and its only runtime dependencies are 1.9.15 and (0.15.4 or 1.0.0). Steps to Reproduce the Bug or Issue 1. Open , click slow, and wait until the page shows "Slow (loaded)". 2. Click fast. 3. Press browser Back, then Forward before 's 500 ms resource resolves. Expected behavior The page shows "Fast" at . Actual behavior: the address bar shows ; the page shows "Slow (loaded)"; is . Clicking slow then changes nothing. Clicking fast recovers. I measured this with Playwright, pressing Forward right after Back: Chromium 145: out of sync in 10 of 10 runs on 0.15.4, and in 10 of 10 on 1.0.0; Firefox 146 and WebKit 26: out of sync in 5 of 5 runs each, on 1.0.0. With Forward 1 s after Back, after the resource had resolved, every run was correct. Platform OS: Windows 11 Browser: Chromium 145, Firefox 146, WebKit 26 (Playwright builds) Version: 0.15.4 and 1.0.0, 1.9.15. has the same code. 2.0.0-next is a different implementation, and I did not test it. Additional context A possible fix is to compare against the pending target when there is one: With this change applied to the built bundle, Back → Forward ends on "Fast" in 10 of 10 runs on 0.15.4 and on 1.0.0. I have not run the router's test suite against it. makes the same comparison with (L613-L615). Clicking slow and then fast at once stays on in 10 of 10 runs. URL and page agree there, but the second click is lost. The change above does not cover that path.
runs on import and reads right after . In an iOS WKWebView (a Flutter embed in our case) doesn't throw but stays , so importing the router throws: Because it happens at module eval, the whole app bundle fails to load, even when only is used. This falls back to , the same value it tries to write. Nothing changes when works. Added a test that mocks as null and as a no-op. It fails without the fix. Same fix for : #627
Recent fixes
Before: the router's single flight (applying keys, , and flight data from a server function response) was installed only when the first router was created. A server function called straight from an event handler got none of it unless it went through . The router's also shared its name with solid-js's primitive. After: a mounted router subscribes to single flight itself (unless ), so any server function call gets revalidation and redirects. The router's action is renamed (type ), the form layer: submissions, , no-JS posts and . and stay as deprecated aliases with a one-time dev warning. is deprecated with no replacement; outside a form, call the server function or a core directly. and keep their names. How: The flight-data consumer moves from into , and the Router calls it at mount. The register/provide rendezvous is removed. Query reads, the consumer and actions share one redirect/revalidation helper (). As a result, action redirects now resolve against the router base the same way query redirects do. holds the alias; warns once in dev. README and tests are updated, and two patch changesets are added. Size (entry chunk, brotli, Vite production build through the entry): Tests: (710 client tests, 96 server tests, type tests) passes and (fs gate) passes. A new test checks that a router with no actions subscribes at mount and that never subscribes. 🤖 Generated with Claude Code https://claude.ai/code/session_01CLHVghj7oAvSMqnq9WRKdv
Before: a route's preload starts a fetch, and the page reads it a render pass later, behind its lazy chunk. The read gets a fresh wrapper, so in dev and observe builds both waterfall checks (the client's and the server's ) treat the work as starting at the read. That turns parallel route data into a false waterfall lead (solidjs/solid#4105). After: stamps the fetch when it starts, and stamps each wrapper it hands out with that same start, through . Both checks then see the data was already in flight and leave it out of the chain. How: one internal helper, called at the fetch and in . Both calls sit behind , the same pattern the router already uses for , so they fold out of shipped bundles. The slot's and come from solidjs/solid#4108. They're called optionally, so a without them is left alone. Tests: the new covers a preloaded fetch read later through a wrapper, a fresh fetch, and an older . The first two fail without the change. The full suite passes (711 client + 96 server), and so do and prettier. 🤖 Generated with Claude Code https://claude.ai/code/session_018LY7F9czoRqdMEvk2QwPr1 _Generated by Claude Code_
In Solid 2 throws when there is no provider, so every router primitive throws outside a router. That makes it awkward to write a component that renders both inside and outside one. My case is a link component that resolves relative hrefs against when it can, and is also used in an error fallback rendered by an boundary above the router: Moving the boundary into the root layout doesn't cover it. This is the last-resort boundary, so it also has to catch errors thrown by the layout itself and by the router setup, which a boundary inside the layout can't. Right now the link component has to catch the throw: Repro on (dc1e0b0), saved as a spec under : It fails with , thrown by inside . The router already makes this check internally. in wraps the same try/catch, and calls to warn about nested routers. I'd like to export that check as a boolean: The owner guard is there because swallows every error, including the one Solid throws when there is no owner. Without it, in an event handler under a router would return where throws. With it, calling it with no owner throws like the other primitives (solid-js doesn't export , so it reuses for the throw). If you'd rather it return there, that's a one-line change. The link component then becomes . I went with a boolean instead of something like because one check can guard any router hook, so there's no need for an optional variant of each. It also doesn't widen the context API, which #413 was wary of: on , the exported there throws the same way under . React Router ships the same check as . I know Solid 2 throws on a missing provider by design. The router already swallows that throw for its own checks, though, and users can't do the same without copying the try/catch. I have this implemented on with a test and a short README entry next to . Happy to rename it (, ) or drop it if you'd rather keep the surface as is. I opened a PR with it so you can see the shape.
Repository: solidjs/solid-router. Description: A universal router for Solid inspired by Ember and React Router Stars: 1320, Forks: 184. Primary language: TypeScript. Languages: TypeScript (76.5%), JavaScript (23.5%). License: MIT. Open PRs: 11, open issues: 26. Last activity: 4h ago. Community health: 75%. Top contributors: ryansolid, rturnq, Brendonovich, birkskyum, atilafassina, Brendan-csel, oedotme, Jutanium, jpdutoit, jchatard and others.