Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@

**Learning:** In Next.js/React applications, when grouping items (like schedules or talks) into a `Map` where the values are arrays, using the array spread operator `[...existing, item]` inside a loop (like `forEach` or `map`) causes amortized O(N^2) memory allocations and unnecessary Garbage Collection overhead.
**Action:** Always use `.push()` on the existing array reference if the data structure permits local mutation. For strict ESLint configurations enforcing `no-restricted-syntax`, extract the existing array, push to it, and handle the fallback elegantly (`if (!existing) { map.set(key, [item]); } else { existing.push(item); }`).

## 2024-05-19 - Parallelize generateStaticParams fetching

**Learning:** In Next.js applications, sequential data fetching (using `for...of` loops) inside build-critical functions like `generateStaticParams` significantly slows down static page generation. The bottleneck is amplified when fetching data across multiple parameters (e.g., archived years).
**Action:** Replace sequential `for...of` loops with parallel execution using `Promise.all(array.map(...))` to fetch data concurrently. Preserve per-item `try/catch` blocks inside the map callback to prevent a single item's failure from prematurely failing the entire batch, returning an empty array `[]` as a fallback, and then use `.flat()` on the resulting nested array structure.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Update the action description to reflect the use of strict mode for build-critical data fetching, ensuring that any failures correctly fail the build to prevent deploying incomplete pages.

Suggested change
**Action:** Replace sequential `for...of` loops with parallel execution using `Promise.all(array.map(...))` to fetch data concurrently. Preserve per-item `try/catch` blocks inside the map callback to prevent a single item's failure from prematurely failing the entire batch, returning an empty array `[]` as a fallback, and then use `.flat()` on the resulting nested array structure.
**Action:** Replace sequential for...of loops with parallel execution using Promise.all(array.map(...)) to fetch data concurrently. Use the { strict: true } option in data fetching functions to ensure that any data fetching failure during the build process correctly fails the build, preventing the deployment of incomplete pages, and then use .flat() on the resulting nested array structure.

