Skip to content

feat: [performance improvement] - #365

Open
anyulled wants to merge 1 commit into
mainfrom
bolt-optimize-tags-search-406554294882876090
Open

feat: [performance improvement]#365
anyulled wants to merge 1 commit into
mainfrom
bolt-optimize-tags-search-406554294882876090

Conversation

@anyulled

Copy link
Copy Markdown
Owner

💡 What:
Replaced the allTalks.flatMap(getTagsFromTalk).find(...) logic in the tags page (app/[year]/tags/[tag]/page.tsx and app/2026/tags/[tag]/page.tsx) with a more efficient allTalks.find(talk => getTagsFromTalk(talk).some(...)) approach. Additionally, cached the decodedTag.toLowerCase() result outside the loop to prevent repeated string allocations. Also added a journal entry to .jules/bolt.md documenting this learning.

🎯 Why:
The previous approach flatMapped all tags across all talks into a large intermediate array and traversed it entirely to find a single match. This creates excessive memory allocation and garbage collection overhead, particularly during heavy operations like generating static parameters or handling large arrays. The new logic short-circuits execution the moment a match is found and eliminates the intermediate array entirely.

📊 Impact:
Reduces memory allocation overhead significantly by avoiding intermediate flattened arrays, and decreases runtime traversal time by utilizing early breakouts (some()). Lowers overhead on the garbage collector.

🔬 Measurement:
Run Next.js build (npm run build) and monitor the execution time of generateStaticParams() for tag routes, and view memory consumption traces during the build phase.


PR created automatically by Jules for task 406554294882876090 started by @anyulled

Replaces O(N*M) flat map and find traversal with short-circuiting logic using .some(), caching the lowercase target string to prevent redundant re-evaluations.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Optimize tag route lookup to avoid flatMap allocations

✨ Enhancement 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Short-circuit tag lookup by scanning talks and their tags without flattening all tags.
• Cache normalized tag string to avoid repeated lowercasing and allocations.
• Document the performance lesson in the Jules engineering journal.
Diagram

graph TD
  A["Tag route page.tsx"] --> B["getTalks(year)"] --> C["allTalks (sessions)"] --> D["matchedTalk = find(talk => some(tagMatch))"] --> E["displayTag"] --> F["filteredTalks (some(tagMatch))"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Precompute a tag→displayTag index once per year
  • ➕ Avoids repeated tag normalization across metadata + page render + static generation.
  • ➕ Can reduce overall build time if many tag pages are generated.
  • ➖ Requires shared caching/lifecycle decisions (build vs runtime) and extra code complexity.
  • ➖ Must ensure index stays consistent with getTagsFromTalk normalization rules.
2. Extract shared helper for tag normalization + lookup
  • ➕ Eliminates duplicated logic between app/[year]/... and app/2026/... routes.
  • ➕ Reduces risk of future drift in matching behavior.
  • ➖ Small abstraction overhead; may be overkill for two call sites.
  • ➖ Still recomputes normalization per talk unless paired with indexing.

Recommendation: The chosen find+some approach is a good low-risk improvement that removes the largest allocation hotspot (flatMap) and preserves behavior. If tag-route build time remains significant, the next step would be extracting a shared helper and/or building a per-year tag index reused by both metadata and page rendering.

Files changed (3) +27 / -10

Enhancement (2) +22 / -10
page.tsxShort-circuit tag display lookup and cache normalized tag for 2026 route +11/-5

Short-circuit tag display lookup and cache normalized tag for 2026 route

• Replaces allTalks.flatMap(getTagsFromTalk).find(...) with a short-circuiting search: find a talk whose tags contain the normalized target. Caches decodedTag.toLowerCase() and reuses it for both displayTag derivation and filteredTalks matching.

app/2026/tags/[tag]/page.tsx

page.tsxShort-circuit tag display lookup and cache normalized tag for generic year route +11/-5

Short-circuit tag display lookup and cache normalized tag for generic year route

• Mirrors the 2026 optimization in the parameterized year route: compute targetTag once, find the first talk with a matching tag via some(), then derive displayTag without flattening all tags. Reuses targetTag in the filteredTalks predicate to avoid repeated lowercasing.

app/[year]/tags/[tag]/page.tsx

Documentation (1) +5 / -0
bolt.mdAdd journal entry on avoiding flatMap().find() for nested searches +5/-0

Add journal entry on avoiding flatMap().find() for nested searches

• Adds a dated note describing why flatMap().find() can create large intermediate arrays and GC pressure. Documents a recommended alternative using find()+some() (or explicit loops) to short-circuit without allocations.

.jules/bolt.md

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 300 rules
✅ Skills: 18 invoked
  gsap-timeline
  gsap-performance
  gsap-react
  gsap-frameworks
  gsap-utils
  next-cache-components
  gsap-core
  seo
  gsap-scrolltrigger
  gsap-plugins
  vercel-composition-patterns
  typescript-advanced-types
  nodejs-best-practices
  nodejs-backend-patterns
  accessibility
  supabase-postgres-best-practices
  next-best-practices
  vercel-react-best-practices

Grey Divider


Remediation recommended

1. Redundant tag re-parsing 🐞 Bug ➹ Performance
Description
The new matchedTalk/displayTag logic parses the matched talk’s tags twice (some(...) during
matchedTalk search, then again with find(...) for displayTag). This duplicates split/trim work
(and the page render parses tags again during filtering), reducing the net allocation savings from
the optimization.
Code

app/[year]/tags/[tag]/page.tsx[R50-54]

+  const targetTag = decodedTag.toLowerCase();
+  const matchedTalk = allTalks.find((talk) => getTagsFromTalk(talk).some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag));
+  const displayTag = matchedTalk
+    ? (getTagsFromTalk(matchedTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag) ?? decodedTag.replaceAll("-", " "))
+    : decodedTag.replaceAll("-", " ");
Relevance

