Skip to content

feat: add tkdodo past query and router articles to blog feed - #1000

Merged
KevinVandy merged 5 commits into
mainfrom
add-tk-dodo-tanstack-blogs
Aug 3, 2026
Merged

feat: add tkdodo past query and router articles to blog feed#1000
KevinVandy merged 5 commits into
mainfrom
add-tk-dodo-tanstack-blogs

Conversation

@KevinVandy

@KevinVandy KevinVandy commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Blog listings now include external articles alongside internal posts.
    • External articles display “Read on…” links that open securely in a new tab.
    • Added blog search by keyword and author, including library-specific filtering.
    • Recent posts and blog cards now consistently support external content.
    • Improved author name normalization and duplicate handling.
  • Bug Fixes
    • Empty search results now clearly indicate active search terms and authors.
    • Blog post ordering and library filtering are more consistent.
  • Performance
    • Improved caching for blog listing pages and data requests.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The blog system now aggregates internal and external posts, normalizes authors, supports library and text filtering, applies shared caching, and renders external posts with secure new-tab links.

Changes

External Blog Posts Integration

Layer / File(s) Summary
BlogCardPost and author normalization
src/utils/blog.ts
Adds the shared card-post type, author normalization, conversion, sorting, and library filtering utilities.
AtProto standard-site fetching
src/utils/external-blog-posts.server.ts
Fetches configured external posts, infers libraries, maps records, applies caching, and aggregates results.
Merged blog server endpoints
src/utils/blog.functions.ts
Merges internal and external posts and adds index and library-specific loaders.
Route loaders and blog filtering
src/routes/blog.index.tsx, src/routes/_library/...
Uses the new loaders, normalized author filters, text search, cache headers, and expanded empty states.
External card links and search input
src/components/BlogCard.tsx, src/components/RecentPostsWidget.tsx, src/components/ds/ui/BlogPostCard.tsx, src/components/BlogSearchFilter.tsx
Renders external posts as secure anchors and adds the controlled search component.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BlogRoute
  participant BlogServerFunctions
  participant ExternalBlogPosts
  participant StandardSite
  participant BlogCard

  BlogRoute->>BlogServerFunctions: load merged blog posts
  BlogServerFunctions->>ExternalBlogPosts: fetch external posts
  ExternalBlogPosts->>StandardSite: request paginated records
  StandardSite-->>ExternalBlogPosts: return standard-site records
  ExternalBlogPosts-->>BlogServerFunctions: return BlogCardPost[]
  BlogServerFunctions-->>BlogRoute: return sorted posts
  BlogRoute->>BlogCard: render each post
  BlogCard-->>BlogRoute: use external anchor or internal link
Loading

Possibly related PRs

Suggested reviewers: abeuty

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding TkDodo Query and Router articles to the blog feed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-tk-dodo-tanstack-blogs

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
scripts/scrape-tkdodo-blog-images.ts (1)

277-283: ⚡ Quick win

Keep the batch running when one post fetch fails.

A single network/parser error currently aborts the whole run. Wrap each iteration in try/catch so remaining posts still produce mappings.

