Skip to content

Commit fa44180

Browse files
committed
Bump to latest wouter
1 parent 258b542 commit fa44180

File tree

13 files changed

+4120
-3259
lines changed

13 files changed

+4120
-3259
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,6 @@
5757
"@types/react": "17.0.4",
5858
"@types/react-dom": "17.0.4"
5959
}
60-
}
60+
},
61+
"packageManager": "[email protected]+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b"
6162
}

packages/fastify-renderer/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@
7070
"@vitejs/plugin-react-refresh": "^1.3.6",
7171
"fastify-plugin": "^4.5.1",
7272
"http-errors": "^1.8.1",
73-
"path-to-regexp": "^6.2.1",
73+
"path-to-regexp": "^8.2.0",
7474
"sanitize-filename": "^1.6.3",
7575
"stream-template": "^0.0.10",
7676
"vite": "^5.3.1",
77-
"wouter": "^2.11.0"
77+
"wouter": "^3.3.2"
7878
},
7979
"peerDependencies": {
8080
"fastify": "^4.24.2",

packages/fastify-renderer/src/client/react/Root.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React, { useEffect, useState } from 'react'
22
import { Route, Router, Switch, useLocation, useRouter } from 'wouter'
33
import { usePromise } from './fetcher'
4-
import { shouldScrollToHash, useNavigationDetails, useTransitionLocation } from './locationHook'
5-
import { matcher } from './matcher'
4+
import { shouldScrollToHash, useNavigationDetails, useTransitionLocation, TransitionProvider } from './locationHook'
5+
import { parser } from './parser'
66

77
export interface LayoutProps {
88
isNavigating: boolean
@@ -82,8 +82,10 @@ export function Root<BootProps extends Record<string, any>>(props: {
8282
]
8383

8484
return (
85-
<Router base={props.basePath} hook={useTransitionLocation as any} matcher={matcher}>
86-
<RouteTable routes={routes} Layout={props.Layout} bootProps={props.bootProps} />
87-
</Router>
85+
<TransitionProvider>
86+
<Router base={props.basePath} hook={useTransitionLocation as any} parser={parser}>
87+
<RouteTable routes={routes} Layout={props.Layout} bootProps={props.bootProps} />
88+
</Router>
89+
</TransitionProvider>
8890
)
8991
}

packages/fastify-renderer/src/client/react/locationHook.ts renamed to packages/fastify-renderer/src/client/react/locationHook.tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { unstable_useTransition as useTransition, useCallback, useEffect, useRef, useState } from 'react'
1+
import React, { useContext } from 'react'
2+
import { unstable_useTransition as useTransition, useCallback, useEffect, useRef, useState, createContext } from 'react'
23
import { NavigationHistory, useLocation, useRouter } from 'wouter'
34

45
/**
@@ -9,17 +10,37 @@ const eventPushState = 'pushState'
910
const eventReplaceState = 'replaceState'
1011
export const events = [eventPopstate, eventPushState, eventReplaceState]
1112

13+
const NavigationStateContext = createContext<{
14+
isNavigating: boolean
15+
startTransition: (callback: () => void) => void
16+
}>({
17+
isNavigating: false,
18+
startTransition: (callback: () => void) => callback(),
19+
})
20+
21+
/**
22+
* Internal context for the whole app capturing if we're currently navigating or not
23+
*/
24+
export const TransitionProvider = ({ children }: { children: React.ReactNode }) => {
25+
const [startTransition, isPending] = useTransition()
26+
27+
return (
28+
<NavigationStateContext.Provider value={{ isNavigating: isPending, startTransition }}>
29+
{children}
30+
</NavigationStateContext.Provider>
31+
)
32+
}
33+
1234
/**
1335
* This is a customized `useLocation` hook for `wouter`, adapted to use React's new Concurrent mode with `useTransition` for fastify-renderer.
1436
* @see https://github.com/molefrog/wouter#customizing-the-location-hook
1537
*
16-
* Extended to return an array of 4 elements:
17-
* @return [currentLocation, setLocation, isNavigating, navigationDestination]
38+
* Extended to stick the `isNavigating` and `navigationDestination` properties on the router object
1839
*/
1940
export const useTransitionLocation = ({ base = '' } = {}) => {
2041
const [path, update] = useState(() => currentPathname(base)) // @see https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
2142
const prevLocation = useRef(path + location.search + location.hash)
22-
const [startTransition, isPending] = useTransition()
43+
const { startTransition } = useContext(NavigationStateContext)
2344
const router = useRouter()
2445
useEffect(() => {
2546
if (!router.navigationHistory)
@@ -41,6 +62,8 @@ export const useTransitionLocation = ({ base = '' } = {}) => {
4162

4263
if (prevLocation.current !== destination) {
4364
prevLocation.current = destination
65+
router.navigationDestination = destination
66+
4467
if (shouldScrollToHash(router.navigationHistory)) {
4568
startTransition(() => {
4669
update(destination)
@@ -69,14 +92,12 @@ export const useTransitionLocation = ({ base = '' } = {}) => {
6992
// the function reference should stay the same between re-renders, so that
7093
// it can be passed down as an element prop without any performance concerns.
7194
const navigate = useCallback(
72-
(to, { replace = false } = {}) => {
73-
if (to[0] === '~') {
74-
window.location.href = to.slice(1)
95+
(path, { replace = false } = {}) => {
96+
if (path.startsWith('~') || !path.startsWith(base)) {
97+
window.location.href = path.slice(1)
7598
return
7699
}
77100

78-
const path = base + to
79-
80101
if (!router.navigationHistory) router.navigationHistory = {}
81102
if (router.navigationHistory?.current) {
82103
router.navigationHistory.previous = { ...router.navigationHistory.current }
@@ -97,7 +118,7 @@ export const useTransitionLocation = ({ base = '' } = {}) => {
97118
[base]
98119
)
99120

100-
return [path, navigate, isPending, prevLocation.current]
121+
return [path, navigate]
101122
}
102123

103124
// While History API does have `popstate` event, the only
@@ -122,11 +143,15 @@ if (typeof history !== 'undefined') {
122143

123144
/**
124145
* React hook to access the navigation details of the current context. Useful for capturing the details of an ongoing navigation in the existing page while React is rendering the new page.
146+
*
125147
* @returns [isNavigating: boolean, navigationDestination: string]
126148
*/
127149
export const useNavigationDetails = (): [boolean, string] => {
128-
const [_, __, isNavigating, navigationDestination] = useLocation() as unknown as [any, any, boolean, string] // we hack in more return values from our custom location hook to get at the transition current state and the destination
129-
return [isNavigating, navigationDestination]
150+
const router = useRouter()
151+
const [location] = useLocation()
152+
const { isNavigating } = useContext(NavigationStateContext)
153+
154+
return [isNavigating, router.navigationDestination || location]
130155
}
131156

132157
const currentPathname = (base, path = location.pathname + location.search + location.hash) =>

packages/fastify-renderer/src/client/react/matcher.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { pathToRegexp } from 'path-to-regexp'
2+
import { Parser } from 'wouter'
3+
4+
const cache: Record<string, ReturnType<Parser>> = {}
5+
6+
export const parser: Parser = (path, _loose) => {
7+
if (cache[path]) return cache[path]
8+
9+
try {
10+
const { regexp, keys } = pathToRegexp(path, {
11+
end: false, // we add our own, ok-with-a-query-string-or-hash-based end condition below
12+
})
13+
const pattern = new RegExp(`${regexp.source.replace('(?=\\/|$)', '')}(\\?.+)?(#.*)?$`)
14+
15+
cache[path] = {
16+
pattern,
17+
keys: keys.map((k) => k.name).filter((k) => !!k),
18+
}
19+
20+
return cache[path]
21+
} catch (error: any) {
22+
throw new Error(`Error parsing route syntax for '${path}' into regexp: ${error.message}`)
23+
}
24+
}

packages/fastify-renderer/src/client/react/wouter-extension.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'wouter'
33
declare module 'wouter' {
44
export interface RouterObject {
55
navigationHistory?: NavigationHistory
6+
navigationDestination?: string
67
}
78

89
export interface NavigationHistory {

packages/fastify-renderer/src/node/renderers/react/ReactRenderer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export class ReactRenderer implements Renderer {
101101
{
102102
base: render.base,
103103
hook: staticLocationHook(destination),
104+
ssrPath: destination,
104105
},
105106
React.createElement(
106107
Layout,
@@ -424,7 +425,7 @@ export class ReactRenderer implements Renderer {
424425
// b=2, a=1 if greater than 0
425426

426427
// Convert find-my-way route paths to path-to-regexp syntax
427-
const pathToRegexpify = (path: string) => path.replace('*', ':splat*')
428+
const pathToRegexpify = (path: string) => path.replace('*', '*splat')
428429

429430
return {
430431
name: 'fastify-renderer:react-route-table',

packages/test-apps/simple-react/helpers.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function slash(p: string): string {
1010

1111
const logs: string[] = ((global as any).browserLogs = [])
1212
const onConsole = (msg: ConsoleMessage) => {
13+
console.log('browser log', msg.text())
1314
logs.push(msg.text())
1415
}
1516
let pages: Page[] = []
@@ -60,7 +61,10 @@ afterEach(async () => {
6061

6162
/** Create a new playwright page for testing against */
6263
export const newTestPage = async (): Promise<Page> => {
63-
const browser = await chromium.launch({ headless: true })
64+
const browser = await chromium.launch({
65+
// headless: false, // Run in headful mode
66+
// slowMo: 100, // Optional: Slow down Playwright oper
67+
})
6468
const page: Page = await browser.newPage()
6569
page.on('console', onConsole)
6670
pages.push(page)

packages/test-apps/simple-react/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
"dependencies": {
1212
"fastify": "^4.23.2",
1313
"fastify-renderer": "workspace:*",
14-
"path-to-regexp": "^6.2.1",
14+
"path-to-regexp": "^8.2.0",
1515
"react": "*",
1616
"react-dom": "*",
1717
"stream-template": "^0.0.10",
18-
"wouter": "^2.11.0"
18+
"wouter": "^3.3.2"
1919
},
2020
"devDependencies": {
2121
"@playwright/test": "^1.39.0",

0 commit comments

Comments
 (0)