AgentSkillsCN

frontend-framework

本指南专为使用Pulse JS框架构建响应式UI组件与应用而设。当您需要创建组件、实现响应式模式、构建表单、进行路由配置、管理状态,或处理.pulse文件时,此技能将助您事半功倍。此外,它在无障碍设计、性能优化,以及现代JavaScript/CSS特性等前端通用模式方面同样大有裨益。

SKILL.md
--- frontmatter
name: frontend-framework
description: Guide for building reactive UI components and applications with the Pulse JS framework. Use this skill when creating components, implementing reactivity patterns, building forms, routing, state management, or working with .pulse files. Also helpful for general frontend patterns like accessibility, performance optimization, and modern JavaScript/CSS features.

Frontend Framework Development with Pulse

When to Use This Skill

  • Creating or modifying .pulse component files
  • Implementing reactive state with pulse(), effect(), computed()
  • Building forms with validation using useForm(), useField()
  • Setting up routing with createRouter()
  • Managing global state with createStore()
  • Adding accessibility features (ARIA, focus management, announcements)
  • Optimizing performance (batching, memoization, list rendering)
  • Working with async data (useAsync, useResource, HTTP/WebSocket/GraphQL)
  • Debugging reactivity issues or UI not updating
  • Setting up tests for components

Bundled Resources

This skill includes:

ResourceDescription
assets/Component templates (page, form, modal, list, store)
scripts/Code generators and analyzers
references/Detailed patterns, CSS, testing, troubleshooting

Available Templates

bash
# Generate from templates (in scripts/)
node scripts/generate-component.js MyComponent
node scripts/generate-component.js LoginForm --type form
node scripts/generate-component.js Dashboard --type page
node scripts/generate-component.js ConfirmModal --type modal
node scripts/generate-component.js UserList --type list
node scripts/generate-component.js cart --type store

Analysis Scripts

bash
# Bundle size analysis
node scripts/analyze-bundle.js

# Accessibility check
node scripts/check-a11y.js
node scripts/check-a11y.js --fix

Quick Reference

Core Reactivity

javascript
import { pulse, effect, computed, batch } from 'pulse-js-framework/runtime';

// Reactive state
const count = pulse(0);
count.get();              // Read (tracks dependency)
count.set(5);             // Direct set
count.update(n => n + 1); // Functional update

// Derived state
const doubled = computed(() => count.get() * 2);

// Side effects (auto-runs when dependencies change)
effect(() => console.log(count.get()));

// Batch updates (single effect run)
batch(() => {
  count.set(1);
  name.set('Alice');
});

DOM Creation

javascript
import { el, mount, list, when } from 'pulse-js-framework/runtime';

// CSS selector syntax
el('div.container#main');           // <div class="container" id="main">
el('input[type=text][placeholder=Name]');

// Reactive children and attributes
el('button', {
  class: () => isActive.get() ? 'active' : '',
  disabled: () => isLoading.get(),
  onclick: handleClick
}, 'Click me');

// Conditional rendering
when(
  () => loading.get(),
  () => el('.spinner', 'Loading...'),
  () => el('.content', data.get())
);

// List rendering (always provide key function!)
list(
  () => items.get(),
  (item) => el('li', item.name),
  (item) => item.id  // Key for efficient diffing
);

mount('#app', App());

.pulse File Structure

pulse
@page ComponentName

import Button from './Button.pulse'

state {
  count: 0
  name: ''
}

view {
  .container {
    h1 "Count: {count}"
    input[type=text][value={name}] @input(name = event.target.value)
    Button @click(count++) { "Increment" }
  }
}

style {
  .container { padding: 20px }
}

Common Patterns

Form with Validation

javascript
import { useForm, validators } from 'pulse-js-framework/runtime/form';

const { fields, handleSubmit, isValid } = useForm(
  { email: '', password: '' },
  {
    email: [validators.required(), validators.email()],
    password: [validators.required(), validators.minLength(8)]
  },
  { onSubmit: (values) => login(values) }
);

Router Setup