●●● Strong

Team previously accepted hoisting invariant computations/caching to avoid repeated work (PR #9, #11,
#316).

PR-#9
PR-#11
PR-#316

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The tag pages call getTagsFromTalk() once to locate a matching talk, then call it again on the
same talk to find the matching tag string for display, and the page render filters talks by calling
getTagsFromTalk() again. Since getTagsFromTalk() performs split()/trim() each invocation,
this is measurable redundant work introduced by the refactor.

app/[year]/tags/[tag]/page.tsx[50-54]
app/[year]/tags/[tag]/page.tsx[70-80]
app/2026/tags/[tag]/page.tsx[43-48]
hooks/useTalks.ts[91-100]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`displayTag` determination re-calls `getTagsFromTalk()` after already identifying a match via `getTagsFromTalk(talk).some(...)`, causing redundant parsing/allocations.

## Issue Context
`getTagsFromTalk()` splits and trims the raw tag string on every call, so repeated calls re-allocate arrays/strings.

## Fix Focus Areas
- app/[year]/tags/[tag]/page.tsx[50-54]
- app/[year]/tags/[tag]/page.tsx[70-74]
- app/2026/tags/[tag]/page.tsx[43-47]
- app/2026/tags/[tag]/page.tsx[64-68]

## Suggested fix
Refactor to compute the matching *display tag* in the same pass that finds the match, so the matched talk’s tags are only parsed once.

Example approach:
- Use a small `for...of` search that returns the matching tag string (e.g., `matchedDisplayTag`) instead of `matchedTalk`.
- Or, while filtering talks, set `displayTag` the first time a match is found (and reuse that value for metadata/title).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +50 to +54
const targetTag = decodedTag.toLowerCase();
const matchedTalk = allTalks.find((talk) => getTagsFromTalk(talk).some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag));
const displayTag = matchedTalk
? (getTagsFromTalk(matchedTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag) ?? decodedTag.replaceAll("-", " "))
: decodedTag.replaceAll("-", " ");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Redundant tag re-parsing 🐞 Bug ➹ Performance

The new matchedTalk/displayTag logic parses the matched talk’s tags twice (some(...) during
matchedTalk search, then again with find(...) for displayTag). This duplicates split/trim work
(and the page render parses tags again during filtering), reducing the net allocation savings from
the optimization.
Agent Prompt
## Issue description
`displayTag` determination re-calls `getTagsFromTalk()` after already identifying a match via `getTagsFromTalk(talk).some(...)`, causing redundant parsing/allocations.

## Issue Context
`getTagsFromTalk()` splits and trims the raw tag string on every call, so repeated calls re-allocate arrays/strings.

## Fix Focus Areas
- app/[year]/tags/[tag]/page.tsx[50-54]
- app/[year]/tags/[tag]/page.tsx[70-74]
- app/2026/tags/[tag]/page.tsx[43-47]
- app/2026/tags/[tag]/page.tsx[64-68]

## Suggested fix
Refactor to compute the matching *display tag* in the same pass that finds the match, so the matched talk’s tags are only parsed once.

Example approach:
- Use a small `for...of` search that returns the matching tag string (e.g., `matchedDisplayTag`) instead of `matchedTalk`.
- Or, while filtering talks, set `displayTag` the first time a match is found (and reuse that value for metadata/title).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant