Skip to content

Conversation

simonihmig
Copy link

@simonihmig simonihmig commented Sep 2, 2025

As discussed with the team on Discord, this is adding an example app to showcase the integration with responsive-image.dev. It is a very simple gallery app with some basic routing, and using local images processed by the vite-plugin and rendered by the <ResponsiveImage> component, with different layout modes (fixed for the thumbnails and responsive for the large one):

image

The gallery images use a more dynamic way of importing with import.meta.glob, but the index page also has a more static example for the TanStack logo.

The app was created using create-ts-app, I am not sure if there is something else to do for better integration/alignment/cleanup with the monorepo and the other examples here, so let me know if there is!

Working on this example uncovered a bug on my side, which is not fixed yet. It manifests as the ThumbHash based LQIP (Low Quality Image Placeholder) not showing correctly when switching between images (only working for the initial render). You would have to set network throttling in DevTools to be able to actually see this clearly 😅. So not a huge deal breaker - we can either delay merging this until this is fixed, or update with a new patch release later, as you prefer.

Summary by CodeRabbit

  • New Features

    • New React example showcasing responsive images: thumbnail gallery, image detail route, responsive layout, and devtools integration.
  • Documentation

    • Added README with integration notes and local run instructions.
  • Chores

    • Added example scaffolding: package manifest and scripts, TypeScript and Vite configs, global styles, PWA manifest, robots.txt, .gitignore, build/dev tooling, and image processing setup.

Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Walkthrough

Adds a new React + Vite example at examples/react/with-responsive-image demonstrating TanStack Router + ResponsiveImage integration, including project scaffolding, routes (/, /$imageId), image utilities, styles, PWA assets, Vite config, and dev tooling.

Changes

Cohort / File(s) Summary
Project scaffolding
examples/react/with-responsive-image/.cta.json, examples/react/with-responsive-image/.gitignore, examples/react/with-responsive-image/package.json, examples/react/with-responsive-image/tsconfig.json, examples/react/with-responsive-image/vite.config.ts, examples/react/with-responsive-image/index.html
Adds example project metadata, gitignore, package manifest, TypeScript config, Vite config (tanstackRouter + ResponsiveImage plugin), and HTML shell.
Public assets (PWA / robots)
examples/react/with-responsive-image/public/manifest.json, examples/react/with-responsive-image/public/robots.txt
Adds web manifest and permissive robots.txt.
Routing & app shell
examples/react/with-responsive-image/src/main.tsx, examples/react/with-responsive-image/src/routeTree.gen.ts, examples/react/with-responsive-image/src/routes/__root.tsx, examples/react/with-responsive-image/src/routes/index.tsx, examples/react/with-responsive-image/src/routes/$imageId.tsx
Introduces TanStack Router bootstrap, generated route tree and file-based routes, root layout with thumbnail navigation and Outlet, index route, and dynamic image route with loader.
Image utilities
examples/react/with-responsive-image/src/images.ts, examples/react/with-responsive-image/src/global.d.ts
Adds eager import globs for thumbnails and full images, exports helpers getThumbsnails() and getImage(imageId) (throws notFound on miss), and ambient module for '*responsive' imports.
Styles
examples/react/with-responsive-image/src/styles.css, examples/react/with-responsive-image/src/routes/app.css
Adds global and route-specific CSS for layout, thumbnail strip, and large image rendering.
Diagnostics / docs
examples/react/with-responsive-image/src/reportWebVitals.ts, examples/react/with-responsive-image/README.md
Adds web-vitals reporting helper and example README with quick-start and links.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant B as Browser
  participant R as TanStack Router
  participant Root as Root Route (App)
  participant Images as images.ts
  participant RI as ResponsiveImage

  U->>B: Request "/"
  B->>R: resolve "/"
  R->>Root: render Index
  Root->>RI: render splash image
  R-->>B: render page

  U->>B: Click thumbnail -> navigate "/:imageId"
  B->>R: navigate "/:imageId"
  R->>Images: getImage(imageId)
  alt image found
    Images-->>R: ImageData
    R->>RI: render <ResponsiveImage src=ImageData />
    RI-->>B: display responsive image
  else not found
    Images-->>R: throw notFound()
    R-->>B: show Not Found
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Suggested labels

documentation

