From 0f59b2386f9a7b526b39d4a2f25147dc61fbab02 Mon Sep 17 00:00:00 2001 From: anyulled <100741+anyulled@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:30:51 +0000 Subject: [PATCH 1/2] feat: [performance improvement] avoid flatmap in tags pages Refactored tag matching and filtering in app/[year]/tags/[tag]/page.tsx and app/2026/tags/[tag]/page.tsx to avoid chained .flatMap().find() and .flatMap().filter() operations, reducing memory allocations and multiple array traversals. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ app/2026/tags/[tag]/page.tsx | 43 +++++++++++++++++++++++++++------- app/[year]/tags/[tag]/page.tsx | 43 +++++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index af3158d3..fd492814 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -7,3 +7,7 @@ **Learning:** Using `Object.entries(obj).find(([key]) => key === target)` creates O(N) array allocations for the entries and traverses them linearly just to do a simple property lookup. This adds unnecessary memory allocation overhead and Garbage Collection. **Action:** Use direct property lookup instead: `Object.prototype.hasOwnProperty.call(obj, target) ? obj[target as keyof typeof obj] : undefined`. This maintains O(1) performance while satisfying `security/detect-object-injection` linting rules. +## 2024-07-20 - Avoid chained flatMap().find() and flatMap().filter() on grouped data structures + +**Learning:** When dealing with nested or grouped data structures (like `SessionGroup[]` where each group contains `Session[]`), chaining `.flatMap()` to flatten the arrays followed by `.find()` or `.filter()` causes the engine to allocate an entirely new flattened O(N) array in memory before performing the search. This introduces significant memory allocation overhead and multiple linear traversals. +**Action:** Instead of `flatMap().find()`, use nested loops or `groupedData.some(group => group.items.some(condition))` to allow for O(1) early bailout matching without pre-allocating a flattened array. For `.filter()`, use nested `.forEach()` loops and manually `.push()` matching items into a state array to perform the filtering in a single memory-efficient pass. diff --git a/app/2026/tags/[tag]/page.tsx b/app/2026/tags/[tag]/page.tsx index 5c9a6ebc..cfaa5410 100644 --- a/app/2026/tags/[tag]/page.tsx +++ b/app/2026/tags/[tag]/page.tsx @@ -3,6 +3,7 @@ import TalkCard from "@/components/layout/TalkCard"; import CTASection from "@/components/sections/CTASection"; import { getEditionConfig } from "@/config/editions"; import { getTagsFromTalk, getTalks } from "@/hooks/useTalks"; +import { Talk } from "@/hooks/types"; import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; @@ -39,9 +40,21 @@ export async function generateMetadata({ params }: { params: Promise<{ tag: stri const decodedTag = decodeURIComponent(tag); const sessionGroups = await getTalks(year); - const allTalks = sessionGroups.flatMap((group) => group.sessions); - const displayTag = - allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " "); + const targetTagLower = decodedTag.toLowerCase(); + + const state = { matchedTag: undefined as string | undefined }; + sessionGroups.some((group) => + group.sessions.some((talk) => { + const found = getTagsFromTalk(talk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTagLower); + if (found) { + state.matchedTag = found; + return true; + } + return false; + }) + ); + + const displayTag = state.matchedTag ?? decodedTag.replaceAll("-", " "); return { title: `Talks tagged "${displayTag}" - DevBcn ${year}`, @@ -56,17 +69,29 @@ export default async function Page({ params }: { params: Promise<{ tag: string } const eventData = getEditionConfig(year); const sessionGroups = await getTalks(year); - const allTalks = sessionGroups.flatMap((group) => group.sessions); - const displayTag = - allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " "); + const targetTagLower = decodedTag.toLowerCase(); - const filteredTalks = allTalks.filter((talk) => { - const talkTags = getTagsFromTalk(talk); + const state = { + filteredTalks: [] as Talk[], + displayTag: undefined as string | undefined, + }; - return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()); + sessionGroups.forEach((group) => { + group.sessions.forEach((talk) => { + const matchedTag = getTagsFromTalk(talk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTagLower); + if (matchedTag) { + if (!state.displayTag) { + state.displayTag = matchedTag; + } + state.filteredTalks.push(talk); + } + }); }); + const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " "); + const filteredTalks = state.filteredTalks; + if (filteredTalks.length === 0) { notFound(); } diff --git a/app/[year]/tags/[tag]/page.tsx b/app/[year]/tags/[tag]/page.tsx index 35c74f61..9cbf269e 100644 --- a/app/[year]/tags/[tag]/page.tsx +++ b/app/[year]/tags/[tag]/page.tsx @@ -3,6 +3,7 @@ import TalkCard from "@/components/layout/TalkCard"; import CTASection from "@/components/sections/CTASection"; import { getArchivedEditions, getEditionConfig } from "@/config/editions"; import { getTagsFromTalk, getTalks } from "@/hooks/useTalks"; +import { Talk } from "@/hooks/types"; import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; @@ -46,9 +47,21 @@ export async function generateMetadata({ params }: Readonly): Prom const decodedTag = decodeURIComponent(tag); const sessionGroups = await getTalks(year); - const allTalks = sessionGroups.flatMap((group) => group.sessions); - const displayTag = - allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " "); + const targetTagLower = decodedTag.toLowerCase(); + + const state = { matchedTag: undefined as string | undefined }; + sessionGroups.some((group) => + group.sessions.some((talk) => { + const found = getTagsFromTalk(talk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTagLower); + if (found) { + state.matchedTag = found; + return true; + } + return false; + }) + ); + + const displayTag = state.matchedTag ?? decodedTag.replaceAll("-", " "); return { title: `Talks tagged "${displayTag}" - DevBcn ${year}`, @@ -62,17 +75,29 @@ export default async function TagPage({ params }: Readonly) { const eventData = getEditionConfig(year); const sessionGroups = await getTalks(year); - const allTalks = sessionGroups.flatMap((group) => group.sessions); - const displayTag = - allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " "); + const targetTagLower = decodedTag.toLowerCase(); - const filteredTalks = allTalks.filter((talk) => { - const talkTags = getTagsFromTalk(talk); + const state = { + filteredTalks: [] as Talk[], + displayTag: undefined as string | undefined, + }; - return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()); + sessionGroups.forEach((group) => { + group.sessions.forEach((talk) => { + const matchedTag = getTagsFromTalk(talk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTagLower); + if (matchedTag) { + if (!state.displayTag) { + state.displayTag = matchedTag; + } + state.filteredTalks.push(talk); + } + }); }); + const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " "); + const filteredTalks = state.filteredTalks; + if (filteredTalks.length === 0) { notFound(); } From f6bad137e8630a927733e9906663723826f05e93 Mon Sep 17 00:00:00 2001 From: anyulled <100741+anyulled@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:38:33 +0000 Subject: [PATCH 2/2] feat: [performance improvement] avoid flatmap in tags pages Refactored tag matching and filtering in app/[year]/tags/[tag]/page.tsx and app/2026/tags/[tag]/page.tsx to avoid chained .flatMap().find() and .flatMap().filter() operations, reducing memory allocations and multiple array traversals. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .jules/bolt.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.jules/bolt.md b/.jules/bolt.md index fd492814..44fb1b46 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -7,6 +7,7 @@ **Learning:** Using `Object.entries(obj).find(([key]) => key === target)` creates O(N) array allocations for the entries and traverses them linearly just to do a simple property lookup. This adds unnecessary memory allocation overhead and Garbage Collection. **Action:** Use direct property lookup instead: `Object.prototype.hasOwnProperty.call(obj, target) ? obj[target as keyof typeof obj] : undefined`. This maintains O(1) performance while satisfying `security/detect-object-injection` linting rules. + ## 2024-07-20 - Avoid chained flatMap().find() and flatMap().filter() on grouped data structures **Learning:** When dealing with nested or grouped data structures (like `SessionGroup[]` where each group contains `Session[]`), chaining `.flatMap()` to flatten the arrays followed by `.find()` or `.filter()` causes the engine to allocate an entirely new flattened O(N) array in memory before performing the search. This introduces significant memory allocation overhead and multiple linear traversals.