关于 vue-nuxt
面向 Vue 3 和 Nuxt 3 开发的技能指南,聚焦 JARVIS AI Assistant 的 HUD 界面,并强调安全、性能与 TypeScript。适合构建响应式组件、服务端路由和 3D 界面,提供测试、输入清理及部署检查模式。
主要功能
- 01Vue 3 Composition API 与 TypeScript
- 02Nuxt 服务端路由和安全配置
- 03输入校验与 HTML 清理
- 04响应式性能优化和延迟加载
- 05组件测试与安全验证
适用场景
- 01构建 JARVIS HUD 组件和 3D 场景
- 02实现经校验的 API 路由
- 03防护动态内容中的 XSS 风险
- 04部署前检查类型、漏洞和构建
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ martinholovsky/ claude-skills-generator --skill vue-nuxt安装后在 Claude Code 中输入/vue-nuxt确认已加载。
附带文件references/advanced-patterns.mdreferences/security-examples.md
详细介绍
Vue 3 / Nuxt 3 开发技能
文件组织:此技能采用拆分式结构。高级模式和安全示例请参阅
references/。
1. 概述
此技能提供使用 Vue 3 和 Nuxt 3 构建 JARVIS AI 助手用户界面的专业知识,重点介绍如何通过安全优先的开发实践,创建响应式、高性能的 3D HUD 界面。
风险级别:中 — 处理用户输入、渲染动态内容,可能存在 XSS 攻击向量
主要用例:
- 为 JARVIS 界面构建响应式 3D HUD 组件
- 通过服务端渲染提升初始加载性能
- 集成客户端状态管理
- 安全处理用户输入和 API 响应
2. 核心职责
2.1 基本原则
- TDD 优先:先编写测试,再实现功能,遵循红灯/绿灯/重构循环
- 关注性能:使用 computed、shallowRef 和惰性组件,实现最佳响应性
- 优先使用组合式 API:使用 Vue 3 组合式 API 和
<script setup>,以改善 TypeScript 类型推断和代码组织 - 服务端安全:利用 Nuxt 服务端路由处理敏感操作,绝不向客户端暴露机密信息
- 响应式状态安全:使用
ref()和reactive(),并设置适当的类型,以防止状态损坏 - 输入净化:在渲染或处理用户输入之前,始终对其进行净化
- 性能优化:实现延迟加载、代码分割和高效响应式处理,提升 3D HUD 性能
- 类型安全:全程使用 TypeScript,以便在编译时检测错误
- 安全默认值:配置 CSP 标头,并默认禁用危险功能
3. 技术栈与版本
3.1 建议版本
| 包 | 版本 | 安全说明 |
|---|---|---|
| Vue | ^3.4.0 | 最新稳定版本,响应式能力有所改进 |
| Nuxt | ^3.12.4+ | 严重:修复 CVE-2024-34344 RCE |
| @nuxt/devtools | ^1.3.9+ | 严重:修复 CVE-2024-23657 |
| vite | ^5.0.0 | 最新版本,包含安全补丁 |
3.2 安全关键依赖
{
"dependencies": {
"nuxt": "^3.12.4",
"vue": "^3.4.0",
"dompurify": "^3.0.6",
"isomorphic-dompurify": "^2.0.0"
},
"devDependencies": {
"@nuxt/devtools": "^1.3.9",
"eslint-plugin-vue": "^9.0.0",
"eslint-plugin-security": "^2.0.0"
}
}
4. 实现模式
4.1 安全的组件结构
<script setup lang="ts">
// ✅ Type-safe props with validation
interface Props {
hudData: HUDDisplayData
userId: string
}
const props = defineProps<Props>()
// ✅ Emit events with typed payloads
const emit = defineEmits<{
'update:status': [status: string]
'command:execute': [command: JARVISCommand]
}>()
// ✅ Secure ref initialization
const displayState = ref<HUDState>({
isActive: false,
securityLevel: 'standard'
})
</script>
<template>
<div class="hud-panel">
<span v-text="props.hudData.title" />
</div>
</template>
4.2 输入净化模式
// composables/useSanitize.ts
import DOMPurify from 'isomorphic-dompurify'
export function useSanitize() {
const sanitizeHTML = (dirty: string): string => {
// ✅ Strict sanitization for any HTML content
return DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'span'],
ALLOWED_ATTR: ['class']
})
}
const sanitizeText = (input: string): string => {
// ✅ Strip all HTML for plain text
return DOMPurify.sanitize(input, { ALLOWED_TAGS: [] })
}
return { sanitizeHTML, sanitizeText }
}
4.3 安全的 API 路由模式
// server/api/jarvis/command.post.ts
import { z } from 'zod'
// ✅ Define strict schema for command validation
const commandSchema = z.object({
action: z.enum(['status', 'control', 'query']),
target: z.string().max(100).regex(/^[a-zA-Z0-9-_]+$/),
parameters: z.record(z.string()).optional()
})
export default defineEventHandler(async (event) => {
const body = await readBody(event)
// ✅ Validate input against schema
const result = commandSchema.safeParse(body)
if (!result.success) {
throw createError({
statusCode: 400,
message: 'Invalid command format' // ✅ Generic error message
})
}
// ✅ Process validated command
const command = result.data
// Never log sensitive data
console.log(`Processing command: ${command.action}`)
return { success: true, commandId: generateSecureId() }
})
4.4 安全的环境配置
// nuxt.config.ts
export default defineNuxtConfig({
// ✅ Security headers
routeRules: {
'/**': {
headers: {
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block'
}
}
},
// ✅ Runtime config - secrets stay server-side
runtimeConfig: {
apiSecret: process.env.API_SECRET, // Server only
public: {
apiBase: '/api' // Client accessible
}
},
// ✅ Disable devtools in production
devtools: { enabled: process.env.NODE_ENV === 'development' }
})
4.5 3D HUD 组件集成
<script setup lang="ts">
// components/HUDDisplay.vue
import { TresCanvas } from '@tresjs/core'
const props = defineProps<{
metrics: SystemMetrics
}>()
// ✅ Validate metrics before rendering
const validatedMetrics = computed(() => {
return {
cpu: Math.min(100, Math.max(0, props.metrics.cpu)),
memory: Math.min(100, Math.max(0, props.metrics.memory)),
status: sanitizeText(props.metrics.status)
}
})
</script>
<template>
<TresCanvas>
<HUDMetricsDisplay :data="validatedMetrics" />
</TresCanvas>
</template>
5. 实现工作流(TDD)
5.1 步骤 1:先编写失败的测试
始终先编写测试,明确预期行为:
// tests/components/VoiceIndicator.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import VoiceIndicator from '@/components/VoiceIndicator.vue'
describe('VoiceIndicator', () => {
it('displays idle state by default', () => {
const wrapper = mount(VoiceIndicator)
expect(wrapper.find('.indicator').classes()).toContain('idle')
expect(wrapper.text()).toContain('Ready')
})
it('shows listening state when active', async () => {
const wrapper = mount(VoiceIndicator, {
props: { isListening: true }
})
expect(wrapper.find('.indicator').classes()).toContain('listening')
expect(wrapper.find('.pulse-animation').exists()).toBe(true)
})
it('emits cancel event on escape key', async () => {
const wrapper = mount(VoiceIndicator, {
props: { isListening: true }
})
await wrapper.trigger('keydown.escape')
expect(wrapper.emitted('cancel')).toBeTruthy()
})
})
5.2 步骤 2:仅实现通过测试所需的内容
只编写足以让测试通过的代码:
<script setup lang="ts">
const props = defineProps<{ isListening?: boolean }>()
const emit = defineEmits<{ 'cancel': [] }>()
const handleKeydown = (e: KeyboardEvent) => {
if (e.key === 'Escape') emit('cancel')
}
</script>
<template>
<div
class="indicator"
:class="isListening ? 'listening' : 'idle'"
@keydown="handleKeydown"
tabindex="0"
>
<span v-if="!isListening">Ready</span>
<div v-else class="pulse-animation" />
</div>
</template>
5.3 步骤 3:按需重构
测试通过后,在不改变行为的前提下改进代码质量。每次重构后都要重新运行测试。
5.4 步骤 4:运行完整验证
# Run all verification steps before committing
npx vitest run # Unit tests
npx eslint . --ext .vue,.ts # Linting
npx nuxi typecheck # Type checking
npm run build # Build verification
6. 性能模式
6.1 使用计算属性派生状态
// ❌ BAD - Recalculates in template on every render
<template>
<div>{{ items.filter(i => i.active).length }} active</div>
</template>
// ✅ GOOD - Cached until dependencies change
const activeCount = computed(() => items.value.filter(i => i.active).length)
<template>
<div>{{ activeCount }} active</div>
</template>
6.2 对大型对象使用 shallowRef
// ❌ BAD - Deep reactivity on large 3D data
const meshData = ref<MeshData>({ vertices: new Float32Array(100000), ... })
// ✅ GOOD - Shallow reactivity, manual trigger
const meshData = shallowRef<MeshData>({ vertices: new Float32Array(100000), ... })
// Trigger update explicitly
meshData.value = { ...newData }
triggerRef(meshData)
6.3 使用 defineAsyncComponent 实现延迟加载
// ❌ BAD - All components loaded upfront
import HeavyChart from '@/components/HeavyChart.vue'
// ✅ GOOD - Load only when needed
const HeavyChart = defineAsyncComponent(() =>
import('@/components/HeavyChart.vue')
)
// With loading state
const HeavyChart = defineAsyncComponent({
loader: () => import('@/components/HeavyChart.vue'),
loadingComponent: LoadingSpinner,
delay: 200
})
6.4 使用 v-memo 优化列表
<div v-for="item in items" :key="item.id">
<ExpensiveComponent :data="item" />
</div>
<div v-for="item in items" :key="item.id" v-memo="[item.id, item.updated]">
<ExpensiveComponent :data="item" />
</div>
6.5 对长列表使用虚拟滚动
<script setup lang="ts">
import { useVirtualList } from '@vueuse/core'
const { list, containerProps, wrapperProps } = useVirtualList(
items,
{ itemHeight: 50 }
)
</script>
<template>
<div v-bind="containerProps" class="h-[400px] overflow-auto">
<div v-bind="wrapperProps">
<div v-for="{ data, index } in list" :key="index">
{{ data.name }}
</div>
</div>
</div>
</template>
6.6 使用防抖侦听器
// ❌ BAD - Fires on every keystroke
watch(searchQuery, async (query) => {
results.value = await searchAPI(query)
})
// ✅ GOOD - Debounced to reduce API calls
import { watchDebounced } from '@vueuse/core'
watchDebounced(
searchQuery,
async (query) => {
results.value = await searchAPI(query)
},
{ debounce: 300 }
)
// Alternative with manual debounce
watch(searchQuery, useDebounceFn(async (query) => {
results.value = await searchAPI(query)
}, 300))
7. 安全标准
7.1 已知漏洞(CVE 研究)
| CVE | 严重性 | 描述 | 缓解措施 |
|---|---|---|---|
| CVE-2024-34344 | 高 | 通过测试组件实现 Nuxt 远程代码执行(RCE) | 更新至 Nuxt 3.12.4+ |
| CVE-2024-23657 | 高 | Devtools 路径遍历/远程代码执行(RCE) | 将 devtools 更新至 1.3.9+ |
| CVE-2023-3224 | 严重 | 开发服务器代码注入 | 更新至 Nuxt 3.4.4+,绝不暴露开发服务器 |
参见:references/security-examples.md,了解详细的缓解措施代码
5.2 OWASP Top 10 覆盖情况
| OWASP 类别 | 风险 | 缓解策略 |
|---|---|---|
| A01 访问控制失效 | 高 | 服务端路由防护、身份验证中间件 |
| A03 注入 | 高 | 使用 Zod 验证输入、参数化查询 |
| A05 安全配置错误 | 中 | CSP 标头、安全的 nuxt.config |
| A07 XSS | 高 | v-text 指令、使用 DOMPurify 清理 |
5.3 输入验证框架
// ❌ DANGEROUS - Direct v-html with user input
<div v-html="userMessage" />
// ✅ SECURE - Sanitized HTML or plain text
<div v-html="sanitizeHTML(userMessage)" />
<span v-text="userMessage" />
5.4 身份验证中间件
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
const { authenticated } = useAuthState()
if (!authenticated.value && to.meta.requiresAuth) {
return navigateTo('/login')
}
})
6. 测试与质量
6.1 安全测试
// tests/security/xss.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import HUDPanel from '@/components/HUDPanel.vue'
describe('XSS Prevention', () => {
it('should sanitize malicious input', () => {
const wrapper = mount(HUDPanel, {
props: {
title: '<script>alert("xss")</script>Hello'
}
})
expect(wrapper.html()).not.toContain('<script>')
expect(wrapper.text()).toContain('Hello')
})
})
6.2 组件测试
// tests/components/HUDDisplay.test.ts
describe('HUDDisplay', () => {
it('validates metric bounds', () => {
const wrapper = mount(HUDDisplay, {
props: {
metrics: { cpu: 150, memory: -10, status: 'active' }
}
})
// Should clamp values to valid range
expect(wrapper.vm.validatedMetrics.cpu).toBe(100)
expect(wrapper.vm.validatedMetrics.memory).toBe(0)
})
})
7. 常见模式 / 工作流
7.1 JARVIS HUD 组件工作流
- 定义 TypeScript 接口,涵盖所有数据结构
- 创建组合式函数,封装共享逻辑
- 使用 Composition API 实现组件
- 在组件边界处添加输入验证
- 编写安全测试,检查 XSS/注入
- 通过 TresJS 与 3D 场景集成
7.2 API 集成工作流
- 定义 Zod 架构,用于请求/响应
- 创建服务端路由并进行验证
- 创建客户端组合式函数并处理错误
- 为 UI 添加加载/错误状态
- 测试错误情况和边界条件
8. 常见错误与反模式
8.1 严重安全反模式
切勿:对未清理的输入使用 v-html
<div v-html="userProvidedContent" />
<div v-html="sanitizeHTML(userProvidedContent)" />
<span v-text="userProvidedContent" />
切勿:在客户端代码中暴露机密信息
// ❌ DANGEROUS - Secret in public config
runtimeConfig: {
public: {
apiKey: process.env.API_KEY // Exposed to client!
}
}
// ✅ SECURE - Secrets stay server-side
runtimeConfig: {
apiKey: process.env.API_KEY, // Server only
public: {
apiBase: '/api'
}
}
切勿:只信任客户端验证
// ❌ DANGEROUS - Client-only validation
const handleSubmit = () => {
if (isValidEmail(email.value)) {
$fetch('/api/subscribe', { body: { email: email.value } })
}
}
// ✅ SECURE - Server-side validation
// server/api/subscribe.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const result = emailSchema.safeParse(body)
if (!result.success) {
throw createError({ statusCode: 400, message: 'Invalid email' })
}
// Process validated email
})
8.2 性能反模式
避免:在 computed 中使用响应式数组
// ❌ BAD - Creates new array on every access
const filtered = computed(() => {
return items.value.filter(i => i.active).sort()
})
// ✅ GOOD - Memoized with stable reference
const filtered = computed(() => {
const result = items.value.filter(i => i.active)
result.sort((a, b) => a.name.localeCompare(b.name))
return result
})
9. 快速参考
基本命令
# Development
npx nuxi dev --host # Never expose to public network!
# Security audit
npm audit --audit-level=high
npx nuxi typecheck
# Production build
npx nuxi build
关键组合式函数
// State management
const state = useState<T>('key', () => initialValue)
// Runtime config access
const config = useRuntimeConfig()
// Route navigation
const router = useRouter()
await navigateTo('/path')
13. 部署前检查清单
安全验证
- Nuxt 版本 >= 3.12.4(修复 CVE-2024-34344)
- Devtools 版本 >= 1.3.9(修复 CVE-2024-23657)
- 已在 nuxt.config 中配置 CSP 标头
-
runtimeConfig.public中没有机密信息 - 已使用 DOMPurify 清理所有用户输入
- 服务端路由已使用 Zod 架构进行验证
- 受保护的路由上已启用身份验证中间件
- 已在生产环境中禁用 Devtools
构建验证
-
npm audit未发现高危或严重漏洞 - TypeScript 编译通过
- 所有安全测试均通过
- 生产构建顺利完成,没有错误
14. 总结
此 Vue/Nuxt 技能为构建 JARVIS AI 助手 HUD 界面提供了安全模式:
- 安全优先:始终清理输入、在服务端进行验证,并使用 CSP 标头
- 类型安全:全程使用 TypeScript 和严格的验证架构
- 性能:使用 Composition API、延迟加载和高效的响应式机制
- 可维护性:采用清晰的组件结构,并使用组合式函数实现复用
请记住:JARVIS HUD 会处理敏感的系统数据。每个组件都必须将用户输入视为潜在的恶意内容,并验证所有数据边界。
参考资料:
references/advanced-patterns.md- 复杂组件模式references/security-examples.md- 详细的安全实现
评论
支持 Markdown