Suggested reviewers

  • schiller-manuel

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title “docs: add with-responsive-image example app” accurately and concisely summarizes the main change of adding a new example application for the responsive-image integration without unnecessary detail or noise. It clearly reflects the key addition that a reader scanning the history would understand immediately. As such, it aligns with the criteria for a good pull request title.
Description Check ✅ Passed The description provides context for the addition of the example app, details its functionality, and mentions relevant tooling and a known bug, which all directly relate to the changes in the pull request. It clearly describes the content and purpose of the new example without deviating off-topic. This level of detail satisfies the criteria for passing the description check.

Poem

Hop hop, I stitched the routes with care,
Thumbs parade and pixels flare. 🐇
Vite hums soft, the router sings,
Images scale on nimble wings.
Click a thumb — behold the view!

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (25)
examples/react/with-responsive-image/public/robots.txt (1)

1-3: Decide if the example should be indexable; current robots.txt allows all crawling

Disallow: with an empty value permits crawling. For examples, we typically block indexing to avoid SEO noise.

Apply this if you want to block indexing:

-# https://www.robotstxt.org/robotstxt.html
-User-agent: *
-Disallow:
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow: /

Optional: also add a <meta name="robots" content="noindex"> in index.html or an X-Robots-Tag header.

examples/react/with-responsive-image/src/styles.css (1)

13-20: Add focus-visible styles for keyboard a11y on dark background

Improve discoverability of links when tabbing.

 a {
   color: #00c2ab;
 }
 
+/* Improve keyboard accessibility */
+a:focus-visible {
+  outline: 2px solid currentColor;
+  outline-offset: 2px;
+}
examples/react/with-responsive-image/public/manifest.json (1)

2-4: Align PWA metadata with this example (name and colors)

These look like scaffold defaults. Consider updating names and making the splash background match the app’s black theme.

-  "short_name": "TanStack App",
-  "name": "Create TanStack App Sample",
+  "short_name": "ResponsiveImage",
+  "name": "TanStack + ResponsiveImage Example",
@@
-  "background_color": "#ffffff"
+  "background_color": "#000000",
+  "scope": ".",
+  "id": "."

Also applies to: 21-24

examples/react/with-responsive-image/README.md (1)

5-5: Document known LQIP placeholder issue from PR description

Make users aware of the temporary glitch when testing with throttled networks.

-Run `pnpm dev` to run locally.
+Run `pnpm dev` to run locally.
+
+## Known issue
+When testing with network throttling, the ThumbHash-based LQIP placeholder may not update when switching images due to an upstream bug in the `responsive-image` package. This example will be updated after a patch release.
examples/react/with-responsive-image/.gitignore (1)

1-9: Ignore a few common local artifacts (logs/IDE/coverage)

Small quality-of-life additions; safe for examples.

 node_modules
 .DS_Store
 dist
 dist-ssr
 *.local
 count.txt
 .env
 .nitro
 .tanstack
+coverage
+.vscode
+.idea
+pnpm-debug.log*
+npm-debug.log*
+yarn-error.log*
examples/react/with-responsive-image/.cta.json (1)

1-11: Update framework in .cta.json to “react-vite”

In examples/react/with-responsive-image/.cta.json, change the framework value to align with the Vite setup:

-  "framework": "react-cra",
+  "framework": "react-vite",
examples/react/with-responsive-image/src/reportWebVitals.ts (1)

1-11: Type the callback as ReportHandler and simplify the guard

Improves typings and narrows correctly; optional no-op catch to avoid unhandled rejections.

-const reportWebVitals = (onPerfEntry?: () => void) => {
-  if (onPerfEntry && onPerfEntry instanceof Function) {
-    import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {
+import type { ReportHandler } from 'web-vitals'
+const reportWebVitals = (onPerfEntry?: ReportHandler) => {
+  if (typeof onPerfEntry === 'function') {
+    void import('web-vitals').then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {
       onCLS(onPerfEntry)
       onINP(onPerfEntry)
       onFCP(onPerfEntry)
       onLCP(onPerfEntry)
       onTTFB(onPerfEntry)
-    })
+    }).catch(() => {})
   }
 }
examples/react/with-responsive-image/src/routes/app.css (2)

13-15: Add visible keyboard focus for thumbnails

Better a11y without changing visuals.

 aside a.active {
   border-color: #00c2ab;
 }
+aside a:focus-visible {
+  outline: 2px solid #00c2ab;
+  outline-offset: 2px;
+  border-radius: 4px;
+}

31-34: Constrain large image width to prevent overflow

Keeps image within viewport on narrow screens.

 img.large {
   max-height: calc(100vh - 140px);
-  width: auto;
+  width: auto;
+  max-width: 100%;
+  height: auto;
 }
examples/react/with-responsive-image/index.html (1)

8-11: Fix meta description branding

Minor copy tweak for consistency.

-      content="Web site created using create-tsrouter-app"
+      content="Website created using Create TanStack App"
examples/react/with-responsive-image/src/routes/$imageId.tsx (2)

13-13: Add alt text for accessibility.

If decorative, use alt=""; if meaningful, pass a descriptive alt (ideally from image metadata).

-  return <ResponsiveImage src={image} className="large" />
+  return <ResponsiveImage src={image} className="large" alt="" />

3-3: Drop the .ts extension for consistency with Vite/TS resolution.

-import { getImage } from '../images.ts'
+import { getImage } from '../images'
examples/react/with-responsive-image/src/routes/index.tsx (1)

12-12: Provide alt (and optional sizes) on the hero image.

Improves a11y; sizes helps the browser pick the right source.

-      <ResponsiveImage src={visual} width={300} />
+      <ResponsiveImage
+        src={visual}
+        width={300}
+        alt="TanStack logo"
+        sizes="(min-width: 768px) 600px, 300px"
+      />
examples/react/with-responsive-image/vite.config.ts (2)

11-11: Support JPEG too in the include pattern.

Covers common .jpeg extensions.

-      include: /^[^?]+\.(?:jpg|png)\?.*responsive.*$/,
+      include: /^[^?]+\.(?:jpe?g|png)\?.*responsive.*$/,

10-13: Make LQIP type switchable (ThumbHash bug workaround).

Given the known ThumbHash placeholder update bug, allow opting into a different LQIP in demos via env.

Would you prefer this minimal tweak (keeps config object form)?

     setupPlugins({
       include: /^[^?]+\.(?:jpe?g|png)\?.*responsive.*$/,
-      lqip: { type: 'thumbhash' },
+      // VITE_LQIP_TYPE can be: 'thumbhash' | 'dominant-color' | 'blurhash' (if supported)
+      lqip: { type: (process.env.VITE_LQIP_TYPE as any) ?? 'thumbhash' },
     }),

If you’d like, I can flip this to use loadEnv for stricter typing.

examples/react/with-responsive-image/src/routes/__root.tsx (3)

18-22: Add alt (and lazy/decoding hints) to thumbnails.

Improves a11y and perf for the sidebar grid.

