一键导入
astro
Astro framework code standards. Use when writing or reviewing Astro components (.astro), content collections, layouts, and pages.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Astro framework code standards. Use when writing or reviewing Astro components (.astro), content collections, layouts, and pages.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Deep interview for a single feature or module brief that produces a final spec or implementation plan.
@nextnode-solutions/logger standards. Reference this skill when a project uses @nextnode-solutions/logger or when logger integration is being added.
Manage n8n workflows on the NextNode automation instance with the local n8n-cli tool.
NextNode brand guidelines — color palette, typography, logo system, and per-project branding rules. Use when doing UI/frontend work on a NextNode project.
NextNode ecosystem hub. Auto-load when working on any NextNode or SaaS project — covers nextnode.toml config, CI workflows, docker-compose rules, and cross-references to package skills.
Audit a NextNode/SaaS project against all NextNode standards — produces a compliance report with pass/fail/missing status for every required item.
| name | astro |
| description | Astro framework code standards. Use when writing or reviewing Astro components (.astro), content collections, layouts, and pages. |
| user-invocable | false |
MANDATORY CO-SKILL: When this skill is active, ALWAYS also load the
structure-astroskill. Thestructure-astroskill defines the canonical project structure for all Astro projects and is non-negotiable. Ifstructure-astrois not already loaded, load it immediately before proceeding with any Astro work.
.astro components over framework components when no interactivity neededclient:load — interactive immediately on page load (modals, nav menus)client:idle — interactive after page idle (below-fold widgets)client:visible — interactive when scrolled into viewport (counters, carousels)client:only="react" — client-render only, skip SSR (browser-only APIs)client:* to a component that doesn't need interactivityclient:visible or client:idle over client:load for performancesrc/content.config.ts using Zod via astro/zoddefineCollection + z.object({}) — NEVER untyped frontmatterreference() for cross-collection relationshipsglob() for file-based, file() for single-file data sourcesgetCollection() / getEntry() — NEVER raw file readsimport { defineCollection, reference } from 'astro:content';
import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/data/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
author: reference('authors'),
}),
});
---) for server-only logic: imports, data fetching, propsAstro.props with explicit interfacesrc/pages/[slug].astro with getStaticPaths() for static.ts files in src/pages/api/ returning Response objectsoutput: 'static') unless SSR is requiredimport.meta.env works under the hoodimport.meta.env.X becomes the literal value in the output JSPUBLIC_ vars are always inlined into both client and server bundles (by design)staticImportMetaEnv): non-public import.meta.env.SECRET is replaced with process.env.SECRET (runtime) — this is safe but will changeexperimental.staticImportMetaEnv (default in Astro 6.0): ALL import.meta.env values are inlined, including secrets — the literal secret value ends up in the server JS bundleimport.meta.env object into the bundle (fixed, but illustrates the risk)process.env.X is always a runtime lookup — the value never appears in any bundleastro:env/server with access: "secret" for sensitive values — this is the only future-proof patternimport.meta.env.SECRET_X for sensitive data — safe today, broken in Astro 6process.env in Astro — Vite replaces process.env.X with ({}).X in some contexts, and .env files are not auto-loaded into process.envPUBLIC_ vars are fine via import.meta.env.PUBLIC_X — they are meant to be public// astro.config.mjs
import { defineConfig, envField } from "astro/config";
export default defineConfig({
env: {
schema: {
API_SECRET: envField.string({ context: "server", access: "secret" }),
PORT: envField.number({ context: "server", access: "public", default: 4321 }),
},
validateSecrets: true, // validate at startup, useful in CI
},
});
// src/lib/my-service.ts
import { API_SECRET } from "astro:env/server";
// API_SECRET is: never in client bundle, never inlined, always runtime, type-safe, validated
astro:env/server is FORBIDDENastro:env/server can ONLY be imported in server-only files (.astro frontmatter, middleware, API routes). If a .ts file is imported by BOTH server code AND client-side framework components (React, Svelte, etc.), importing astro:env/server will crash the browser with:
The "astro:env/server" module is only available server-side.
Fix: Use astro:env/client for vars needed in shared files. For server-only vars in a shared file, use import.meta.env.X (which Vite strips/replaces correctly per context).
// src/lib/supabase.ts — imported by BOTH server and client code
import { SUPABASE_ANON_KEY } from "astro:env/client"; // works everywhere
export function createServerSupabase(context) {
// SUPABASE_URL is server-only — use import.meta.env, NOT astro:env/server
return createServerClient(import.meta.env.SUPABASE_URL, SUPABASE_ANON_KEY, { ... });
}
export function createBrowserSupabase() {
return createBrowserClient(window.location.origin, SUPABASE_ANON_KEY, { ... });
}
PUBLIC_ prefix duplication with astro:envimport.meta.env.PUBLIC_X requires a PUBLIC_-prefixed env var to expose values to client JS. This forces duplication when infra generates X (not PUBLIC_X).
astro:env eliminates this. Define context: "client", access: "public" in the schema — Astro exposes the var to the browser using the ORIGINAL env var name. No PUBLIC_ prefix, no mapping, no duplication.
// astro.config.ts
import { defineConfig, envField } from "astro/config";
export default defineConfig({
env: {
schema: {
DB_URL: envField.string({ context: "server", access: "public" }),
ANON_KEY: envField.string({ context: "client", access: "public" }),
},
},
});
ANON_KEY is available client-side via import { ANON_KEY } from "astro:env/client" — no PUBLIC_ANON_KEY neededANON_KEY as-is — one name everywhereARG ANON_KEY) so Astro bakes it into client JS| Pattern | Safe for secrets? | Future-proof? |
|---|---|---|
import { X } from "astro:env/server" (access: "secret") | Yes | Yes |
import { X } from "astro:env/client" (access: "public") | Public only | Yes |
import.meta.env.SECRET (current Astro default) | Yes (today) | No (inlined in Astro 6) |
process.env.SECRET | Yes (runtime) | Fragile (Vite may rewrite) |
import.meta.env.PUBLIC_X | Public only | Legacy — prefer astro:env/client |
is:inlineIn Astro, <script> tags are processed by Vite by default — they get bundled, hoisted, and treated as ES modules. This is NOT what you want for external CDN scripts.
When Vite processes a <script src="https://cdn.example.com/lib.js"> tag:
Origin: http://localhost:4321cdn.tailwindcss.com) return a 302 redirect (e.g., to a versioned URL)Access-Control-Allow-Origin headers[Error] Cross-origin redirection to https://cdn.tailwindcss.com/3.4.17
denied by Cross-Origin Resource Sharing policy:
Origin http://localhost:4321 is not allowed by Access-Control-Allow-Origin.
Status code: 302
<script src="https://..."> MUST have is:inline — this tells Astro to emit the tag verbatim, bypassing Vite entirely:
<!-- WRONG — Vite processes this, CORS breaks -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- CORRECT — emitted as-is, browser loads normally -->
<script is:inline src="https://cdn.tailwindcss.com"></script>
<link> stylesheets that Vite might try to processis:inline scripts cannot use TypeScript, imports, or Vite features — they are raw browser scriptsNEVER use the Tailwind Play CDN (cdn.tailwindcss.com) for production. It:
is:inlineProper setup:
pnpm astro add tailwind
This installs @astrojs/tailwind + tailwindcss, patches astro.config.mjs, and generates CSS at build time with full tree-shaking — zero runtime CDN dependency.
If CDN is required (e.g., quick prototype, spec explicitly says CDN):
<script is:inline src="https://cdn.tailwindcss.com"></script>
When reviewing Astro code, flag as critical: bug if:
<script src="https://..."> lacks is:inline — it WILL break in dev with CORS errorsis:inline — page renders unstyledFlag as important: security if:
crossorigin="anonymous" (error reporting is opaque)<style> blocks in .astro files by defaultis:global only when scoped styles genuinely can't work