⚡ Bolt: Optimize project detail page data fetching#26
⚡ Bolt: Optimize project detail page data fetching#26aicoder2009 wants to merge 2 commits intomainfrom
Conversation
- Fetch `project` details and `lists` within the project concurrently via `Promise.all()` to reduce initial blocking sequence on render. - Lazy load `allLists` to only fetch when the user triggers the "Add List" UI, trimming unnecessary initial network load. Co-authored-by: aicoder2009 <[email protected]>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Optimizes the /projects/[id] detail page’s client-side data fetching to reduce time-to-interactive by parallelizing independent requests and deferring non-critical data until the user initiates an action.
Changes:
- Fetch project details and project lists concurrently via
Promise.all()insrc/app/projects/[id]/page.tsx. - Lazily fetch “all user lists” (
/api/lists) only when the user opens the “Add List” UI. - Add a Jules “Bolt” learning note documenting the performance approach.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/app/projects/[id]/page.tsx | Parallelizes project + project-lists fetch; defers all-lists fetch until user opens add-list UI. |
| evaluate_page.py | Adds a Python helper script that checks for a substring in the page file. |
| .jules/bolt.md | Documents the “concurrent + lazy fetch” approach as a learning/action item. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| This project has no lists yet. | ||
| </p> | ||
| <WikiButton variant="primary" onClick={() => setShowAddList(true)}> | ||
| <WikiButton variant="primary" onClick={() => { setShowAddList(true); if (!hasFetchedAllLists) fetchAllUserLists(); }}> |
There was a problem hiding this comment.
This inline click handler duplicates the “open add list + lazy fetch all lists” behavior implemented in handleToggleAddList, which increases the chance of the two code paths drifting (and makes it harder to add loading/error UI for the add-list panel). Consider reusing the shared handler or extracting a dedicated handleOpenAddList helper used by both buttons.
| <WikiButton variant="primary" onClick={() => { setShowAddList(true); if (!hasFetchedAllLists) fetchAllUserLists(); }}> | |
| <WikiButton | |
| variant="primary" | |
| onClick={() => { | |
| if (!showAddList) { | |
| handleToggleAddList(); | |
| } | |
| }} | |
| > |
| import re | ||
|
|
||
| with open("src/app/projects/[id]/page.tsx", "r") as f: | ||
| content = f.read() | ||
|
|
||
| if "fetchProjectAndLists" not in content: | ||
| print("Function not found") | ||
| else: | ||
| print("Function found") |
There was a problem hiding this comment.
This Python script appears to be a one-off verification helper (it just checks for a substring in a TSX file) and introduces an otherwise-unused Python artifact into a Node/Next.js repo (there are no npm scripts or other Python utilities). Recommend removing it from the PR, or moving it under scripts/ and rewriting it in TS/JS (or wiring it into CI) if it’s intended to be kept. Also, re is imported but unused.
| import re | |
| with open("src/app/projects/[id]/page.tsx", "r") as f: | |
| content = f.read() | |
| if "fetchProjectAndLists" not in content: | |
| print("Function not found") | |
| else: | |
| print("Function found") | |
| import argparse | |
| import sys | |
| def main() -> int: | |
| parser = argparse.ArgumentParser( | |
| description="Verify that a source file contains a required substring." | |
| ) | |
| parser.add_argument( | |
| "file_path", | |
| nargs="?", | |
| default="src/app/projects/[id]/page.tsx", | |
| help="Path to the file to inspect.", | |
| ) | |
| parser.add_argument( | |
| "expected_text", | |
| nargs="?", | |
| default="fetchProjectAndLists", | |
| help="Substring that must be present in the file.", | |
| ) | |
| args = parser.parse_args() | |
| with open(args.file_path, "r", encoding="utf-8") as f: | |
| content = f.read() | |
| if args.expected_text not in content: | |
| print("Function not found") | |
| return 1 | |
| print("Function found") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) |
| if (allListsResult.success) { | ||
| setAllLists(allListsResult.data); | ||
| setHasFetchedAllLists(true); | ||
| } | ||
| } catch (err) { | ||
| console.error("Error fetching project:", err); | ||
| setError("Failed to load project"); | ||
| } finally { | ||
| setIsLoading(false); | ||
| console.error("Error fetching all user lists:", err); | ||
| } |
There was a problem hiding this comment.
fetchAllUserLists swallows failures (only logs to console). If /api/lists fails or returns non-success, the “Add existing list” section will silently stay empty with no user feedback. Consider setting error (or a dedicated allListsError / loading state for the add-list panel) when the request fails or when allListsResult.success is false so the UI can explain what happened.
💡 What: The data fetching logic in
src/app/projects/[id]/page.tsxwas optimized to run parallel independent fetches, and defer fetching data that isn't immediately necessary for the UI.🎯 Why: The project detail page was sequentially fetching project data, then lists data, then all lists data. This blocked the render thread longer than necessary.
📊 Impact: This cuts Time-to-Interactive (TTI) since the major project data fetches are executed concurrently. It also removes one network request (
/api/lists) from the critical path entirely, only loading it if the user wants to append an existing list.🔬 Measurement: Verify by using the "Network" tab in devtools on
/projects/:idto see the concurrent timing of/api/projects/:idand/api/projects/:id/lists. Ensure/api/listsis only requested upon clicking "Add List".PR created automatically by Jules for task 3229720793011527760 started by @aicoder2009