AgentSkillsCN

jaspr

精通Jaspr框架与jaspr_content。可用于组件设计(SSR/水合渲染)、内容引擎、CSS-in-Dart样式化,以及Jaspr特有的构建流程。

SKILL.md
--- frontmatter
name: jaspr
description: Expert guidance for the Jaspr framework and jaspr_content. Use for component design (SSR/Hydration), content engines, CSS-in-Dart styling, and Jaspr-specific build workflows.

Jaspr Framework Dev

Core Principles

1. Execution Model

  • Server-Side Rendering (SSR): Preferred for SEO and initial load. Global config in lib/main.server.dart.
  • Client-Side Hydration: Use @client for stateful/interactive components.
  • Isomorphic Code: Favor package:jaspr/jaspr.dart for core logic and package:jaspr/dom.dart for HTML elements.

2. Content Management (jaspr_content)

  • Eager Loading: Enable eagerlyLoadAllPages: true in ContentApp to access metadata for all pages.
  • Programmatic Access: If ContentContext.of(context).pages is inaccessible, manually read the content/ directory using Directory('content/blog').listSync() and parse Markdown files.
  • Frontmatter Parsing: When manually parsing, split content by --- and extract keys like title:, date:, and description:.
  • Frontmatter Access in Layouts: Inside a custom PageLayout, access frontmatter via page.data.page['your_key'].
  • Custom Slugs/Routing: To decouple filenames from URL paths (e.g., 2024-01-01-post.md -> /blog/post), use ContentApp.custom and provide a routerBuilder. Inside routerBuilder, iterate through the generated routes and return a new Route with the desired path by reading the file's frontmatter.

3. Custom Layouts

  • Implementation: Extend PageLayout or PageLayoutBase. PageLayoutBase provides default buildHead logic for SEO tags.
  • Member Implementation: If extending PageLayout, implement buildLayout(Page page, Component child). If extending PageLayoutBase, implement buildBody(Page page, Component child).
  • Layout Styling: To include layout-specific global styles, override buildHead and yield a Style component: yield Style(styles: _styles);.
  • DocsLayout Limitations: DocsLayout does not have built-in flags to hide the title/description. Use a custom layout for full control over the content-header.
  • Header Navigation: The Header component from jaspr_content accepts an items list of components, ideal for top-level navigation links.
  • DOM Naming: Use main_() for the <main> tag to avoid name collisions with the Dart main() function.

4. Styling (CSS-in-Dart)

  • Typed API Enums:
    • Display.flex, Display.grid, Display.none.
    • AlignItems.start, AlignItems.center, AlignItems.end.
    • FlexDirection.row, FlexDirection.column.
    • FontWeight.w400 (normal), FontWeight.w600 (semibold), FontWeight.w700 (bold), FontWeight.w800 (extrabold).
  • Units & Spacing: Use extensions like .rem, .px, .percent, or Unit.auto. For .all(Unit.zero), use Unit.zero instead of 0.
  • Raw Styles: Use raw: {} for:
    • grid-template-columns: 'repeat(auto-fit, minmax(420px, 1fr))'.
    • gap: '3rem' (if Gap() constructor fails).
    • aspect-ratio: '2 / 1', object-fit: 'cover'.
    • border: '1px solid rgba(0, 0, 0, 0.2)'.
    • text-decoration: 'underline'.

Workflows

Searching Documentation

  1. ALWAYS use the context7 MCP server as the primary source for documentation, code examples, and API references for Jaspr and related libraries.
  2. Call resolve-library-id with jaspr to get the correct library ID: /schultek/jaspr. Note: This ID also contains documentation for sub-packages like jaspr_content, jaspr_router, etc.
  3. Use query-docs with /schultek/jaspr to find specific information before attempting to write code or solve complex framework-specific issues.

Creating a Blog Overview

  1. Create a component that accesses all loaded pages using context.pages (requires eagerlyLoadAllPages: true in ContentApp).
  2. Filter pages by path (e.g., page.path.startsWith('blog/')) and ensure they aren't index pages.
  3. Access frontmatter data via page.data.page['key'] (e.g., title, description, date).
  4. Sort posts by date (parsed from frontmatter) descending.
  5. Render using a ul with Display.grid and auto-fit for responsiveness.

Registering Custom Components

Use CustomComponent in ContentApp to enable custom tags in Markdown:

dart
CustomComponent(
  pattern: 'MyComponent',
  builder: (name, attributes, child) => MyComponent(
    title: attributes['title'],
    children: [if (child != null) child],
  ),
)

AFTER making code changes and BEFORE considering a task complete, you MUST:

  1. Build: Run jaspr build and verify successful completion.

No-Shortcut Policy

  • Never skip the build: Even for "trivial" or "safe" changes (like paths, text, or CSS), a build is required to ensure no regressions or syntax errors were introduced.
  • Final Tool Call: The last tool call in any turn that modifies the codebase or assets MUST be jaspr build (or a command that includes it).

Pre-Response Check

Before sending a text response to the user after a modification:

  • "Did I run jaspr build in this turn?"
  • If NO, run it now.
  • If YES but it failed, resolve the error.

Common Issues

  • highlighter crash: CodeBlock() from jaspr_content may throw "Null check operator used on a null value" due to complex language hints or missing theme colors. Disable it in lib/main.server.dart if it blocks the build.
  • OptionsSkew: If jaspr build fails with OptionsSkew, run pkill -f dart && pkill -f jaspr and try again.
  • Import Errors: Ensure package:jaspr/dom.dart is used for HTML tags and package:jaspr/jaspr.dart for core components.