Static Paths
Static Paths
Section titled “Static Paths”Static Paths helpers eliminate getStaticPaths() boilerplate for common patterns like episodes and guests pages. These functions fetch data from Sanity and generate Astro static paths automatically.
Import
Section titled “Import”import { getStaticPathsForEpisodes, getStaticPathsForGuests} from '@rejected-media/podcast-framework-core';Why Use Static Paths Helpers?
Section titled “Why Use Static Paths Helpers?”Without Helpers (Boilerplate)
Section titled “Without Helpers (Boilerplate)”---import { getEpisodes } from '@rejected-media/podcast-framework-core';
export async function getStaticPaths() { const episodes = await getEpisodes();
return episodes.map((episode) => ({ params: { slug: episode.slug.current }, props: { episode }, }));}
const { episode } = Astro.props;---With Helpers (One Line)
Section titled “With Helpers (One Line)”---import { getStaticPathsForEpisodes } from '@rejected-media/podcast-framework-core';
export const getStaticPaths = getStaticPathsForEpisodes;
const { episode } = Astro.props;---Result: Same functionality, 90% less code!
Functions
Section titled “Functions”getStaticPathsForEpisodes()
Section titled “getStaticPathsForEpisodes()”Generate static paths for all episodes.
Signature:
function getStaticPathsForEpisodes(): Promise<Array<{ params: { slug: string }; props: { episode: Episode };}>>Returns: Array of path objects for Astro
Complete Example:
---import { getStaticPathsForEpisodes, formatDate } from '@rejected-media/podcast-framework-core';import BaseLayout from '@rejected-media/podcast-framework-core/layouts/BaseLayout.astro';
export const getStaticPaths = getStaticPathsForEpisodes;
const { episode } = Astro.props;---
<BaseLayout title={episode.title}> <article> <h1>Episode {episode.episodeNumber}: {episode.title}</h1> <p>Published: {formatDate(episode.publishDate)}</p> <p>{episode.description}</p> </article></BaseLayout>What It Generates:
For episodes with slugs: "ep-1", "ep-2", "ep-3", generates:
[ { params: { slug: 'ep-1' }, props: { episode: { title: '...', episodeNumber: 1, ... } } }, { params: { slug: 'ep-2' }, props: { episode: { title: '...', episodeNumber: 2, ... } } }, { params: { slug: 'ep-3' }, props: { episode: { title: '...', episodeNumber: 3, ... } } }]Generated Routes:
/episodes/ep-1 → Episode 1 page/episodes/ep-2 → Episode 2 page/episodes/ep-3 → Episode 3 pagegetStaticPathsForGuests()
Section titled “getStaticPathsForGuests()”Generate static paths for all guests.
Signature:
function getStaticPathsForGuests(): Promise<Array<{ params: { slug: string }; props: { guest: Guest };}>>Returns: Array of path objects for Astro
Complete Example:
---import { getStaticPathsForGuests } from '@rejected-media/podcast-framework-core';import BaseLayout from '@rejected-media/podcast-framework-core/layouts/BaseLayout.astro';
export const getStaticPaths = getStaticPathsForGuests;
const { guest } = Astro.props;---
<BaseLayout title={guest.name}> <article> <img src={guest.photo?.url} alt={guest.name} /> <h1>{guest.name}</h1> <p>{guest.bio}</p>
<!-- Guest's episodes --> <h2>Episodes featuring {guest.name}</h2> {guest.episodes?.map(episode => ( <a href={`/episodes/${episode.slug.current}`}> Episode {episode.episodeNumber}: {episode.title} </a> ))} </article></BaseLayout>Generated Routes:
/guest/vitalik-buterin → Guest profile page/guest/danny-ryan → Guest profile page/guest/patrick-mccorry → Guest profile pageHow It Works
Section titled “How It Works”1. Fetch Data
Section titled “1. Fetch Data”// getStaticPathsForEpisodesconst episodes = await getEpisodes();2. Map to Path Objects
Section titled “2. Map to Path Objects”return episodes.map((episode) => ({ params: { slug: episode.slug.current }, props: { episode },}));3. Astro Generates Pages
Section titled “3. Astro Generates Pages”Astro uses params to generate routes and passes props to the page component.
TypeScript Support
Section titled “TypeScript Support”Full type safety for props:
---import type { Episode } from '@rejected-media/podcast-framework-core';import { getStaticPathsForEpisodes } from '@rejected-media/podcast-framework-core';
export const getStaticPaths = getStaticPathsForEpisodes;
// TypeScript knows episode typeconst { episode }: { episode: Episode } = Astro.props;
// Autocomplete and type checking workconst title = episode.title; // ✅ TypeScript knows this existsconst invalid = episode.xyz; // ❌ TypeScript error---Custom Static Paths
Section titled “Custom Static Paths”Example 1: Filtered Episodes
Section titled “Example 1: Filtered Episodes”---import { getEpisodes } from '@rejected-media/podcast-framework-core';import type { Episode } from '@rejected-media/podcast-framework-core';
export async function getStaticPaths() { const episodes = await getEpisodes();
// Only featured episodes const featured = episodes.filter(ep => ep.featured);
return featured.map((episode) => ({ params: { slug: episode.slug.current }, props: { episode }, }));}
const { episode }: { episode: Episode } = Astro.props;---
<h1>Featured: {episode.title}</h1>Example 2: Paginated Episodes
Section titled “Example 2: Paginated Episodes”---import { getEpisodes } from '@rejected-media/podcast-framework-core';
export async function getStaticPaths() { const episodes = await getEpisodes(); const pageSize = 10; const pageCount = Math.ceil(episodes.length / pageSize);
return Array.from({ length: pageCount }, (_, i) => { const page = i + 1; const start = i * pageSize; const end = start + pageSize;
return { params: { page: page.toString() }, props: { episodes: episodes.slice(start, end), currentPage: page, totalPages: pageCount } }; });}
const { episodes, currentPage, totalPages } = Astro.props;---
<h1>Episodes - Page {currentPage} of {totalPages}</h1>{episodes.map(ep => <EpisodeCard episode={ep} />)}Example 3: Episodes by Year
Section titled “Example 3: Episodes by Year”---import { getEpisodes } from '@rejected-media/podcast-framework-core';
export async function getStaticPaths() { const episodes = await getEpisodes();
// Group by year const byYear = episodes.reduce((acc, ep) => { const year = new Date(ep.publishDate).getFullYear(); if (!acc[year]) acc[year] = []; acc[year].push(ep); return acc; }, {} as Record<number, Episode[]>);
return Object.entries(byYear).map(([year, eps]) => ({ params: { year }, props: { episodes: eps, year: parseInt(year) } }));}
const { episodes, year } = Astro.props;---
<h1>{year} Episodes ({episodes.length})</h1>Performance
Section titled “Performance”Static paths are generated at build time only:
Build Process:1. Run getStaticPaths() → Fetch from Sanity2. Generate HTML pages → Create /episodes/ep-1.html, etc.3. Deploy static files → Instant load, no runtime queries
Runtime (Production):- No database queries- No API calls- Instant page load (static HTML)Build Performance:
69 episodes:- getStaticPathsForEpisodes: ~200ms (1 API call, cached)- Page generation: ~1.5s (69 HTML files)- Total build: ~20s (full site)Troubleshooting
Section titled “Troubleshooting””No routes generated”
Section titled “”No routes generated””Check that Sanity has content:
# List episodes in Sanitynpx sanity documents list episodeIf empty, add episodes in Sanity Studio.
”Slug is undefined”
Section titled “”Slug is undefined””Ensure episodes have valid slugs:
// In Sanity{ _type: 'episode', slug: { _type: 'slug', current: 'episode-1' // ← Must be defined }}Build hangs during static path generation
Section titled “Build hangs during static path generation”Check for infinite loops or very slow queries:
# Add timeoutASTRO_TELEMETRY_DISABLED=1 timeout 60 npm run buildDebug:
export async function getStaticPaths() { console.log('Starting getStaticPaths...'); const episodes = await getEpisodes(); console.log(`Got ${episodes.length} episodes`); // ... rest of function}Duplicate slugs error
Section titled “Duplicate slugs error”Sanity allows duplicate slugs - add validation:
export async function getStaticPaths() { const episodes = await getEpisodes();
// Check for duplicates const slugs = episodes.map(ep => ep.slug.current); const duplicates = slugs.filter((slug, index) => slugs.indexOf(slug) !== index);
if (duplicates.length > 0) { console.error('Duplicate slugs found:', duplicates); throw new Error('Fix duplicate slugs in Sanity before building'); }
return episodes.map((episode) => ({ params: { slug: episode.slug.current }, props: { episode }, }));}Related
Section titled “Related”- Sanity Helpers - Fetch data for static paths
- Project Structure - File-based routing
- Dynamic Routes - Advanced routing patterns
Next Steps
Section titled “Next Steps”- Hosting Adapter - Platform abstraction
- Server Services - Backend services
- Deployment - Deploy static site