소스 정보
- 저장소
- tomevault-io/skills-registry
- 최근 소스 활동
- 2026년 6월 7일 23:30
- 감지된 SKILL.md 언어
- 중국어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tomevault-io/skills-registry --skill vue-service-creator명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | vue-service-creator |
| description | name: vue-service-creator Use when this capability is needed. |
name: vue-service-creator description: | 【Vue服务脚手架】快速创建 Vue 3 / Nuxt 3 前端项目,支持 Composition API、Pinia、Vue Router。
触发时机:
生成标准化 Vue 3 / Nuxt 3 项目,内置 Composition API、Pinia、TypeScript 最佳实践。
快速创建 Vue 3 / Nuxt 3 前端项目,支持 Composition API、Pinia、Vue Router
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| SPA 后台管理系统 | Vue 3 + Vite | 轻量、灵活、构建快 |
| 内容站点 / 博客 | Nuxt 3 | SSR/SSG、SEO 友好 |
| 企业官网 | Nuxt 3 | 预渲染、路由自动生成 |
| 移动端 H5 | Vue 3 + Vite | 纯前端、打包体积小 |
| 全栈应用 | Nuxt 3 | 内置 server routes、API 层 |
| 组件库 / SDK | Vue 3 + Vite | 纯库模式、无框架依赖 |
| 层次 | Vue 3 方案 | Nuxt 3 方案 |
|---|---|---|
| 构建工具 | Vite 6 | Nuxt 内置 (Vite) |
| 状态管理 | Pinia | Pinia (内置支持) |
| 路由 | Vue Router 4 | 文件系统路由 (自动) |
| 样式 | Tailwind CSS / UnoCSS | Tailwind CSS / UnoCSS |
| 测试 | Vitest + Vue Test Utils | Vitest + Vue Test Utils |
| HTTP | ofetch / axios | useFetch / $fetch |
| 表单 | VeeValidate / FormKit | VeeValidate / FormKit |
| UI 库 | Element Plus / Naive UI | Element Plus / Naive UI |
{project-name}/
├── src/
│ ├── api/ # API 服务层
│ │ ├── request.ts # HTTP 客户端封装
│ │ ├── user.ts # 用户相关 API
│ │ └── index.ts
│ ├── assets/ # 静态资源
│ │ ├── images/
│ │ └── styles/
│ │ └── main.css
│ ├── components/ # 通用组件
│ │ ├── ui/ # 基础 UI 组件
│ │ │ ├── BaseButton.vue
│ │ │ ├── BaseInput.vue
│ │ │ └── index.ts
│ │ └── layout/ # 布局组件
│ │ ├── AppHeader.vue
│ │ ├── AppSidebar.vue
│ │ └── AppLayout.vue
│ ├── composables/ # 组合式函数
│ │ ├── useAuth.ts
│ │ ├── useApi.ts
│ │ └── index.ts
│ ├── pages/ # 页面组件
│ │ ├── Home.vue
│ │ ├── Login.vue
│ │ └── Dashboard.vue
│ ├── router/ # 路由配置
│ │ ├── index.ts
│ │ └── guards.ts
│ ├── stores/ # Pinia 状态
│ │ ├── modules/
│ │ │ ├── auth.ts
│ │ │ └── app.ts
│ │ └── index.ts
│ ├── types/ # TypeScript 类型
│ │ ├── api.d.ts
│ │ ├── env.d.ts
│ │ └── index.ts
│ ├── utils/ # 工具函数
│ │ ├── storage.ts
│ │ └── format.ts
│ ├── App.vue
│ └── main.ts
├── public/
├── tests/
│ ├── setup.ts
│ └── components/
├── .env.example
├── .eslintrc.cjs
├── .prettierrc
├── components.d.ts # unplugin-vue-components 自动生成
├── auto-imports.d.ts # unplugin-auto-import 自动生成
├── tailwind.config.ts
├── tsconfig.json
├── vite.config.ts
├── package.json
└── README.md
{project-name}/
├── app.vue # 根组件
├── error.vue # 错误页面
├── assets/
│ └── css/
│ └── main.css
├── components/ # 自动导入组件
│ ├── ui/
│ │ ├── BaseButton.vue
│ │ └── BaseInput.vue
│ └── layout/
│ ├── AppHeader.vue
│ └── AppSidebar.vue
├── composables/ # 自动导入组合式函数
│ ├── useAuth.ts
│ └── useApi.ts
├── layouts/ # 布局模板
│ ├── default.vue
│ └── auth.vue
├── middleware/ # 路由中间件
│ ├── auth.ts
│ └── guest.ts
├── pages/ # 文件系统路由
│ ├── index.vue
│ ├── login.vue
│ ├── dashboard/
│ │ ├── index.vue
│ │ └── settings.vue
│ └── users/
│ ├── index.vue
│ └── [id].vue
├── plugins/ # 插件
│ └── api.ts
├── public/ # 静态资源
├── server/ # 服务端
│ ├── api/ # API 路由
│ │ ├── auth/
│ │ │ ├── login.post.ts
│ │ │ └── me.get.ts
│ │ └── users/
│ │ ├── index.get.ts
│ │ └── [id].get.ts
│ ├── middleware/ # 服务端中间件
│ │ └── auth.ts
│ ├── plugins/
│ └── utils/
│ └── db.ts
├── stores/ # Pinia stores
│ ├── auth.ts
│ └── app.ts
├── types/
│ └── index.d.ts
├── tests/
├── nuxt.config.ts
├── tailwind.config.ts
├── tsconfig.json
├── package.json
└── README.md
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import { fileURLToPath, URL } from 'node:url';
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
resolvers: [ElementPlusResolver()],
dts: 'auto-imports.d.ts',
}),
Components({
resolvers: [ElementPlusResolver()],
dts: 'components.d.ts',
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
: {
: ,
: {
: {
: ,
: ,
: path.(, ),
},
},
},
: {
: {
: {
: {
: [, , ],
},
},
},
},
});
export default defineNuxtConfig({
devtools: { enabled: true },
modules: [
'@pinia/nuxt',
'@nuxtjs/tailwindcss',
'@vueuse/nuxt',
],
css: ['~/assets/css/main.css'],
runtimeConfig: {
// 服务端私有变量
jwtSecret: process.env.JWT_SECRET || '',
// 客户端公开变量(以 public 开头)
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api',
},
},
routeRules: {
'/dashboard/**': { ssr: false }, // SPA 模式
'/': { prerender: true }, // 预渲染
'/api/**': { cors: true }, // CORS
},
nitro: {
compressPublicAssets: true,
},
app: {
head: {
title: 'My Nuxt App',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
},
: { : , : },
},
: {
: ,
},
});
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
"paths":
import { ref, reactive, toRefs } from 'vue';
// ref — 适用于基本类型或单个对象
const count = ref(0);
const user = ref<User | null>(null);
// reactive — 适用于对象/数组(注意不能解构,需 toRefs)
const form = reactive({
username: '',
password: '',
remember: false,
});
// toRefs 保持响应性
const { username, password } = toRefs(form);
import { computed } from 'vue';
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
// 可写 computed
const fullNameRW = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (val: string) => {
const [first, last] = val.split(' ');
firstName.value = first;
lastName.value = last;
},
});
import { watch, watchEffect } from 'vue';
// watch — 精确追踪
watch(
() => route.params.id,
async (newId) => {
if (newId) await fetchUser(Number(newId));
},
{ immediate: true }
);
// watchEffect — 自动追踪依赖
watchEffect(async () => {
const data = await fetchUser(userId.value);
user.value = data;
});
import { onMounted, onUnmounted, onUpdated } from 'vue';
onMounted(() => {
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});
// stores/modules/auth.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { apiClient } from '@/api/request';
interface User {
id: number;
username: string;
email: string;
role: string;
}
export const useAuthStore = defineStore('auth', () => {
// State
const user = ref<User | null>(null);
const token = ref<string>(localStorage.getItem('token') || '');
// Getters
const isAuthenticated = computed(() => !!token.value);
const isAdmin = computed(() => user.value?.role === 'admin');
// Actions
async function login(username: , : ) {
{ data } = apiClient.(, {
username,
password,
});
token. = data.;
user. = data.;
.(, data.);
}
() {
(!token.) ;
{
{ data } = apiClient.();
user. = data;
} {
();
}
}
() {
user. = ;
token. = ;
.();
}
{
user,
token,
isAuthenticated,
isAdmin,
login,
fetchCurrentUser,
logout,
};
});
// router/index.ts
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/components/layout/AppLayout.vue'),
children: [
{ path: '', name: 'home', component: () => import('@/pages/Home.vue') },
{
path: 'dashboard',
name: 'dashboard',
component: () => import('@/pages/Dashboard.vue'),
meta: { requiresAuth: true },
},
{
path: 'users',
children: [
{ path: '', name: 'user-list', component: () => import('@/pages/users/UserList.vue') },
{ path: ':id', name: 'user-detail', component: () => import() },
],
},
],
},
{ : , : , : () },
{ : , : , : () },
];
router = ({
: (),
routes,
});
router;
// router/guards.ts
import type { Router } from 'vue-router';
import { useAuthStore } from '@/stores/modules/auth';
export function setupRouteGuards(router: Router) {
router.beforeEach(async (to, _from, next) => {
const authStore = useAuthStore();
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
next({ name: 'login', query: { redirect: to.fullPath } });
} else if (to.meta.guestOnly && authStore.isAuthenticated) {
next({ name: 'home' });
} else {
next();
}
});
}
pages/
├── index.vue → /
├── about.vue → /about
├── login.vue → /login
├── users/
│ ├── index.vue → /users
│ ├── [id].vue → /users/:id
│ └── [id]/
│ └── edit.vue → /users/:id/edit
└── [...slug].vue → /* (catch-all)
Nuxt 中间件:
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const authStore = useAuthStore();
if (!authStore.isAuthenticated) {
return navigateTo('/login', { redirectCode: 302 });
}
});
<!-- BaseCard.vue -->
<template>
<div class="rounded-lg border bg-white p-4 shadow-sm">
<header v-if="$slots.header" class="mb-3 border-b pb-2">
<slot name="header" />
</header>
<main>
<slot /> <!-- 默认插槽 -->
</main>
<footer v-if="$slots.footer" class="mt-3 border-t pt-2">
<slot name="footer" />
</footer>
</div>
</template>
<!-- 使用 -->
<BaseCard>
<template #header>
<h2>用户信息</h2>
</template>
<p>姓名:{{ user.name }}</p>
<template #footer>
<BaseButton @click="edit">编辑</BaseButton>
</template>
</BaseCard>
// 父组件 provide
import { provide, ref } from 'vue';
const theme = ref<'light' | 'dark'>('light');
provide('theme', theme);
provide('toggleTheme', () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
});
// 子/孙组件 inject
import { inject } from 'vue';
const theme = inject<Ref<'light' | 'dark'>>('theme');
const toggleTheme = inject<() => void>('toggleTheme');
// composables/useApi.ts
import { ref } from 'vue';
import type { Ref } from 'vue';
export function useApi<T>(apiFn: (...args: any[]) => Promise<T>) {
const data: Ref<T | null> = ref(null);
const loading = ref(false);
const error = ref<Error | null>(null);
async function execute(...args: any[]) {
loading.value = true;
error.value = null;
try {
data.value = await apiFn(...args);
return data.value;
} catch (err) {
error.value = err as Error;
throw err;
} finally {
loading.value = false;
}
}
{ data, loading, error, execute };
}
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';
import { fileURLToPath } from 'node:url';
export default defineConfig({
plugins: [vue()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./tests/setup.ts'],
include: ['tests/**/*.test.ts', 'src/**/*.test.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
},
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
});
// tests/setup.ts
import { config } from '@vue/test-utils';
config.global.mocks = {
$t: (key: string) => key, // i18n mock
$route: { path: '/' },
};
// tests/components/BaseButton.test.ts
import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import BaseButton from '@/components/ui/BaseButton.vue';
describe('BaseButton', () => {
it('renders slot content', () => {
const wrapper = mount(BaseButton, {
slots: { default: 'Click me' },
});
expect(wrapper.text()).toBe('Click me');
});
it('emits click event', async () => {
const wrapper = mount(BaseButton);
await wrapper.trigger('click');
expect(wrapper.emitted('click')).toHaveLength(1);
});
it('is disabled when loading', () => {
const wrapper = mount(BaseButton, {
props: { loading: },
});
(wrapper.()).();
});
});
// tailwind.config.ts
import type { Config } from 'tailwindcss';
export default {
content: [
'./index.html',
'./src/**/*.{vue,ts,tsx}',
],
theme: {
extend: {
colors: {
primary: { 50: '#eff6ff', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8' },
},
},
},
plugins: [require('@tailwindcss/forms')],
} satisfies Config;
// uno.config.ts
import { defineConfig, presetUno, presetAttributify, presetIcons } from 'unocss';
export default defineConfig({
presets: [
presetUno(),
presetAttributify(),
presetIcons({ scale: 1.2 }),
],
shortcuts: {
'btn': 'px-4 py-2 rounded-md font-medium transition-colors',
'btn-primary': 'btn bg-blue-600 text-white hover:bg-blue-700',
'btn-secondary': 'btn bg-gray-200 text-gray-900 hover:bg-gray-300',
},
});
# 创建 Vue 3 项目
创建一个 Vue 3 + Vite 项目,用于企业后台管理系统,使用 Element Plus + Pinia
# 创建 Nuxt 3 项目
创建一个 Nuxt 3 项目,用于技术博客,支持 SSR 和暗黑模式
# 添加功能模块
为项目添加用户管理模块,包含列表、详情、编辑页面
# 生成组件
生成一个 DataTable 组件,支持排序、分页、筛选,基于 Composition API
# 生成 composable
写一个 usePagination composable,支持分页逻辑复用
# 生成 store
写一个 useProductStore,包含商品的 CRUD 操作
Source: afine907/skills — distributed by TomeVault.