javascript
import { createRouter, lazy } from 'pulse-js-framework/runtime/router';

const router = createRouter({
  routes: {
    '/': HomePage,
    '/users/:id': UserPage,
    '/admin': lazy(() => import('./Admin.js'))
  },
  mode: 'history'
});

router.outlet('#app');

Global Store

javascript
import { createStore, createActions } from 'pulse-js-framework/runtime/store';

const store = createStore({ user: null, theme: 'light' });
const actions = createActions(store, {
  login: (store, user) => store.user.set(user),
  toggleTheme: (store) => store.theme.update(t => t === 'light' ? 'dark' : 'light')
});

Async Data

javascript
import { useAsync, useResource } from 'pulse-js-framework/runtime/async';

// One-time fetch
const { data, loading, error } = useAsync(
  () => fetch('/api/users').then(r => r.json())
);

// Cached resource with SWR pattern
const users = useResource(
  'users',
  () => fetch('/api/users').then(r => r.json()),
  { refreshInterval: 30000, refreshOnFocus: true }
);

Accessibility Checklist

  1. Images: Always include alt attribute
  2. Buttons: Must have text content or aria-label
  3. Forms: Inputs need labels (aria-label or <label>)
  4. Modals: Use trapFocus() and announce() for screen readers
  5. Lists: Use semantic <ul>/<ol> with proper roles
  6. Headings: Maintain sequential order (h1 → h2 → h3)
javascript
import { trapFocus, announce } from 'pulse-js-framework/runtime/a11y';

// Modal pattern
const modal = el('dialog[aria-labelledby=title]', ...);
const release = trapFocus(modal, { autoFocus: true, returnFocus: true });
announce('Dialog opened');

Performance Tips

  1. Use computed() for derived values instead of recalculating in effects
  2. Always provide key functions to list() for efficient DOM diffing
  3. Use batch() when updating multiple related pulses
  4. Lazy load routes with lazy() for code splitting
  5. Use peek() to read without creating dependency tracking
  6. Custom equality for object pulses to prevent unnecessary updates
javascript
// Custom equality to prevent spurious updates
const config = pulse({ theme: 'dark' }, {
  equals: (a, b) => a.theme === b.theme
});

CLI Commands

bash
pulse create my-app          # New project
pulse dev                    # Dev server
pulse build                  # Production build
pulse new MyComponent        # Create component
pulse lint --fix             # Lint and auto-fix
pulse test --coverage        # Run tests

Key Files Reference

ModulePurpose
runtime/pulse.jsCore reactivity
runtime/dom.jsDOM creation, auto-ARIA
runtime/router.jsSPA routing
runtime/store.jsGlobal state
runtime/form.jsForm validation
runtime/async.jsAsync primitives
runtime/a11y.jsAccessibility helpers

See CLAUDE.md for complete API documentation.

Reference Documentation

For detailed guides, see the references/ folder:

  • patterns.md - Advanced patterns (composition, HOCs, error boundaries, optimistic updates, real-time data)
  • css-patterns.md - CSS variables, dark mode, responsive design, animations, component styles
  • testing.md - Unit tests, component tests, mocking, integration tests
  • troubleshooting.md - Common issues and solutions, debug checklist

Quick Troubleshooting

ProblemLikely CauseSolution
UI not updatingNot using .get() in reactive contextWrap in function: () => value.get()
Circular dependencyEffect triggers itselfUse untrack() or separate pulses
List items wrongMissing key functionAdd key: list(items, render, i => i.id)
Effect runs too oftenReading entire objectUse computed() for derived values
Memory leakMissing cleanupReturn cleanup function from effect()
Route 404 on refreshServer not configured for SPAConfigure server to serve index.html

Component Checklist

When creating a new component:

  • Define props with types in props {} block
  • Initialize local state in state {} block
  • Use semantic HTML elements
  • Add ARIA attributes for accessibility
  • Include keyboard navigation for interactive elements
  • Scope styles in style {} block
  • Add loading/error states for async data
  • Write tests in co-located .test.js file