perf: stop shipping full blog post content to every client bundle#1025
Conversation
…tsForLibrary and update RouteComponent to use loader data
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
tanstack-com | 6eff051 | Commit Preview URL Branch Preview URL |
Jul 02 2026, 06:01 AM |
📝 WalkthroughWalkthroughBlog formatting utilities (author list formatting, date formatting/parsing, library lookup, distinct authors) are extracted into a new ChangesBlog utilities refactor and related-posts server fetching
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant StackCategoryPage as stack.$category route
participant FetchRelatedPosts as fetchRelatedPostsForLibraries
participant BlogUtils as getPostsForLibrary
participant CategoryArticle
StackCategoryPage->>FetchRelatedPosts: request related posts for category library ids
FetchRelatedPosts->>BlogUtils: getPostsForLibrary per library id
BlogUtils-->>FetchRelatedPosts: published posts
FetchRelatedPosts-->>StackCategoryPage: sliced RelatedPost[] (max 4)
StackCategoryPage->>CategoryArticle: render with slug and relatedPosts
CategoryArticle->>CategoryArticle: reconstructRelatedPosts(libraries, relatedPosts)
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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/utils/blog-format.ts`:
- Around line 60-70: The author sorting in getDistinctAuthors uses localeCompare
without a fixed locale, so the order can vary between SSR and hydration. Update
the sort callback in getDistinctAuthors to use the same pinned locale approach
as formatAuthors by passing a fixed locale like en-US to localeCompare, keeping
author ordering deterministic across runtimes.
🪄 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: c301cd08-24bb-4c3f-a95b-48525cd291fd
📒 Files selected for processing (12)
src/components/BlogCard.tsxsrc/components/RecentPostsWidget.tsxsrc/components/home/HomeSocialProofSection.tsxsrc/components/stack/CategoryArticle.tsxsrc/routes/_library/$libraryId/$version.docs.blog.tsxsrc/routes/blog.$.tsxsrc/routes/blog.index.tsxsrc/routes/rss[.]xml.tssrc/routes/stack.$category.tsxsrc/utils/blog-format.tssrc/utils/blog.functions.tssrc/utils/blog.ts
| export function getDistinctAuthors( | ||
| posts: ReadonlyArray<{ authors: string[] }>, | ||
| ): string[] { | ||
| const authors = new Set<string>() | ||
| for (const post of posts) { | ||
| for (const author of post.authors) { | ||
| authors.add(author) | ||
| } | ||
| } | ||
| return [...authors].sort((a, b) => a.localeCompare(b)) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Pin locale for deterministic sort order.
localeCompare without an explicit locale depends on the runtime's default locale, which can differ between server (SSR) and client (hydration), causing non-deterministic author ordering and potential hydration mismatches. formatAuthors in this same file already pins locale ('en-US') for this reason — apply the same here.
🌐 Proposed fix
- return [...authors].sort((a, b) => a.localeCompare(b))
+ return [...authors].sort((a, b) => a.localeCompare(b, 'en-US'))📝 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.
| export function getDistinctAuthors( | |
| posts: ReadonlyArray<{ authors: string[] }>, | |
| ): string[] { | |
| const authors = new Set<string>() | |
| for (const post of posts) { | |
| for (const author of post.authors) { | |
| authors.add(author) | |
| } | |
| } | |
| return [...authors].sort((a, b) => a.localeCompare(b)) | |
| } | |
| export function getDistinctAuthors( | |
| posts: ReadonlyArray<{ authors: string[] }>, | |
| ): string[] { | |
| const authors = new Set<string>() | |
| for (const post of posts) { | |
| for (const author of post.authors) { | |
| authors.add(author) | |
| } | |
| } | |
| return [...authors].sort((a, b) => a.localeCompare(b, 'en-US')) | |
| } |
🤖 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/utils/blog-format.ts` around lines 60 - 70, The author sorting in
getDistinctAuthors uses localeCompare without a fixed locale, so the order can
vary between SSR and hydration. Update the sort callback in getDistinctAuthors
to use the same pinned locale approach as formatAuthors by passing a fixed
locale like en-US to localeCompare, keeping author ordering deterministic across
runtimes.
Problem
src/utils/blog.tsimportedallPostsfromcontent-collectionsat module top level. That generated module inlines the full markdown body of all 56 blog posts. Two components (CategoryArticlefor/stack/*pages, and the per-library/docs/blogroute) called blog-data functions directly during render with no server boundary, so Rollup hoisted the whole thing into the shared entry chunk — referenced by ~190 of ~200 client chunks, i.e. almost every page on the site.Measured before this change:
allPostsarray literal alone: 650KB raw / ~211KB gzip (47% of the entry chunk), shipped to every visitor on every pageFix
src/utils/blog.tsinto pure formatters (blog-format.ts, nocontent-collectionsimport) and data functions that still readallPosts(blog.ts). No behavior change, no leak severed yet.fetchRelatedPostsForLibraries, acreateServerFnfor/stack/$categorythat replicates the original client-sideflatMap(...).slice(0, 4)logic server-side, preserving exact post order/cutoff.CategoryArticlenow reconstructs{post, lib}pairs from loader data + the already-in-memorylibrariesarray instead of callinggetPostsForLibraryin render.fetchPostsForLibrary, a wider 7-fieldcreateServerFn(matchingblog.index.tsx's existingfetchFrontMattersshape) for/docs/blog, which needsauthors,headerImage, andlibraryin addition to slug/title/published/excerpt. Added a route loader withstaleTime: Infinity(matchingblog.index.tsxprecedent).Result (measured via fresh
pnpm build)dist/client/(was previously present); it now lives only indist/server/assets/blog-*.js(651KB, server-only, never shipped to the browser)Risk
Low. No UI/design changes — same posts, same order, same badges on every affected page. The only behavior change is where the data is computed (server loader vs. client render), which is standard TanStack Start loader/server-fn usage already used elsewhere in this codebase (
blog.index.tsx).Summary by CodeRabbit
New Features
Bug Fixes