Skip to content

Commit bcfe15e

Browse files
Merge remote-tracking branch 'origin/main' into HEAD
2 parents 1c2977c + 35485bb commit bcfe15e

File tree

105 files changed

+2729
-1023
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+2729
-1023
lines changed

docs/router/eslint/eslint-plugin-router.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,32 @@ Alternatively, add `@tanstack/eslint-plugin-router` to the plugins section, and
103103
The following rules are available in the TanStack Router ESLint Plugin:
104104

105105
- [@tanstack/router/create-route-property-order](../create-route-property-order.md)
106+
107+
## Conflicts with other ESLint plugins
108+
109+
If you have other ESLint plugins installed, they may rules that conflict with this plugin. If so, you'll need to make some tweaks to allow these plugins to work together.
110+
111+
### `typescript-eslint`
112+
113+
The [`@typescript-eslint/only-throw-error`](https://typescript-eslint.io/rules/only-throw-error/) rule, enabled by default in the `recommended-type-checked` and `strict-type-checked` rulesets, disallows the throwing of non-Error values as exceptions, which is considered a good practice.
114+
115+
To make sure it that it does not conflict with TanStack Router, you should add `redirect` to the allowed as a throwable objects.
116+
117+
```json
118+
{
119+
"rules": {
120+
"@typescript-eslint/only-throw-error": [
121+
"error",
122+
{
123+
"allow": [
124+
{
125+
"from": "package",
126+
"package": "@tanstack/router-core",
127+
"name": "Redirect"
128+
}
129+
]
130+
}
131+
]
132+
}
133+
}
134+
```

docs/router/framework/react/api/router/NotFoundErrorType.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,40 @@ export type NotFoundError = {
1111
data?: any
1212
throw?: boolean
1313
routeId?: string
14+
headers?: HeadersInit
1415
}
1516
```
1617
1718
## NotFoundError properties
1819
1920
The `NotFoundError` object accepts/contains the following properties:
2021
22+
### `global` property (⚠️ deprecated, use `routeId: rootRouteId` instead)
23+
24+
- Type: `boolean`
25+
- Optional - `default: false`
26+
- If true, the not-found error will be handled by the `notFoundComponent` of the root route instead of bubbling up from the route that threw it. This has the same behavior as importing the root route and calling `RootRoute.notFound()`.
27+
2128
### `data` property
2229
2330
- Type: `any`
2431
- Optional
2532
- Custom data that is passed into to `notFoundComponent` when the not-found error is handled
2633
27-
### `global` property
34+
### `throw` property
2835
2936
- Type: `boolean`
3037
- Optional - `default: false`
31-
- If true, the not-found error will be handled by the `notFoundComponent` of the root route instead of bubbling up from the route that threw it. This has the same behavior as importing the root route and calling `RootRoute.notFound()`.
38+
- If provided, will throw the not-found object instead of returning it. This can be useful in places where `throwing` in a function might cause it to have a return type of `never`. In that case, you can use `notFound({ throw: true })` to throw the not-found object instead of returning it.
3239
3340
### `route` property
3441
3542
- Type: `string`
3643
- Optional
3744
- The ID of the route that will attempt to handle the not-found error. If the route does not have a `notFoundComponent`, the error will bubble up to the parent route (and be handled by the root route if necessary). By default, TanStack Router will attempt to handle the not-found error with the route that threw it.
3845
39-
### `throw` property
46+
### `headers` property
4047
41-
- Type: `boolean`
42-
- Optional - `default: false`
43-
- If provided, will throw the not-found object instead of returning it. This can be useful in places where `throwing` in a function might cause it to have a return type of `never`. In that case, you can use `notFound({ throw: true })` to throw the not-found object instead of returning it.
48+
- Type: `HeadersInit`
49+
- Optional
50+
- HTTP headers to be included when the not-found error is handled on the server side.

docs/router/framework/react/api/router/RouteMatchType.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ interface RouteMatch {
1818
paramsError: unknown
1919
searchError: unknown
2020
updatedAt: number
21-
loadPromise?: Promise<void>
2221
loaderData?: Route['loaderData']
2322
context: Route['allContext']
2423
search: Route['fullSearchSchema']

docs/router/framework/react/faq.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Welcome to the TanStack Router FAQ! Here you'll find answers to common questions
66

77
## Should I commit my `routeTree.gen.ts` file into git?
88

9-
Yes! Although the route tree file (i.e. `routeTree.gen.ts`) is generated by the TanStack Router, it is essentially towards the runtime of your application. It is not a build artifact. The route tree file is a critical part of your application's source code, and it is used by the TanStack Router to build your application's routes at runtime.
9+
Yes! Although the route tree file (i.e., `routeTree.gen.ts`) is generated by TanStack Router, it is essentially part of your application’s runtime, not a build artifact. The route tree file is a critical part of your applications source code, and it is used by TanStack Router to build your applications routes at runtime.
1010

1111
You should commit this file into git so that other developers can use it to build your application.
1212

docs/start/framework/react/getting-started.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ title: Getting Started
55

66
To set up a TanStack Start project, you can:
77

8-
<!-- - Use the [TanStack Start CLI](https://github.com/tanstack/start/tree/main/packages/start-cli) to generate a new project and learn as you go -->
9-
8+
- Use the [TanStack Start CLI](https://github.com/TanStack/create-tsrouter-app/blob/main/cli/create-start-app/README.md) via `npx create-start-app@latest`
109
- Use the [Quick Start Examples](../quick-start) to rapidly learn as you go
1110
- [Build a project from scratch](../build-from-scratch) to learn how TanStack Start works from the ground up

docs/start/framework/react/static-prerendering.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default defineConfig({
4141
retryDelay: 1000,
4242

4343
// Callback when page is successfully rendered
44-
onSuccess: (page) => {
44+
onSuccess: ({ page }) => {
4545
console.log(`Rendered ${page.path}!`)
4646
},
4747
},

e2e/react-router/basic-file-based/src/routeTree.gen.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import { createFileRoute } from '@tanstack/react-router'
1212

1313
import { Route as rootRouteImport } from './routes/__root'
1414
import { Route as Char45824Char54620Char48124Char44397RouteImport } from './routes/대한민국'
15+
import { Route as RemountDepsRouteImport } from './routes/remountDeps'
1516
import { Route as PostsRouteImport } from './routes/posts'
17+
import { Route as NotRemountDepsRouteImport } from './routes/notRemountDeps'
1618
import { Route as EditingBRouteImport } from './routes/editing-b'
1719
import { Route as EditingARouteImport } from './routes/editing-a'
20+
import { Route as ComponentTypesTestRouteImport } from './routes/component-types-test'
1821
import { Route as AnchorRouteImport } from './routes/anchor'
1922
import { Route as LayoutRouteImport } from './routes/_layout'
2023
import { Route as SearchParamsRouteRouteImport } from './routes/search-params/route'
@@ -65,11 +68,21 @@ const Char45824Char54620Char48124Char44397Route =
6568
path: '/대한민국',
6669
getParentRoute: () => rootRouteImport,
6770
} as any)
71+
const RemountDepsRoute = RemountDepsRouteImport.update({
72+
id: '/remountDeps',
73+
path: '/remountDeps',
74+
getParentRoute: () => rootRouteImport,
75+
} as any)
6876
const PostsRoute = PostsRouteImport.update({
6977
id: '/posts',
7078
path: '/posts',
7179
getParentRoute: () => rootRouteImport,
7280
} as any)
81+
const NotRemountDepsRoute = NotRemountDepsRouteImport.update({
82+
id: '/notRemountDeps',
83+
path: '/notRemountDeps',
84+
getParentRoute: () => rootRouteImport,
85+
} as any)
7386
const EditingBRoute = EditingBRouteImport.update({
7487
id: '/editing-b',
7588
path: '/editing-b',
@@ -80,6 +93,11 @@ const EditingARoute = EditingARouteImport.update({
8093
path: '/editing-a',
8194
getParentRoute: () => rootRouteImport,
8295
} as any)
96+
const ComponentTypesTestRoute = ComponentTypesTestRouteImport.update({
97+
id: '/component-types-test',
98+
path: '/component-types-test',
99+
getParentRoute: () => rootRouteImport,
100+
} as any)
83101
const AnchorRoute = AnchorRouteImport.update({
84102
id: '/anchor',
85103
path: '/anchor',
@@ -276,9 +294,12 @@ export interface FileRoutesByFullPath {
276294
'/': typeof groupLayoutRouteWithChildren
277295
'/search-params': typeof SearchParamsRouteRouteWithChildren
278296
'/anchor': typeof AnchorRoute
297+
'/component-types-test': typeof ComponentTypesTestRoute
279298
'/editing-a': typeof EditingARoute
280299
'/editing-b': typeof EditingBRoute
300+
'/notRemountDeps': typeof NotRemountDepsRoute
281301
'/posts': typeof PostsRouteWithChildren
302+
'/remountDeps': typeof RemountDepsRoute
282303
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
283304
'/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute
284305
'/inside': typeof groupInsideRoute
@@ -315,8 +336,11 @@ export interface FileRoutesByFullPath {
315336
export interface FileRoutesByTo {
316337
'/': typeof groupLayoutRouteWithChildren
317338
'/anchor': typeof AnchorRoute
339+
'/component-types-test': typeof ComponentTypesTestRoute
318340
'/editing-a': typeof EditingARoute
319341
'/editing-b': typeof EditingBRoute
342+
'/notRemountDeps': typeof NotRemountDepsRoute
343+
'/remountDeps': typeof RemountDepsRoute
320344
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
321345
'/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute
322346
'/inside': typeof groupInsideRoute
@@ -355,9 +379,12 @@ export interface FileRoutesById {
355379
'/search-params': typeof SearchParamsRouteRouteWithChildren
356380
'/_layout': typeof LayoutRouteWithChildren
357381
'/anchor': typeof AnchorRoute
382+
'/component-types-test': typeof ComponentTypesTestRoute
358383
'/editing-a': typeof EditingARoute
359384
'/editing-b': typeof EditingBRoute
385+
'/notRemountDeps': typeof NotRemountDepsRoute
360386
'/posts': typeof PostsRouteWithChildren
387+
'/remountDeps': typeof RemountDepsRoute
361388
'/대한민국': typeof Char45824Char54620Char48124Char44397Route
362389
'/(another-group)/onlyrouteinside': typeof anotherGroupOnlyrouteinsideRoute
363390
'/(group)': typeof groupRouteWithChildren
@@ -400,9 +427,12 @@ export interface FileRouteTypes {
400427
| '/'
401428
| '/search-params'
402429
| '/anchor'
430+
| '/component-types-test'
403431
| '/editing-a'
404432
| '/editing-b'
433+
| '/notRemountDeps'
405434
| '/posts'
435+
| '/remountDeps'
406436
| '/대한민국'
407437
| '/onlyrouteinside'
408438
| '/inside'
@@ -439,8 +469,11 @@ export interface FileRouteTypes {
439469
to:
440470
| '/'
441471
| '/anchor'
472+
| '/component-types-test'
442473
| '/editing-a'
443474
| '/editing-b'
475+
| '/notRemountDeps'
476+
| '/remountDeps'
444477
| '/대한민국'
445478
| '/onlyrouteinside'
446479
| '/inside'
@@ -478,9 +511,12 @@ export interface FileRouteTypes {
478511
| '/search-params'
479512
| '/_layout'
480513
| '/anchor'
514+
| '/component-types-test'
481515
| '/editing-a'
482516
| '/editing-b'
517+
| '/notRemountDeps'
483518
| '/posts'
519+
| '/remountDeps'
484520
| '/대한민국'
485521
| '/(another-group)/onlyrouteinside'
486522
| '/(group)'
@@ -523,9 +559,12 @@ export interface RootRouteChildren {
523559
SearchParamsRouteRoute: typeof SearchParamsRouteRouteWithChildren
524560
LayoutRoute: typeof LayoutRouteWithChildren
525561
AnchorRoute: typeof AnchorRoute
562+
ComponentTypesTestRoute: typeof ComponentTypesTestRoute
526563
EditingARoute: typeof EditingARoute
527564
EditingBRoute: typeof EditingBRoute
565+
NotRemountDepsRoute: typeof NotRemountDepsRoute
528566
PostsRoute: typeof PostsRouteWithChildren
567+
RemountDepsRoute: typeof RemountDepsRoute
529568
Char45824Char54620Char48124Char44397Route: typeof Char45824Char54620Char48124Char44397Route
530569
anotherGroupOnlyrouteinsideRoute: typeof anotherGroupOnlyrouteinsideRoute
531570
groupRoute: typeof groupRouteWithChildren
@@ -564,13 +603,27 @@ declare module '@tanstack/react-router' {
564603
preLoaderRoute: typeof Char45824Char54620Char48124Char44397RouteImport
565604
parentRoute: typeof rootRouteImport
566605
}
606+
'/remountDeps': {
607+
id: '/remountDeps'
608+
path: '/remountDeps'
609+
fullPath: '/remountDeps'
610+
preLoaderRoute: typeof RemountDepsRouteImport
611+
parentRoute: typeof rootRouteImport
612+
}
567613
'/posts': {
568614
id: '/posts'
569615
path: '/posts'
570616
fullPath: '/posts'
571617
preLoaderRoute: typeof PostsRouteImport
572618
parentRoute: typeof rootRouteImport
573619
}
620+
'/notRemountDeps': {
621+
id: '/notRemountDeps'
622+
path: '/notRemountDeps'
623+
fullPath: '/notRemountDeps'
624+
preLoaderRoute: typeof NotRemountDepsRouteImport
625+
parentRoute: typeof rootRouteImport
626+
}
574627
'/editing-b': {
575628
id: '/editing-b'
576629
path: '/editing-b'
@@ -585,6 +638,13 @@ declare module '@tanstack/react-router' {
585638
preLoaderRoute: typeof EditingARouteImport
586639
parentRoute: typeof rootRouteImport
587640
}
641+
'/component-types-test': {
642+
id: '/component-types-test'
643+
path: '/component-types-test'
644+
fullPath: '/component-types-test'
645+
preLoaderRoute: typeof ComponentTypesTestRouteImport
646+
parentRoute: typeof rootRouteImport
647+
}
588648
'/anchor': {
589649
id: '/anchor'
590650
path: '/anchor'
@@ -946,9 +1006,12 @@ const rootRouteChildren: RootRouteChildren = {
9461006
SearchParamsRouteRoute: SearchParamsRouteRouteWithChildren,
9471007
LayoutRoute: LayoutRouteWithChildren,
9481008
AnchorRoute: AnchorRoute,
1009+
ComponentTypesTestRoute: ComponentTypesTestRoute,
9491010
EditingARoute: EditingARoute,
9501011
EditingBRoute: EditingBRoute,
1012+
NotRemountDepsRoute: NotRemountDepsRoute,
9511013
PostsRoute: PostsRouteWithChildren,
1014+
RemountDepsRoute: RemountDepsRoute,
9521015
Char45824Char54620Char48124Char44397Route:
9531016
Char45824Char54620Char48124Char44397Route,
9541017
anotherGroupOnlyrouteinsideRoute: anotherGroupOnlyrouteinsideRoute,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
3+
// Test route for type safety of different component types
4+
// This test should
5+
// - check that `false` can be set on the `errorComponent`
6+
// ...without causing build-time TypeScript errors
7+
export const Route = createFileRoute('/component-types-test')({
8+
component: () => <div>Testing test types</div>,
9+
errorComponent: false, // Should not cause TypeScript error
10+
pendingComponent: undefined, // Should not cause TypeScript error
11+
notFoundComponent: undefined, // Should not cause TypeScript error
12+
})
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
import * as React from 'react'
3+
4+
export const Route = createFileRoute('/notRemountDeps')({
5+
validateSearch(search: { searchParam: string }) {
6+
return { searchParam: search.searchParam }
7+
},
8+
loaderDeps(opts) {
9+
return opts.search
10+
},
11+
component: Home,
12+
remountDeps(opts) {
13+
return opts.params
14+
},
15+
})
16+
17+
let counter = 0
18+
19+
function Home() {
20+
const search = Route.useSearch()
21+
const navigate = Route.useNavigate()
22+
23+
const [mounts, setMounts] = React.useState(counter)
24+
React.useEffect(() => {
25+
setMounts(++counter)
26+
}, [])
27+
28+
return (
29+
<div className="p-2">
30+
<button
31+
onClick={() => {
32+
navigate({
33+
search: { searchParam: Math.random().toString(36).substring(2, 8) },
34+
})
35+
}}
36+
>
37+
Regenerate search param
38+
</button>
39+
40+
<div>Search: {search.searchParam}</div>
41+
<div data-testid="component-mounts">Page component mounts: {mounts}</div>
42+
</div>
43+
)
44+
}

0 commit comments

Comments
 (0)