diff --git a/.jules/bolt.md b/.jules/bolt.md index af3158d3..2c35cd84 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -7,3 +7,8 @@ **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. + +## 2026-10-25 - Avoid flatMap().find() in large arrays + +**Learning:** When searching for an item based on properties of nested arrays, using `array.flatMap(mapFn).find(findFn)` creates large intermediate arrays and unnecessarily traverses all elements, causing memory bloat and garbage collection overhead, especially in data-heavy operations like `generateStaticParams`. +**Action:** Use nested `for...of` loops, or `.find()` with `.some()` internally (e.g. `array.find(item => item.children.some(condition))`) to immutably locate the parent element without full flat mapping, then extract the required nested value. diff --git a/app/2026/tags/[tag]/page.tsx b/app/2026/tags/[tag]/page.tsx index 5c9a6ebc..8f99d982 100644 --- a/app/2026/tags/[tag]/page.tsx +++ b/app/2026/tags/[tag]/page.tsx @@ -40,8 +40,11 @@ export async function generateMetadata({ params }: { params: Promise<{ tag: stri 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 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("-", " "); return { title: `Talks tagged "${displayTag}" - DevBcn ${year}`, @@ -58,13 +61,16 @@ export default async function Page({ params }: { params: Promise<{ tag: string } 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 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("-", " "); const filteredTalks = allTalks.filter((talk) => { const talkTags = getTagsFromTalk(talk); - return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()); + return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag); }); if (filteredTalks.length === 0) { diff --git a/app/[year]/tags/[tag]/page.tsx b/app/[year]/tags/[tag]/page.tsx index 35c74f61..32f91104 100644 --- a/app/[year]/tags/[tag]/page.tsx +++ b/app/[year]/tags/[tag]/page.tsx @@ -47,8 +47,11 @@ export async function generateMetadata({ params }: Readonly): Prom 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 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("-", " "); return { title: `Talks tagged "${displayTag}" - DevBcn ${year}`, @@ -64,13 +67,16 @@ export default async function TagPage({ params }: Readonly) { 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 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("-", " "); const filteredTalks = allTalks.filter((talk) => { const talkTags = getTagsFromTalk(talk); - return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()); + return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag); }); if (filteredTalks.length === 0) {