From 9e982e7d90fbe569f720f65107962231ff5d832f Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Fri, 11 Sep 2026 17:58:22 -0600 Subject: [PATCH] feat(start): explain selected examples before indexing --- src/components/StartExampleOverview.tsx | 55 ++++++++++ ...n.docs.framework.$framework.examples.$.tsx | 25 ++++- src/utils/sitemap.ts | 2 + src/utils/start-example-pages.ts | 102 ++++++++++++++++++ 4 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 src/components/StartExampleOverview.tsx create mode 100644 src/utils/start-example-pages.ts diff --git a/src/components/StartExampleOverview.tsx b/src/components/StartExampleOverview.tsx new file mode 100644 index 000000000..f5e7580dd --- /dev/null +++ b/src/components/StartExampleOverview.tsx @@ -0,0 +1,55 @@ +import { CodeBlock } from '~/components/markdown' +import { getStartExamplePage } from '~/utils/start-example-pages' + +export function StartExampleOverview({ + params, +}: { + params: { + libraryId: string + version: string + framework: string + _splat?: string + } +}) { + const page = getStartExamplePage(params) + if (!page) return null + const source = `https://github.com/TanStack/router/blob/main/examples/react/${page.slug}` + return ( +
+

{page.description}

+

{page.details}

+

Run locally

+

+ Use Node.js 22.12 or newer and pnpm 11. These examples fetch public + sample data from JSONPlaceholder, so an internet connection is required. + No API key or database is needed. +

+ + {`git clone https://github.com/TanStack/router.git +cd router +pnpm install +cd examples/react/${page.slug} +pnpm dev`} + +

{page.note}

+

+ Run pnpm build from the example directory to build the app + and check its types. +

+

Files to follow

+ +

+ + {page.guideTitle} + +

+
+ ) +} diff --git a/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx b/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx index 516e59fda..3c06f2a79 100644 --- a/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx +++ b/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx @@ -1,3 +1,5 @@ +import { StartExampleOverview } from '~/components/StartExampleOverview' +import { getStartExamplePage } from '~/utils/start-example-pages' import { ClientOnly, isNotFound, @@ -268,8 +270,13 @@ export const Route = createFileRoute( const library = getLibrary(params.libraryId) const exampleName = slugToTitle(params._splat || '') const frameworkName = capitalize(params.framework) - const ogTitle = `${frameworkName} ${library.name} ${exampleName} Example` - const ogDescription = `An example showing how to implement ${exampleName} in ${frameworkName} using ${library.name}.` + const overview = getStartExamplePage(params) + const ogTitle = + overview?.title ?? + `${frameworkName} ${library.name} ${exampleName} Example` + const ogDescription = + overview?.description ?? + `An example showing how to implement ${exampleName} in ${frameworkName} using ${library.name}.` const canonicalHref = canonicalUrl( loaderData?.canonicalPathOverride ?? buildExamplePath(params), @@ -532,7 +539,9 @@ function ExternalExamplePage({
- {capitalize(framework)} Example: {slugToTitle(_splat!)} + {getStartExamplePage({ libraryId, version, framework, _splat }) + ?.title ?? + `${capitalize(framework)} Example: ${slugToTitle(_splat!)}`}
{orderedExampleDeployProviders.map((provider) => @@ -569,6 +578,9 @@ function ExternalExamplePage({
+
- {capitalize(framework)} Example: {slugToTitle(_splat!)} + {getStartExamplePage({ libraryId, version, framework, _splat }) + ?.title ?? + `${capitalize(framework)} Example: ${slugToTitle(_splat!)}`}
+
diff --git a/src/utils/sitemap.ts b/src/utils/sitemap.ts index 60758d4c5..f818b1740 100644 --- a/src/utils/sitemap.ts +++ b/src/utils/sitemap.ts @@ -1,3 +1,4 @@ +import { getStartExampleSitemapEntries } from './start-example-pages' import { getBranch, libraries } from '~/libraries' import type { LibrarySlim } from '~/libraries/types' import { getPublishedPosts } from '~/utils/blog' @@ -118,6 +119,7 @@ export async function getSitemapEntries(): Promise> { const entries = [ ...HIGH_VALUE_NON_DOC_PAGES.map((path) => ({ path })), ...getLibraryEntries(), + ...getStartExampleSitemapEntries(), ...docsEntries.flat(), ...getBlogEntries(), ...getPartnerSitemapEntries(), diff --git a/src/utils/start-example-pages.ts b/src/utils/start-example-pages.ts new file mode 100644 index 000000000..f5b5da6fa --- /dev/null +++ b/src/utils/start-example-pages.ts @@ -0,0 +1,102 @@ +const startExamplePages = [ + { + slug: 'start-basic', + title: 'TanStack Start routing and server functions example', + description: + 'Explore file-based routes, nested layouts, server functions, and server-rendered pages in a runnable React application.', + details: + 'Browse posts and users, open a detail URL directly, and follow links between nested layouts. The post loaders call server functions, so you can follow the request from a route to the server and back to the page.', + files: [ + { + path: 'src/router.tsx', + description: + 'Creates the router and configures shared loading and error behavior.', + }, + { + path: 'src/routes/posts.tsx', + description: 'Loads the post list for the route.', + }, + { + path: 'src/utils/posts.tsx', + description: 'Fetches sample posts inside server functions.', + }, + ], + guide: 'routing', + guideTitle: 'Routing guide', + note: 'Open the local URL printed by Vite. Try a post detail URL in a new tab to see a direct server-rendered request.', + }, + { + slug: 'start-basic-react-query', + title: 'TanStack Start with React Query example', + description: + 'Connect React Query to TanStack Start for server rendering, route preloading, hydration, and cached client navigation.', + details: + 'Route loaders prepare query data before rendering. Components read the same query options, while the Router integration transfers server-fetched query data to the browser. Follow the post list into a detail page to see how route loading and query caching work together.', + files: [ + { + path: 'src/router.tsx', + description: + 'Creates a QueryClient for the router and connects the SSR query integration.', + }, + { + path: 'src/utils/posts.tsx', + description: 'Shares query keys and server-function query options.', + }, + { + path: 'src/routes/posts.$postId.tsx', + description: + 'Preloads and renders a post using the shared query options.', + }, + ], + guide: 'tanstack-query', + guideTitle: 'React Query integration guide', + note: 'Open the local URL printed by Vite. Visit a post directly, navigate back to the list, and inspect query state with the included devtools.', + }, + { + slug: 'start-basic-static', + title: 'TanStack Start static rendering example', + description: + 'Explore SPA mode, prerendered routes, and static server-function results in a React application built with TanStack Start.', + details: + 'This example combines SPA mode with link crawling during prerendering. Its post functions use static-function middleware to capture results for static output. Use it to understand the build configuration before adapting it to your own public content.', + files: [ + { + path: 'vite.config.ts', + description: + 'Configures the /test/ base path, SPA prerendering, link crawling, and sitemap host.', + }, + { + path: 'src/utils/posts.tsx', + description: 'Uses static-function middleware for public sample posts.', + }, + { + path: 'src/routes/posts.$postId.tsx', + description: 'Loads and displays an individual post.', + }, + ], + guide: 'static-prerendering', + guideTitle: 'Static prerendering guide', + note: 'Visit http://localhost:3000/test/ in development. Before publishing, replace the sample sitemap host and base path. The example sets failOnError to false, so inspect build output for failed pages. Static output is a build-time snapshot, not a live database.', + }, +] + +export function getStartExamplePage(params: { + libraryId: string + version: string + framework: string + _splat?: string +}) { + if ( + params.libraryId !== 'start' || + params.framework !== 'react' || + params.version !== 'latest' + ) + return undefined + return startExamplePages.find((page) => page.slug === params._splat) +} + +export function getStartExampleSitemapEntries() { + return startExamplePages.map((page) => ({ + path: `/start/latest/docs/framework/react/examples/${page.slug}`, + })) +}