A retro-styled Pokémon encyclopedia that demonstrates Svelte 5's new experimental await expressions functionality. Built with SvelteKit, TypeScript, and Tailwind CSS, featuring a nostalgic 90's Game Boy aesthetic.
🚀 Live Demo: https://svelte-await-pokedex.vercel.app/
# Clone and navigate to the project
cd sveltekit-test-await
# Install dependencies
pnpm install
# Start the development server
pnpm dev
# Visit http://localhost:5174
pnpm dev # Start development server
pnpm build # Build for production
pnpm preview # Preview production build
pnpm test # Run unit tests
pnpm test:e2e # Run end-to-end tests
pnpm lint # Run linting
pnpm format # Format code with Prettier
This app serves as a comprehensive exploration of Svelte 5's new await expressions feature, demonstrating various patterns and use cases through a real-world Pokémon API integration.
The experimental await functionality is enabled in svelte.config.js:
export default {
compilerOptions: {
experimental: {
async: true // Enable await expressions
}
}
};
<svelte:boundary>All await expressions must be wrapped in a <svelte:boundary> with a pending snippet:
<svelte:boundary>
{#snippet pending()}
<div class="loading-state">
<!-- Unified loading UI for all await expressions -->
<div class="pokeball-loader"></div>
<p>Loading Pokémon data...</p>
</div>
{/snippet}
<!-- All your await expressions go here -->
</svelte:boundary>
{#await} BlocksStill supported and useful for complex loading states
{#await fetchPokemon(pokemonId)}
<div class="custom-loader">Loading Pokémon...</div>
{:then pokemon}
<div class="pokemon-card">
<h2>{pokemon.name}</h2>
<img src={pokemon.sprites.front_default} alt={pokemon.name} />
</div>
{:catch error}
<div class="error-state">Error: {error.message}</div>
{/await}
Location in app: Main Pokémon data display (src/routes/+page.svelte:138)
Multiple API calls executed simultaneously
{#await Promise.all([fetchPokemon(pokemonId), calculateStats(pokemonId)])}
<p>Calculating battle statistics...</p>
{:then [pokemon, statsInfo]}
<div class="stats-display">
<h3>{pokemon.name} Battle Stats</h3>
<p>Total Power: {statsInfo.total}</p>
<p>Average: {statsInfo.average}</p>
</div>
{/await}
Location in app: Stats analysis section (src/routes/+page.svelte:246)
Dependent API calls where one result feeds into another
{#await fetchPokemonSpecies(pokemonId)}
<p>Loading species data...</p>
{:then species}
{#await fetchEvolutionChain(species.evolution_chain.url)}
<p>Processing evolution chain...</p>
{:then evolutionData}
{@const chain = parseEvolutionChain(evolutionData.chain)}
<div class="evolution-display">
{#each chain as pokemon, i (pokemon)}
<span>{pokemon}</span>
{#if i < chain.length - 1}→{/if}
{/each}
</div>
{/await}
{/await}
Location in app: Evolution chain section (src/routes/+page.svelte:302)
Automatically re-execute when dependencies change
When pokemonId changes:
pending snippetThe app demonstrates await expressions with real HTTP requests to the PokéAPI:
// Fetch main Pokémon data
async function fetchPokemon(id: number) {
const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`);
if (!response.ok) throw new Error('Pokémon not found');
return response.json();
}
// Fetch species information for evolution data
async function fetchPokemonSpecies(id: number) {
const response = await fetch(`https://pokeapi.co/api/v2/pokemon-species/${id}`);
if (!response.ok) throw new Error('Species data not found');
return response.json();
}
// Calculate derived stats asynchronously
async function calculateStats(pokemonId: number) {
const pokemon = await fetchPokemon(pokemonId);
const total = pokemon.stats.reduce((sum, stat) => sum + stat.base_stat, 0);
return { total, average: Math.round(total / pokemon.stats.length) };
}
Each await expression includes proper error handling:
{:catch error}
<div class="error-display">
<p>⚠️ ERROR: {error.message}</p>
<p>System malfunction detected</p>
</div>
{/await}
src/
├── routes/
│ └── +page.svelte # Main Pokédex component
├── app.html # HTML template
├── app.css # Global styles (Tailwind imports)
└── lib/ # Shared utilities (if any)
interface EvolutionChain {
species: { name: string };
evolves_to: EvolutionChain[];
}
interface PokemonStat {
base_stat: number;
stat: { name: string };
}
Promise.all()pending snippet handles all awaitsfetch() APIThis is a learning/demo project, but contributions are welcome:
pnpm lint && pnpm testMIT License - feel free to use this code for learning and experimentation!
Happy coding, and gotta catch 'em all! 🎮✨