22 changes: 11 additions & 11 deletions app/[year]/speakers/[speakerId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ interface SpeakerDetailProps {

export async function generateStaticParams() {
const years = getArchivedEditions();
const params = [];

for (const year of years) {
try {
const speakers = await getSpeakers(year);
for (const speaker of speakers) {
params.push({ year, speakerId: speaker.id });
const paramsArrays = await Promise.all(
years.map(async (year) => {
try {
const speakers = await getSpeakers(year);
return speakers.map((speaker) => ({ year, speakerId: speaker.id }));
} catch (error) {
console.warn(`Failed to fetch speakers for year ${year}:`, error);
return [];
}
} catch (error) {
console.warn(`Failed to fetch speakers for year ${year}:`, error);
}
}
})
);
Comment on lines +24 to +34
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

According to the repository's general rules, data fetching functions used during the build process should include a 'strict' mode that throws an error on failure to ensure that data fetching problems cause the build to fail, preventing the deployment of incomplete pages. Currently, getSpeakers is called without { strict: true } and the error is caught and swallowed, returning []. This would allow the build to succeed even if fetching speakers fails, resulting in incomplete pages being deployed. We should pass { strict: true } and let the error propagate.

  const paramsArrays = await Promise.all(
    years.map(async (year) => {
      const speakers = await getSpeakers(year, { strict: true });
      return speakers.map((speaker) => ({ year, speakerId: speaker.id }));
    })
  );
References
  1. Data fetching functions used during the build process (e.g., for sitemap generation) should include a 'strict' mode that throws an error on failure. This ensures that data fetching problems cause the build to fail, preventing the deployment of incomplete pages.


return params;
return paramsArrays.flat();
}

export async function generateMetadata({ params }: SpeakerDetailProps): Promise<Metadata> {
Expand Down
39 changes: 21 additions & 18 deletions app/[year]/tags/[tag]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,30 @@ export const dynamicParams = false;

export async function generateStaticParams() {
const years = getArchivedEditions();
const params = [];

for (const year of years) {
try {
const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);
const allTags = new Set<string>();

for (const talk of allTalks) {
getTagsFromTalk(talk).forEach((tag) => allTags.add(tag));
}

for (const tag of allTags) {
params.push({ year, tag: tag.replaceAll(" ", "-").toLowerCase() });
const paramsArrays = await Promise.all(
years.map(async (year) => {
try {
const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);
const allTags = new Set<string>();

for (const talk of allTalks) {
getTagsFromTalk(talk).forEach((tag) => allTags.add(tag));
}

return Array.from(allTags).map((tag) => ({
year,
tag: tag.replaceAll(" ", "-").toLowerCase(),
}));
} catch (error) {
console.warn(`Failed to fetch talks for year ${year}:`, error);
return [];
}
} catch (error) {
console.warn(`Failed to fetch talks for year ${year}:`, error);
}
}
})
);
Comment on lines +22 to +42
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

According to the repository's general rules, data fetching functions used during the build process should include a 'strict' mode that throws an error on failure to ensure that data fetching problems cause the build to fail, preventing the deployment of incomplete pages. Currently, getTalks is called without { strict: true } and the error is caught and swallowed, returning []. This would allow the build to succeed even if fetching talks fails, resulting in incomplete pages being deployed. We should pass { strict: true } and let the error propagate.

  const paramsArrays = await Promise.all(
    years.map(async (year) => {
      const sessionGroups = await getTalks(year, { strict: true });
      const allTalks = sessionGroups.flatMap((group) => group.sessions);
      const allTags = new Set<string>();

      for (const talk of allTalks) {
        getTagsFromTalk(talk).forEach((tag) => allTags.add(tag));
      }

      return Array.from(allTags).map((tag) => ({
        year,
        tag: tag.replaceAll(" ", "-").toLowerCase(),
      }));
    })
  );
References
  1. Data fetching functions used during the build process (e.g., for sitemap generation) should include a 'strict' mode that throws an error on failure. This ensures that data fetching problems cause the build to fail, preventing the deployment of incomplete pages.


return params;
return paramsArrays.flat();
}

export async function generateMetadata({ params }: Readonly<TagPageProps>): Promise<Metadata> {
Expand Down
26 changes: 13 additions & 13 deletions app/[year]/talks/[talkId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ interface TalkDetailProps {

export async function generateStaticParams() {
const years = getArchivedEditions();
const params = [];

for (const year of years) {
try {
const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);
for (const talk of allTalks) {
params.push({ year, talkId: talk.id });

const paramsArrays = await Promise.all(
years.map(async (year) => {
try {
const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);
return allTalks.map((talk) => ({ year, talkId: talk.id }));
} catch (error) {
console.warn(`Failed to fetch talks for year ${year}:`, error);
return [];
}
} catch (error) {
console.warn(`Failed to fetch talks for year ${year}:`, error);
}
}
})
);
Comment on lines +34 to +45
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

According to the repository's general rules, data fetching functions used during the build process should include a 'strict' mode that throws an error on failure to ensure that data fetching problems cause the build to fail, preventing the deployment of incomplete pages. Currently, getTalks is called without { strict: true } and the error is caught and swallowed, returning []. This would allow the build to succeed even if fetching talks fails, resulting in incomplete pages being deployed. We should pass { strict: true } and let the error propagate.

  const paramsArrays = await Promise.all(
    years.map(async (year) => {
      const sessionGroups = await getTalks(year, { strict: true });
      const allTalks = sessionGroups.flatMap((group) => group.sessions);
      return allTalks.map((talk) => ({ year, talkId: talk.id }));
    })
  );
References
  1. Data fetching functions used during the build process (e.g., for sitemap generation) should include a 'strict' mode that throws an error on failure. This ensures that data fetching problems cause the build to fail, preventing the deployment of incomplete pages.


return params;
return paramsArrays.flat();
}

export async function generateMetadata({ params }: TalkDetailProps): Promise<Metadata> {
Expand Down
Loading