Understanding Plugin Architecture
Esta página aún no está disponible en tu idioma.
This guide explains the internal architecture of the starlight-tags plugin. Understanding these internals helps when debugging, extending, or contributing to the plugin.
Data Flow Overview
Section titled “Data Flow Overview”┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐│ tags.yml │────▶│ tags-processor │────▶│ data.ts │└─────────────┘ └──────────────────┘ └─────────────────┘ │ │ ▼ ▼ ┌──────────────┐ ┌─────────────────┐ │ Validation │ │ Middleware │ │ (Zod Schema) │ │ (onRequest) │ └──────────────┘ └─────────────────┘ │ ▼ ┌─────────────────┐ │ Astro.locals │ │ .starlightTags │ └─────────────────┘ │ ┌────────────────────────┴────────────────────────┐ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ Components │ │ Generated Pages │ │ (TagBadge...) │ │ /tags/[slug]/ │ └─────────────────┘ └─────────────────┘1. Configuration Loading
Section titled “1. Configuration Loading”The plugin reads your tags.yml file at build time:
tags: authentication: label: "Authentication" description: "Auth-related content" color: "#3b82f6"2. Processing & Validation
Section titled “2. Processing & Validation”tags-processor.ts handles:
- Converts YAML to JavaScript objects
- Validates against Zod schemas
- Scans content files for tag references
- Creates slugs and URLs for each tag
3. Middleware & Data Access
Section titled “3. Middleware & Data Access”The plugin uses route middleware to inject processed tag data into Astro.locals:
// Access via Astro.locals (automatically available)const { tags, allTagsSorted, tagsByPage, config } = Astro.locals.starlightTags;
// Get a specific tagconst tag = tags.get('authentication');
// Get tags for current pageconst pageTags = tagsByPage.get(pageSlug) ?? [];4. Page Generation
Section titled “4. Page Generation”Astro’s getStaticPaths() generates all tag pages at build time.
Tag Page Generation
Section titled “Tag Page Generation”Static Path Generation
Section titled “Static Path Generation”Tag pages are generated for every combination of:
- Each tag defined in
tags.yml - Each locale configured in Starlight (en, fr, es, etc.)
- Each page number based on
itemsPerPagesetting
// Simplified example of generated paths[ { params: { tag: 'js-basics', locale: undefined, page: undefined } }, { params: { tag: 'js-basics', locale: undefined, page: '2' } }, { params: { tag: 'js-basics', locale: 'fr', page: undefined } }, { params: { tag: 'js-basics', locale: 'fr', page: '2' } }, // ... for every tag × locale × page combination]Props Passed to Tag Pages
Section titled “Props Passed to Tag Pages”Each generated tag page receives these props:
| Prop | Type | Description |
|---|---|---|
tag | ProcessedTag | Tag data (label, icon, color, description, url) |
pages | PageReference[] | Paginated subset of pages with this tag |
pagination | PaginationInfo | Current page, total pages, start/end index |
ProcessedTag Type
Section titled “ProcessedTag Type”interface ProcessedTag { // Core properties id: string; // Tag identifier (key in tags.yml) label: string; // Display name description?: string; // Optional description color?: string; // Hex color code icon?: string; // Emoji or icon permalink?: string; // Custom URL slug override hidden?: boolean; // Whether to hide from index priority?: number; // Sort order (higher first, default: 0)
// Computed properties slug: string; // URL-safe slug (from permalink or generated) url: string; // Full URL path count: number; // Number of pages with this tag pages: PageReference[]; // All pages with this tag
// Educational properties (optional) difficulty?: 'beginner' | 'intermediate' | 'advanced'; contentType?: 'lecture' | 'lab' | 'assignment' | 'project' | 'reference' | 'tutorial' | 'assessment'; prerequisites?: string[]; // Tag IDs that should be understood first
// Computed educational relationships relatedTags?: string[]; // IDs of related tags prerequisiteChain?: string[]; // Ordered prerequisite IDs (resolved recursively) nextSteps?: string[]; // Suggested next topics
// Custom fields from extended schemas [key: string]: unknown;}PageReference Type
Section titled “PageReference Type”interface PageReference { id: string; // Content collection ID slug: string; // Page URL slug title: string; // Page title description?: string; // Page description tags?: string[]; // All tags on this page frontmatter?: Record<string, unknown>; // Full frontmatter data for advanced use}Related Tags Calculation
Section titled “Related Tags Calculation”The “Related Tags” section on tag pages shows tags that co-occur with the current tag:
// Find other tags that appear on the same pagesconst relatedTags = new Set<string>();
pages.forEach(page => { page.tags?.forEach(tagId => { if (tagId !== currentTag.id) { relatedTags.add(tagId); } });});
// Sort by usage count (most used first)const sortedRelatedTags = Array.from(relatedTags) .map(tagId => getTag(tagId)) .filter(tag => tag && !tag.hidden) .sort((a, b) => b.count - a.count);Example
Section titled “Example”If the “authentication” tag appears on pages that also have:
- “api” (5 pages)
- “security” (3 pages)
- “oauth” (2 pages)
The related tags section will show these three tags, sized by frequency.
Popularity Tiers (Tag Cloud Sizing)
Section titled “Popularity Tiers (Tag Cloud Sizing)”Related tags are displayed with different sizes based on usage frequency:
| Tier | CSS Class | Usage Percentile | Visual Size |
|---|---|---|---|
| 5 | tier-5 | Top 20% | Largest |
| 4 | tier-4 | 60-80% | Large |
| 3 | tier-3 | 40-60% | Medium |
| 2 | tier-2 | 20-40% | Small |
| 1 | tier-1 | Bottom 20% | Smallest |
Tier Calculation
Section titled “Tier Calculation”function getPopularityTier(count: number): 'tier-1' | ... | 'tier-5' { const range = maxCount - minCount; if (range === 0) return 'tier-3'; // All same count
const normalized = (count - minCount) / range;
if (normalized >= 0.8) return 'tier-5'; if (normalized >= 0.6) return 'tier-4'; if (normalized >= 0.4) return 'tier-3'; if (normalized >= 0.2) return 'tier-2'; return 'tier-1';}i18n Support
Section titled “i18n Support”Tag pages automatically support Starlight’s i18n configuration.
Route Generation
Section titled “Route Generation”- Root locale:
/tags/authentication/ - French:
/fr/tags/authentication/ - Spanish:
/es/tags/authentication/
Translation Loading
Section titled “Translation Loading”UI strings are loaded from the plugin’s translation files:
// Access via Astro.locals.tconst t = Astro.locals.t;
t('starlightTags.relatedTags'); // "Related Tags"t('starlightTags.pages'); // "pages"t('starlightTags.taggedPrefix'); // "Tagged:"Adding Translations
Section titled “Adding Translations”See the i18n Guide for adding custom translations.
File Structure
Section titled “File Structure”Key files in the plugin:
packages/starlight-tags/├── index.ts # Plugin entry point├── middleware.ts # Route middleware for Astro.locals├── locals.d.ts # TypeScript declarations for Astro.locals├── src/│ ├── components/ # Astro components│ │ ├── TagBadge.astro│ │ ├── PageTags.astro│ │ └── ...│ ├── libs/│ │ ├── data.ts # Core data interface (StarlightTagsData)│ │ ├── integration.ts # Astro integration setup│ │ ├── tags-processor.ts # YAML processing & validation│ │ ├── vite.ts # Config virtual module for runtime│ │ ├── pagination.ts # Pagination logic│ │ └── url.ts # URL building utilities│ ├── pages/│ │ ├── tags-index.astro # /tags/ index page│ │ └── tag-page.astro # /tags/[slug]/ pages│ ├── schemas/│ │ ├── config.ts # Plugin config schema│ │ ├── tags.ts # tags.yml schema│ │ └── frontmatter.ts # Frontmatter extension│ ├── utils.ts # Standalone utility functions│ └── translations.ts # i18n stringsExtending the Plugin
Section titled “Extending the Plugin”Custom Tag Fields
Section titled “Custom Tag Fields”You can extend the tag schema with custom fields. See the Extending Schema Guide.
Programmatic Tag Access
Section titled “Programmatic Tag Access”Access tag data programmatically in your components via Astro.locals:
---import { filterByDifficulty, filterByContentType, getLearningPath, validatePrerequisites, getPopularityTier} from 'starlight-tags/utils';
// Core tag access - automatically available via middlewareconst { tags, allTagsSorted, tagsByPage, config } = Astro.locals.starlightTags;
// Get a specific tagconst authTag = tags.get('authentication');
// Get tags for a specific pageconst pageTags = tagsByPage.get('guides/authentication') ?? [];
// Filter by difficulty or content typeconst beginnerTags = filterByDifficulty(allTagsSorted, 'beginner');const tutorials = filterByContentType(allTagsSorted, 'tutorial');
// Educational featuresconst path = getLearningPath(tags, 'basics', 'advanced');const { isValid, errors } = validatePrerequisites(tags);---See the Accessing Tag Data guide for complete documentation.