Suggested fix
   for (const item of items) {
-    const entry = await scrapePostImage(item)
-
-    if (entry) {
-      entries.push(entry)
-    }
+    try {
+      const entry = await scrapePostImage(item)
+      if (entry) {
+        entries.push(entry)
+      }
+    } catch (error) {
+      console.warn(`[skip] ${getExternalPostSlug(item)}: failed to scrape`, error)
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/scrape-tkdodo-blog-images.ts` around lines 277 - 283, The loop
iterating over items does not handle errors from the scrapePostImage function
call, causing any network or parser error to abort the entire batch. Wrap the
scrapePostImage function call and the entry push logic inside a try/catch block
within the for loop. In the catch block, log the error with context (such as the
current item being processed) but allow the loop to continue processing the
remaining items instead of crashing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/external-blog-posts.server.ts`:
- Around line 191-214: The externalUrl assignment uses feedItem.link directly
without validating the URL scheme, which is a security risk. Before the return
statement that creates the post object (after the getExternalPostSlug call), add
validation to ensure feedItem.link uses a safe scheme (http: or https:). If the
URL does not match these schemes, return an empty array to drop the invalid
item. This validation should be done by checking the URL scheme before passing
feedItem.link to addSearchParams.

---

Nitpick comments:
In `@scripts/scrape-tkdodo-blog-images.ts`:
- Around line 277-283: The loop iterating over items does not handle errors from
the scrapePostImage function call, causing any network or parser error to abort
the entire batch. Wrap the scrapePostImage function call and the entry push
logic inside a try/catch block within the for loop. In the catch block, log the
error with context (such as the current item being processed) but allow the loop
to continue processing the remaining items instead of crashing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 281cd017-bfee-4b7e-9642-eea304dee620

📥 Commits

Reviewing files that changed from the base of the PR and between e4cc876 and e54fcc0.

⛔ Files ignored due to path filters (36)
  • public/blog-assets/tkdodosblog/automatic-query-invalidation-after-mutations.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/breaking-react-querys-api-on-purpose.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/concurrent-optimistic-updates-in-react-query.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/context-inheritance-in-tan-stack-router.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/creating-query-abstractions.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/effective-react-query-keys.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/how-infinite-queries-work.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/inside-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/leveraging-the-query-function-context.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/mastering-mutations-in-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/offline-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/placeholder-and-initial-data-in-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/practical-react-query.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/react-query-and-forms.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-and-react-context.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-and-type-script.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-api-design-lessons-learned.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/react-query-as-a-state-manager.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-data-transformations.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-error-handling.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-fa-qs.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-meets-react-router.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-render-optimizations.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/react-query-selectors-supercharged.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/react-query-the-bad-parts.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/seeding-the-query-cache.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/status-checks-in-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/tan-stack-router-and-query.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/testing-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/the-beauty-of-tan-stack-router.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/the-query-options-api.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/thinking-in-react-query.png is excluded by !**/*.png
  • public/blog-assets/tkdodosblog/type-safe-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/using-web-sockets-with-react-query.jpeg is excluded by !**/*.jpeg
  • public/blog-assets/tkdodosblog/why-you-want-react-query.jpg is excluded by !**/*.jpg
  • public/blog-assets/tkdodosblog/you-might-not-need-react-query.jpeg is excluded by !**/*.jpeg
📒 Files selected for processing (11)
  • public/blog-assets/tkdodosblog/tkdodosblog.webp
  • scripts/scrape-tkdodo-blog-images.ts
  • src/components/BlogCard.tsx
  • src/components/RecentPostsWidget.tsx
  • src/components/home/HomeSocialProofSection.tsx
  • src/routes/_library/$libraryId/$version.docs.blog.tsx
  • src/routes/blog.index.tsx
  • src/utils/blog.functions.ts
  • src/utils/blog.ts
  • src/utils/external-blog-post-images.generated.ts
  • src/utils/external-blog-posts.server.ts

Comment thread src/utils/external-blog-posts.server.ts Outdated
…blogs

# Conflicts:
#	src/components/BlogCard.tsx
#	src/components/home/HomeSocialProofSection.tsx
#	src/routes/_library/$libraryId/$version.docs.blog.tsx
#	src/routes/blog.index.tsx
#	src/utils/blog.functions.ts
#	src/utils/blog.ts
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
tanstack-com 522c614 Commit Preview URL

Branch Preview URL
Aug 03 2026, 12:56 PM

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ds/ui/BlogPostCard.tsx`:
- Around line 58-63: Update standardSiteRecordToBlogCardPost and the canonical
URL production flow around buildStandardSiteCanonicalUrl to accept external URLs
only when their scheme is http or https; reject or omit non-HTTP(S) canonical
URLs before assigning externalUrl, so BlogPostCard never receives an unsafe href
while valid links remain unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ab9b6a34-a5c9-479b-9328-6570e266e88d

📥 Commits

Reviewing files that changed from the base of the PR and between e6023c8 and 522c614.

📒 Files selected for processing (4)
  • src/components/BlogCard.tsx
  • src/components/BlogSearchFilter.tsx
  • src/components/RecentPostsWidget.tsx
  • src/components/ds/ui/BlogPostCard.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/BlogSearchFilter.tsx
  • src/components/RecentPostsWidget.tsx
  • src/components/BlogCard.tsx

Comment on lines +58 to +63
if (post.externalUrl) {
return (
<a
href={post.externalUrl}
target="_blank"
rel="noopener noreferrer"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="src/utils/external-blog-posts.server.ts"
test -f "$file"

rg -n -C 10 \
  'canonicalUrl|buildStandardSiteCanonicalUrl|externalUrl|addSearchParams|protocol' \
  "$file"

Repository: TanStack/tanstack.com

Length of output: 4101


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- BlogPostCard outline ---\n'
ast-grep outline src/components/ds/ui/BlogPostCard.tsx || true

printf '\n--- BlogPostCard relevant lines ---\n'
sed -n '1,110p' src/components/ds/ui/BlogPostCard.tsx | cat -n

printf '\n--- external-blog-posts relevant lines ---\n'
sed -n '180,340p' src/utils/external-blog-posts.server.ts | cat -n

printf '\n--- BlogCardPost type usages/declaration ---\n'
rg -n -C 4 'type BlogCardPost|interface BlogCardPost|externalUrl:' src

Repository: TanStack/tanstack.com

Length of output: 250


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- BlogPostCard outline ---'
ast-grep outline src/components/ds/ui/BlogPostCard.tsx || true

printf '%s\n' ''
printf '%s\n' '--- BlogPostCard relevant lines ---'
sed -n '1,110p' src/components/ds/ui/BlogPostCard.tsx | cat -n

printf '%s\n' ''
printf '%s\n' '--- external-blog-posts relevant lines ---'
sed -n '180,340p' src/utils/external-blog-posts.server.ts | cat -n

printf '%s\n' ''
printf '%s\n' '--- BlogCardPost type usages/declaration ---'
rg -n -C 4 'type BlogCardPost|interface BlogCardPost|externalUrl:' src

Repository: TanStack/tanstack.com

Length of output: 12635


Validate the URL scheme before rendering external links.

buildStandardSiteCanonicalUrl() accepts document.canonicalUrl without limiting it to http: or https:, and standardSiteRecordToBlogCardPost() stores that value as externalUrl. BlogPostCard then assigns it directly to href. Reject non-HTTP(S) canonical URLs in the producer so the unsafe scheme cannot reach React.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ds/ui/BlogPostCard.tsx` around lines 58 - 63, Update
standardSiteRecordToBlogCardPost and the canonical URL production flow around
buildStandardSiteCanonicalUrl to accept external URLs only when their scheme is
http or https; reject or omit non-HTTP(S) canonical URLs before assigning
externalUrl, so BlogPostCard never receives an unsafe href while valid links
remain unchanged.

Source: MCP tools

@KevinVandy
KevinVandy merged commit bf00919 into main Aug 3, 2026
7 checks passed
@KevinVandy
KevinVandy deleted the add-tk-dodo-tanstack-blogs branch August 3, 2026 14:34
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