
astro
by yacosta738
My Personal Blog and Portfolio ๐
SKILL.md
name: astro description: > Astro framework patterns and best practices for content-focused sites. Trigger: When working with .astro files, content collections, or Astro routing. allowed-tools: Read, Edit, Write, Glob, Grep, Bash
Astro Framework Skill
Conventions for building content-focused, high-performance websites with Astro.
When to Use
- Creating or modifying
.astrocomponents - Working with content collections (blog, articles, resume)
- Configuring Astro routing and layouts
- Optimizing performance with island architecture
- Integrating Vue components as islands
Critical Patterns
1. Island Architecture - Server First
ALWAYS minimize client-side JavaScript. Astro ships zero JS by default.
Compare these patterns: Static vs Interactive
Static component โ No JavaScript shipped to the client:
---
import Header from '../components/Header.astro';
---
<Header title="Welcome" />
Interactive island โ JavaScript loaded only for this component (uses client:visible):
---
import Counter from '../components/Counter.vue';
---
<Counter client:visible />
2. Hydration Directives
| Directive | When to Use |
|---|---|
client:load | Critical interactivity needed immediately |
client:idle | Non-critical, can wait for browser idle |
client:visible | Below the fold, hydrate on scroll |
client:media="(max-width: 768px)" | Mobile-only interactivity |
client:only="vue" | No SSR, client-only rendering (see note) |
Default choice: client:visible unless there's a reason otherwise.
[!WARNING]
client:onlytrade-offs Components usingclient:onlyskip server-side rendering entirely, which increases the client JS payload and can harm SEO since no HTML is rendered initially. Use only for:
- Third-party widgets that cannot render on the server
- Complex client-only UI (e.g., canvas, WebGL, maps)
- Non-SEO-critical parts of the page (modals, admin dashboards)
3. Component Structure
Props typing options: Astro supports both runtime access via Astro.props and compile-time
typing.
---
// 1. Type definitions FIRST
type Props = {
title: string;
description?: string;
isActive?: boolean;
};
// 2. Props destructuring with defaults (runtime access)
const { title, description, isActive = false } = Astro.props;
// 3. Imports and logic
import { getCollection } from 'astro:content';
const posts = await getCollection('articles');
---
<!-- 4. Template -->
<section class:list={["hero", { active: isActive }]}>
<h1>{title}</h1>
{description && <p>{description}</p>}
<slot />
</section>
<!-- 5. Scoped styles -->
<style>
.hero {
padding: var(--space-8);
}
</style>
4. Content Collections
ALWAYS define schemas for type safety (see src/content.config.ts):
// src/content.config.ts
import {defineCollection, z, reference} from 'astro:content';
import {glob} from 'astro/loaders';
const articles = defineCollection({
loader: glob({pattern: '**/*.{md,mdx}', base: './src/data/articles'}),
schema: ({image}) => z.object({
title: z.string(),
description: z.string(),
date: z.coerce.date(),
cover: image().optional(),
author: reference('authors'),
tags: z.array(reference('tags')),
category: reference('categories'),
draft: z.boolean().optional().default(false),
}),
});
export const collections = {articles};
5. Image Optimization
ALWAYS use Astro's Image component:
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<!-- โ
Optimized, responsive -->
<Image
src={heroImage}
alt="Hero banner"
width={1200}
height={600}
format="webp"
/>
<!-- โ NEVER use raw img for local images -->
<img src="/hero.jpg" alt="Hero" />
Project Structure (This Portfolio)
apps/portfolio/
โโโ src/
โ โโโ pages/ # File-based routing
โ โโโ components/
โ โ โโโ atoms/ # Smallest elements
โ โ โโโ molecules/ # Atom combinations
โ โ โโโ organisms/ # Full sections
โ โโโ layouts/ # BaseLayout.astro, etc.
โ โโโ data/ # Content collections
โ โ โโโ articles/ # Blog posts (MDX)
โ โ โโโ resume/ # Resume JSON by locale
โ โ โโโ tags/ # Tag definitions
โ โ โโโ authors/ # Author profiles
โ โโโ core/ # Business logic (domain)
โ โโโ lib/ # Utilities
โ โโโ i18n/ # Internationalization
โ โโโ styles/ # Global CSS (Tailwind)
โโโ public/ # Static assets
โโโ astro.config.mjs
Anti-Patterns
โ Shipping unnecessary JS - Use .astro for static content
โ Using client:load everywhere - Most components don't need immediate hydration
โ Raw <img> tags - Use <Image> for optimization
โ Inline styles for everything - Use scoped <style> blocks
โ Hardcoded meta tags - Use a reusable BaseHead.astro
SEO Pattern
---
// BaseHead.astro
type Props = {
title: string;
description: string;
image?: string;
};
const { title, description, image } = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
---
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="canonical" href={canonicalURL} />
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalURL} />
{image && <meta property="og:image" content={new URL(image, Astro.site)} />}
Commands
Astro CLI Usage: Use
pnpm exec astroorpnpm --filter portfolio exec astro
# Development
pnpm --filter=portfolio dev
# Build
pnpm --filter=portfolio build
# Preview production build
pnpm --filter=portfolio preview
# Running Astro CLI commands directly
pnpm --filter=portfolio exec astro check # Type-check .astro files
pnpm --filter=portfolio exec astro add vue # Add integrations
Integration with Vue
When using Vue components as islands:
---
import InteractiveWidget from '../components/InteractiveWidget.vue';
---
<!-- Pass props, use appropriate hydration -->
<InteractiveWidget
client:visible
title="Dashboard"
:items={data.items}
/>
Resources
Score
Total Score
Based on repository quality metrics
SKILL.mdใใกใคใซใๅซใพใใฆใใ
ใฉใคใปใณในใ่จญๅฎใใใฆใใ
100ๆๅญไปฅไธใฎ่ชฌๆใใใ
GitHub Stars 100ไปฅไธ
1ใถๆไปฅๅ ใซๆดๆฐ
10ๅไปฅไธใใฉใผใฏใใใฆใใ
ใชใผใใณIssueใ50ๆชๆบ
ใใญใฐใฉใใณใฐ่จ่ชใ่จญๅฎใใใฆใใ
1ใคไปฅไธใฎใฟใฐใ่จญๅฎใใใฆใใ
Reviews
Reviews coming soon

