feat(adapters): add React Router v6 HashRouter support#1303
feat(adapters): add React Router v6 HashRouter support#1303
Conversation
|
@gsaandy is attempting to deploy a commit to the 47ng Team on Vercel. A member of the Team first needs to authorize it. |
84603d5 to
6cbd6ad
Compare
|
Wow, that's quite impressive, thanks! Since the hash part is never sent to the server, I don't think the shallow: false option makes sense for this adapter, it's only ever going to be used client-side (since RRv6 doesn't do SSR). It's mostly a way to control whether to call the loader or not (some sort of inverted logic for Feel free to add a job to the ci-cd.yml so we can have the test results in here. |
6cbd6ad to
b0d0ada
Compare
@franky47 - Updated the PR, could you take another look. |
4a53fae to
73f1760
Compare
Add a dedicated adapter for React Router v6 HashRouter (createHashRouter and <HashRouter>) which stores search params inside the URL hash fragment. This adapter correctly handles the HashRouter URL structure where params are at /#/page?foo=bar instead of /?foo=bar. New files: - adapters/react-router/v6-hash entry point - lib/hash-router.ts factory function - lib/hash-router-utils.ts URL parsing utilities - Full e2e test suite Closes 47ng#810 Closes 47ng#1173 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
73f1760 to
78b24f3
Compare
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
franky47
left a comment
There was a problem hiding this comment.
Thanks, I took a look and the main issue is the lack of actual test specs for the routes that are declared in the e2e-react-router-v6-hash package.
Once we actually have the basics (shared behaviour testing) covered, we could consider this a core adapter. If it works fine enough with manual testing, I'm also happy to add it as a community adapter as a shadcn registry item.
| "version": "0.0.0", | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "vite --port 3016", |
There was a problem hiding this comment.
praise: Good way to indicate we're still on RRv6, I like it.
suggestion: This should be added to the list of ports used in the CONTRIBUTING.md document.
There was a problem hiding this comment.
issue: These utility functions should be unit-tested against various (passing & edge) cases.
There was a problem hiding this comment.
note: It's hard to see the difference without an actual diff, but it looks like there is a lot of overlap between this implementation and that of the location.search-based adapters for RRv6/v7/Remix.
Would it make sense to make the generic implementation configurable to route to either the query string or the hash? (which may even open the possibility of having a hash-based behaviour for RRv7, not sure if Remix supports it).
| await page.goto('./#/basic-io/useQueryState?test=init') | ||
| await page.waitForLoadState('networkidle') | ||
| await page.locator('#hydration-marker').waitFor({ state: 'hidden' }) |
There was a problem hiding this comment.
suggestion: This could use the updated navigateTo implementation.
| return searchIndex >= 0 ? hashContent.slice(searchIndex) : '' | ||
| } | ||
|
|
||
| test.describe('HashRouter Basic I/O', () => { |
There was a problem hiding this comment.
note: Even though the URL structure is different than the BasicIO test, this should probably be placed in its own basic-io.spec.ts file to help sorting/filtering/maintaining test specs in the future.
There was a problem hiding this comment.
issue: Ah so that explains why the tests are passing, a lot of the test fixtures (routes) are actually not covered with specs.
They would actually not benefit from using the shared *.spec.ts files in e2e-shared, as those are querystring-based, but the rule of thumb is if a route is defined in the app, it should be covered by a test.
For an adapter to be officially supported in core, the list of tests defined in runSharedTests in packages/e2e/shared/shared.spec.ts is the minimum required. Some might actually not make sense in this case (eg: hash preservation, I don't think we can have another layer of hash at the end of the "query string" in the hash router). The other specs would need rewriting to handle the different setup & assertions on the URL (unless you have an idea on how to make it generic, using the abstractions you have in place for navigateTo and .toHaveUrl matchers. Note that we also have custom ones in expect-url.ts).
Thanks @franky47 for reviewing this, I ran it through claude and here is the refactoring plan, could you review this? Plan: Address Review Comments for React Router v6 HashRouter AdapterReview Comments Summary
Part 1: Refactor Adapters (Strategy Pattern)GoalMerge New File:
|
- Refactor hash-router.ts into react-router.ts using strategy pattern - Add RouterModeStrategy interface for mode-specific URL handling - Add unit tests for hash-router-utils.ts (27 tests) - Enable shared tests for v6-hash adapter with isHashRouter support - Update shared specs to pass isHashRouter to navigateTo - Skip Form tests (HTML forms use location.search, not hash) - Skip shallow routing tests (requires useNavigate not used in hash mode) - Add port 3016 to CONTRIBUTING.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
65b611d to
65a8e8e
Compare
|
@franky47 please review the new changes, and let me know if this approach works or not. |
|
@franky47 gentle reminder |
Summary
createHashRouterand<HashRouter>)(
/#/page?foo=barinstead of/?foo=bar)New Files
nuqs/adapters/react-router/v6-hash- Entry pointsrc/adapters/lib/hash-router.ts- Factory functionsrc/adapters/lib/hash-router-utils.ts- URL parsing utilitiespackages/e2e/react-router/v6-hash/- E2E test suiteTest plan
pnpm run test:unit)pnpm run build)createHashRouterCloses #810
Closes #1173