-        {Object.entries(getThumbsnails()).map(([imageId, image]) => (
+        {Object.entries(getThumbsnails()).map(([imageId, image]) => (
           <Link to="/$imageId" params={{ imageId }} key={imageId}>
-            <ResponsiveImage src={image} width={200}></ResponsiveImage>
+            <ResponsiveImage
+              src={image}
+              width={200}
+              alt={imageId}
+              loading="lazy"
+              decoding="async"
+            />
           </Link>
         ))}

33-33: Brand casing nit.

Use “TanStack Router”.

-            name: 'Tanstack Router',
+            name: 'TanStack Router',

8-8: Typo in helper name (optional alias).

Function is spelled getThumbsnails. Consider aliasing locally for readability.

-import { getThumbsnails } from '../images.ts'
+import { getThumbsnails as getThumbnails } from '../images'

And:

-{Object.entries(getThumbsnails()).map(
+{Object.entries(getThumbnails()).map(
examples/react/with-responsive-image/src/main.tsx (1)

9-9: Drop .ts extension for local import.

-import reportWebVitals from './reportWebVitals.ts'
+import reportWebVitals from './reportWebVitals'
examples/react/with-responsive-image/src/images.ts (3)

25-33: Add a correctly spelled alias for the exported helper

Avoid propagating the typo in public API while keeping current imports working.

Apply this diff:

 export function getThumbsnails(): Record<string, ImageData> {
   return Object.fromEntries(
     Object.entries(thumbnails).map(([imageId, module]) => [
       normalizeImageId(imageId),
       module.default,
     ]),
   )
 }
+
+// Alias with correct spelling (prefer importing this going forward)
+export const getThumbnails = getThumbsnails

37-39: Replace placeholder 404 payload

The { foo: 1 } looks like a leftover stub. Keep it clean/minimal for 404s.

Apply this diff:

-    throw notFound({ data: { foo: 1 } })
+    throw notFound()

7-11: Polish comment phrasing

Minor grammar tweak for clarity.

Apply this diff:

-    eager: true, // this is just generating image meta data, not need for lazy loading
+    eager: true, // this only generates image metadata; no need for lazy loading
@@
-    eager: true, // this is just generating image meta data, not need for lazy loading
+    eager: true, // this only generates image metadata; no need for lazy loading

Also applies to: 18-21

examples/react/with-responsive-image/package.json (3)

17-17: Move Vite router plugin to devDependencies

The router plugin is build-time only and shouldn’t ship in runtime deps.

Apply this diff:

   "dependencies": {
     "@responsive-image/core": "^2.1.0",
     "@responsive-image/react": "^1.1.2",
     "@tanstack/react-devtools": "^0.2.2",
     "@tanstack/react-router": "^1.131.32",
     "@tanstack/react-router-devtools": "^1.131.32",
-    "@tanstack/router-plugin": "^1.131.32",
     "react": "^19.0.0",
     "react-dom": "^19.0.0"
   },
   "devDependencies": {
+    "@tanstack/router-plugin": "^1.131.32",
     "@responsive-image/vite-plugin": "^2.0.0",
     "@testing-library/dom": "^10.4.0",
     "@testing-library/react": "^16.2.0",
     "@types/react": "^19.0.8",
     "@types/react-dom": "^19.0.3",
     "@vitejs/plugin-react": "^4.3.4",
     "jsdom": "^26.0.0",
     "typescript": "^5.7.2",
     "vite": "^7.1.3",
     "web-vitals": "^4.2.4"
   }

Also applies to: 21-32


5-10: Optional: trim or clarify scripts

“dev” and “start” are identical. You can drop one or make “start” run “vite preview” for production-like checks.

Example:

   "scripts": {
-    "dev": "vite --port 3000",
-    "start": "vite --port 3000",
+    "dev": "vite --port 3000",
+    "start": "vite preview",
     "build": "vite build && tsc",
     "serve": "vite preview"
   },

1-33: Optional: pin minimal Node engine

Helps avoid local env drift in examples.

Apply this diff:

 {
   "name": "with-responsive-image",
   "private": true,
   "type": "module",
+  "engines": {
+    "node": ">=18.18"
+  },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fec3509 and b014491.

⛔ Files ignored due to path filters (9)
  • examples/react/with-responsive-image/public/favicon.ico is excluded by !**/*.ico
  • examples/react/with-responsive-image/public/logo192.png is excluded by !**/*.png
  • examples/react/with-responsive-image/public/logo512.png is excluded by !**/*.png
  • examples/react/with-responsive-image/src/images/gallery/01.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/gallery/02.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/gallery/03.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/gallery/04.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/splash-dark.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • examples/react/with-responsive-image/.cta.json (1 hunks)
  • examples/react/with-responsive-image/.gitignore (1 hunks)
  • examples/react/with-responsive-image/README.md (1 hunks)
  • examples/react/with-responsive-image/index.html (1 hunks)
  • examples/react/with-responsive-image/package.json (1 hunks)
  • examples/react/with-responsive-image/public/manifest.json (1 hunks)
  • examples/react/with-responsive-image/public/robots.txt (1 hunks)
  • examples/react/with-responsive-image/src/images.ts (1 hunks)
  • examples/react/with-responsive-image/src/main.tsx (1 hunks)
  • examples/react/with-responsive-image/src/reportWebVitals.ts (1 hunks)
  • examples/react/with-responsive-image/src/routeTree.gen.ts (1 hunks)
  • examples/react/with-responsive-image/src/routes/$imageId.tsx (1 hunks)
  • examples/react/with-responsive-image/src/routes/__root.tsx (1 hunks)
  • examples/react/with-responsive-image/src/routes/app.css (1 hunks)
  • examples/react/with-responsive-image/src/routes/index.tsx (1 hunks)
  • examples/react/with-responsive-image/src/styles.css (1 hunks)
  • examples/react/with-responsive-image/tsconfig.json (1 hunks)
  • examples/react/with-responsive-image/vite.config.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
examples/react/with-responsive-image/src/routes/__root.tsx (2)
examples/react/with-responsive-image/src/images.ts (1)
  • getThumbsnails (25-32)
packages/react-router-devtools/src/TanStackRouterDevtoolsPanel.tsx (1)
  • TanStackRouterDevtoolsPanel (37-87)
examples/react/with-responsive-image/src/main.tsx (1)
e2e/react-router/js-only-file-based/src/main.jsx (2)
  • rootElement (15-15)
  • root (18-18)
examples/react/with-responsive-image/src/routes/index.tsx (2)
examples/react/with-responsive-image/src/routes/$imageId.tsx (1)
  • Route (5-7)
examples/react/with-responsive-image/src/routes/__root.tsx (1)
  • Route (10-12)
examples/react/with-responsive-image/src/routes/$imageId.tsx (3)
examples/react/with-responsive-image/src/routes/__root.tsx (1)
  • Route (10-12)
examples/react/with-responsive-image/src/routes/index.tsx (1)
  • Route (5-7)
examples/react/with-responsive-image/src/images.ts (1)
  • getImage (34-42)
🪛 LanguageTool
examples/react/with-responsive-image/public/robots.txt

[grammar] ~1-~1: There might be a mistake here.
Context: ...https://www.robotstxt.org/robotstxt.html User-agent: * Disallow:

(QB_NEW_EN)


[grammar] ~2-~2: There might be a mistake here.
Context: ...botstxt.org/robotstxt.html User-agent: * Disallow:

(QB_NEW_EN)

🪛 ESLint
examples/react/with-responsive-image/src/routes/__root.tsx

[error] 1-1: '@tanstack/react-router' imported multiple times.

(import/no-duplicates)


[error] 5-5: '@tanstack/react-router' imported multiple times.

(import/no-duplicates)

🔇 Additional comments (5)
examples/react/with-responsive-image/tsconfig.json (1)

16-23: Keep noUncheckedSideEffectImports
This option was introduced in TypeScript 5.6 and the project uses TS ^5.9.0, so it’s supported. (typescriptlang.org)

examples/react/with-responsive-image/index.html (1)

17-18: No action required — mount ID matches main.tsx
Verified that examples/react/with-responsive-image/src/main.tsx uses document.getElementById('app'), which matches the <div id="app"> in index.html.

examples/react/with-responsive-image/src/routes/__root.tsx (1)

3-3: Verify devtools component name casing.

I believe the export is TanStackDevtools (capital “S”). Please confirm and adjust import/usage if needed.

-import { TanstackDevtools } from '@tanstack/react-devtools'
+import { TanStackDevtools } from '@tanstack/react-devtools'

And

-      <TanstackDevtools
+      <TanStackDevtools
examples/react/with-responsive-image/src/main.tsx (1)

17-17: defaultStructuralSharing is a supported Router option
The defaultStructuralSharing boolean flag is valid on createRouter (defaults to false), so it can remain.

examples/react/with-responsive-image/src/routeTree.gen.ts (1)

1-10: Generated file LGTM

Marked as generated and excluded from type-checking; no review changes needed.

@simonihmig simonihmig force-pushed the with-responsive-image branch from 721c47c to 46d0321 Compare September 2, 2025 18:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
examples/react/with-responsive-image/src/routes/$imageId.tsx (2)

3-3: Avoid importing .ts extensions directly (portability).

Dropping the extension prevents requiring allowImportingTsExtensions and improves interop.

Apply:

-import { getImage } from '../images.ts'
+import { getImage } from '../images'

Please confirm tsconfig doesn’t rely on allowImportingTsExtensions: true.


7-7: Name nit: avoid generic Image component name.

Prevents confusion with DOM img or other image components.

Apply:

-export const Route = createFileRoute('/$imageId')({
-  loader: ({ params }) => getImage(params.imageId),
-  component: Image,
-})
+export const Route = createFileRoute('/$imageId')({
+  loader: ({ params }) => getImage(params.imageId),
+  component: ImagePage,
+})

-function Image() {
+function ImagePage() {

Also applies to: 10-14

examples/react/with-responsive-image/src/routes/__root.tsx (5)

1-1: Satisfy sort-imports by ordering members alphabetically.

Apply:

-import { Outlet, Link, createRootRoute } from '@tanstack/react-router'
+import { createRootRoute, Link, Outlet } from '@tanstack/react-router'

1-1: Avoid recomputing the thumbnails map on every render.

Memoize once per mount.

Apply:

+import { useMemo } from 'react'
@@
 function App() {
-  return (
+  const thumbnails = useMemo(() => getThumbsnails(), [])
+  return (
@@
-        {Object.entries(getThumbsnails()).map(([imageId, image]) => (
+        {Object.entries(thumbnails).map(([imageId, image]) => (

Also applies to: 12-17


17-19: Prefetch on intent to make image route feel instant.

Leverages TanStack Router’s preloading.

Apply:

-          <Link to="/$imageId" params={{ imageId }} key={imageId}>
+          <Link to="/$imageId" params={{ imageId }} key={imageId} preload="intent">

25-35: Gate devtools to development builds.

Prevents bundling devtools in production.

Apply:

-      <TanstackDevtools
-        config={{
-          position: 'bottom-left',
-        }}
-        plugins={[
-          {
-            name: 'Tanstack Router',
-            render: <TanStackRouterDevtoolsPanel />,
-          },
-        ]}
-      />
+      {import.meta.env.DEV && (
+        <TanstackDevtools
+          config={{ position: 'bottom-left' }}
+          plugins={[
+            {
+              name: 'TanStack Router',
+              render: <TanStackRouterDevtoolsPanel />,
+            },
+          ]}
+        />
+      )}

31-33: Brand nit: “TanStack” casing.

Use the canonical casing in the devtools plugin name.

Apply:

-            name: 'Tanstack Router',
+            name: 'TanStack Router',
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b014491 and 46d0321.

📒 Files selected for processing (3)
  • examples/react/with-responsive-image/README.md (1 hunks)
  • examples/react/with-responsive-image/src/routes/$imageId.tsx (1 hunks)
  • examples/react/with-responsive-image/src/routes/__root.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/react/with-responsive-image/README.md
🧰 Additional context used
🧬 Code graph analysis (2)
examples/react/with-responsive-image/src/routes/$imageId.tsx (2)
examples/react/with-responsive-image/src/routes/__root.tsx (1)
  • Route (8-10)
examples/react/with-responsive-image/src/images.ts (1)
  • getImage (34-42)
examples/react/with-responsive-image/src/routes/__root.tsx (2)
examples/react/with-responsive-image/src/images.ts (1)
  • getThumbsnails (25-32)
packages/react-router-devtools/src/TanStackRouterDevtoolsPanel.tsx (1)
  • TanStackRouterDevtoolsPanel (37-87)
🪛 ESLint
examples/react/with-responsive-image/src/routes/__root.tsx

[error] 1-1: Member 'Link' of the import declaration should be sorted alphabetically.

(sort-imports)

🔇 Additional comments (1)
examples/react/with-responsive-image/src/routes/$imageId.tsx (1)

5-7: Good move: fetch in a route loader.

Loader-based lookup avoids render-time throws and lets the router handle 404s. Looks solid.

<aside>
{Object.entries(getThumbsnails()).map(([imageId, image]) => (
<Link to="/$imageId" params={{ imageId }} key={imageId}>
<ResponsiveImage src={image} width={200}></ResponsiveImage>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add alt text to thumbnails and use a self-closing tag.

Improves accessibility and consistency.

Apply:

-            <ResponsiveImage src={image} width={200}></ResponsiveImage>
+            <ResponsiveImage
+              src={image}
+              width={200}
+              alt={image.alt || image.title || imageId}
+            />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<ResponsiveImage src={image} width={200}></ResponsiveImage>
<ResponsiveImage
src={image}
width={200}
alt={image.alt || image.title || imageId}
/>
🤖 Prompt for AI Agents
In examples/react/with-responsive-image/src/routes/__root.tsx around line 18,
the ResponsiveImage usage lacks an alt attribute and uses an explicit closing
tag; update the component to include a descriptive alt prop (e.g.,
alt="thumbnail" or a value derived from the image variable) and convert it to a
self-closing tag (<ResponsiveImage ... />) to improve accessibility and
consistency.

function Image() {
const image = Route.useLoaderData()

return <ResponsiveImage src={image} className="large" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add accessible alt text (and consider a remount key to work around the ThumbHash LQIP bug).

Provide meaningful alt text; optionally key by imageId to force a remount when switching images.

Apply:

 function Image() {
-  const image = Route.useLoaderData()
+  const image = Route.useLoaderData()
+  const { imageId } = Route.useParams()

-  return <ResponsiveImage src={image} className="large" />
+  return (
+    <ResponsiveImage
+      key={imageId}
+      src={image}
+      className="large"
+      alt={image.alt ?? image.title ?? imageId}
+    />
+  )
 }

Also applies to: 12-12

🤖 Prompt for AI Agents
In examples/react/with-responsive-image/src/routes/$imageId.tsx around lines 13
(and also line 12), the ResponsiveImage is rendered without accessible alt text
and without a remount key to avoid the ThumbHash LQIP bug; update the component
props to include a meaningful alt (e.g., derived from imageId or image metadata)
and add key={imageId} so the component remounts when switching images, ensuring
accessibility and working around the LQIP bug.

<main>
<Outlet />
</main>
<TanstackDevtools
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice using the new devtools!

@brenelz
Copy link
Contributor

brenelz commented Sep 5, 2025

I think this is a good addition. I think a lot of people want some kind of image solution kind of like Next's Image

Copy link

nx-cloud bot commented Sep 9, 2025

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 46d0321

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 6m 15s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 51s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-09 19:43:50 UTC

Copy link

pkg-pr-new bot commented Sep 9, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5070

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5070

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5070

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5070

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5070

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5070

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5070

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5070

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5070

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@5070

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5070

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5070

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5070

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5070

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5070

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5070

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5070

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5070

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5070

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5070

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5070

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5070

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5070

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5070

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5070

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@5070

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5070

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5070

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5070

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5070

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@5070

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@5070

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@5070

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5070

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5070

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5070

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5070

commit: 46d0321

@simonihmig simonihmig force-pushed the with-responsive-image branch from 46d0321 to 2c449aa Compare September 9, 2025 20:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
examples/react/with-responsive-image/src/routes/__root.tsx (1)

16-19: Add alt text and use a self-closing tag for ResponsiveImage.

-            <ResponsiveImage src={image} width={200}></ResponsiveImage>
+            <ResponsiveImage
+              src={image}
+              width={200}
+              alt={image.alt ?? image.title ?? imageId}
+            />
🧹 Nitpick comments (9)
examples/react/with-responsive-image/.gitignore (4)

1-4: Add common Vite cache and package-manager log ignores.

Keeps the example repo clean during development.

 node_modules
 .DS_Store
 dist
 dist-ssr
+/.vite
+npm-debug.log*
+yarn-debug.log*
+pnpm-debug.log*
+Thumbs.db

5-7: Harden .env ignores but keep example env files.

Prevents accidental secret commits while allowing checked-in templates.

-*.local
+*.local
+.env.local
+.env.*.local
+.env.*.preview
+.env.*.production
 count.txt
-.env
+.env
+!.env.example

6-6: Question: Why ignore count.txt?

Looks app-specific and accidental. Prefer removing the file (if unused) rather than tracking it in .gitignore.

-count.txt

9-9: Clarify the purpose of .tanstack ignore.

If the monorepo tooling generates this directory locally for examples, keep it; otherwise remove to avoid overbroad ignores.

-.tanstack
examples/react/with-responsive-image/src/global.d.ts (1)

1-6: Narrow the ambient module pattern to match query imports precisely.

Use *?responsive (and optionally *?responsive&*) to avoid overmatching modules that merely end with “responsive”.

-declare module '*responsive' {
+declare module '*?responsive' {
   import type { ImageData } from '@responsive-image/core'

   const value: ImageData
   export default value
 }
+
+declare module '*?responsive&*' {
+  import type { ImageData } from '@responsive-image/core'
+
+  const value: ImageData
+  export default value
+}
examples/react/with-responsive-image/src/routes/__root.tsx (4)

1-1: Satisfy sort-imports by ordering named imports alphabetically.

-import { Outlet, Link, createRootRoute } from '@tanstack/react-router'
+import { createRootRoute, Link, Outlet } from '@tanstack/react-router'

6-6: Prefer extensionless import for TS/Vite consistency.

-import { getThumbsnails } from '../images.ts'
+import { getThumbsnails } from '../images'

12-20: Avoid recomputing the thumbnails map on every render.

Cache the result once; tiny win, keeps renders cheaper in examples.

+import { useMemo } from 'react'
@@
 function App() {
+  const thumbs = useMemo(() => getThumbsnails(), [])
   return (
@@
-        {Object.entries(getThumbsnails()).map(([imageId, image]) => (
+        {Object.entries(thumbs).map(([imageId, image]) => (

31-31: Brand consistency: “TanStack Router”.

-            name: 'Tanstack Router',
+            name: 'TanStack Router',
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46d0321 and 2c449aa.

⛔ Files ignored due to path filters (9)
  • examples/react/with-responsive-image/public/favicon.ico is excluded by !**/*.ico
  • examples/react/with-responsive-image/public/logo192.png is excluded by !**/*.png
  • examples/react/with-responsive-image/public/logo512.png is excluded by !**/*.png
  • examples/react/with-responsive-image/src/images/gallery/01.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/gallery/02.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/gallery/03.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/gallery/04.jpg is excluded by !**/*.jpg
  • examples/react/with-responsive-image/src/images/splash-dark.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • examples/react/with-responsive-image/.cta.json (1 hunks)
  • examples/react/with-responsive-image/.gitignore (1 hunks)
  • examples/react/with-responsive-image/README.md (1 hunks)
  • examples/react/with-responsive-image/index.html (1 hunks)
  • examples/react/with-responsive-image/package.json (1 hunks)
  • examples/react/with-responsive-image/public/manifest.json (1 hunks)
  • examples/react/with-responsive-image/public/robots.txt (1 hunks)
  • examples/react/with-responsive-image/src/global.d.ts (1 hunks)
  • examples/react/with-responsive-image/src/images.ts (1 hunks)
  • examples/react/with-responsive-image/src/main.tsx (1 hunks)
  • examples/react/with-responsive-image/src/reportWebVitals.ts (1 hunks)
  • examples/react/with-responsive-image/src/routeTree.gen.ts (1 hunks)
  • examples/react/with-responsive-image/src/routes/$imageId.tsx (1 hunks)
  • examples/react/with-responsive-image/src/routes/__root.tsx (1 hunks)
  • examples/react/with-responsive-image/src/routes/app.css (1 hunks)
  • examples/react/with-responsive-image/src/routes/index.tsx (1 hunks)
  • examples/react/with-responsive-image/src/styles.css (1 hunks)
  • examples/react/with-responsive-image/tsconfig.json (1 hunks)
  • examples/react/with-responsive-image/vite.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (16)
  • examples/react/with-responsive-image/README.md
  • examples/react/with-responsive-image/src/routes/app.css
  • examples/react/with-responsive-image/src/routes/index.tsx
  • examples/react/with-responsive-image/public/robots.txt
  • examples/react/with-responsive-image/package.json
  • examples/react/with-responsive-image/src/styles.css
  • examples/react/with-responsive-image/tsconfig.json
  • examples/react/with-responsive-image/vite.config.ts
  • examples/react/with-responsive-image/src/main.tsx
  • examples/react/with-responsive-image/index.html
  • examples/react/with-responsive-image/src/reportWebVitals.ts
  • examples/react/with-responsive-image/src/routeTree.gen.ts
  • examples/react/with-responsive-image/src/routes/$imageId.tsx
  • examples/react/with-responsive-image/src/images.ts
  • examples/react/with-responsive-image/public/manifest.json
  • examples/react/with-responsive-image/.cta.json
🧰 Additional context used
🧬 Code graph analysis (1)
examples/react/with-responsive-image/src/routes/__root.tsx (4)
examples/react/with-responsive-image/src/routes/$imageId.tsx (1)
  • Route (5-8)
examples/react/with-responsive-image/src/routes/index.tsx (1)
  • Route (5-7)
examples/react/with-responsive-image/src/images.ts (1)
  • getThumbsnails (25-32)
packages/react-router-devtools/src/TanStackRouterDevtoolsPanel.tsx (1)
  • TanStackRouterDevtoolsPanel (37-87)
🪛 ESLint
examples/react/with-responsive-image/src/routes/__root.tsx

[error] 1-1: Member 'Link' of the import declaration should be sorted alphabetically.

(sort-imports)

🔇 Additional comments (1)
examples/react/with-responsive-image/.gitignore (1)

8-8: .nitro seems unrelated to this Vite React example.

Nitro is Nuxt-specific. Unless a tool in this example generates .nitro, drop it.

-.nitro

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants