用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/InugamiDev/ultrathink-oss --skill graphql-codegen命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Unified design foundations — design system architecture, tokens, component specs, visual principles, creative vision, figma integration, plus brand design system loader (66 real brands via DESIGN.md). Absorbs design, design-system, design-systems, design-principles, design-router, creative-vision, figma, design-md.
Render, summarize, and present markdown documents and structured content in multiple output modes
Ultra UI skill - combines Google's DESIGN.md spec (machine-readable design tokens) with the ui-ux-pro-max knowledge base (91 styles, 161 palettes, 73 font pairings, 161 products, 104 UX guidelines, 25 chart types). Generates lint-clean DESIGN.md files, validates token references and WCAG contrast, exports Tailwind/DTCG tokens, and diffs design systems version-over-version.
正在显示 SKILL.md
基于 SOC 职业分类
| name | graphql-codegen |
| description | GraphQL code generation — typed operations, fragment colocation, and schema-first development. |
| layer | domain |
| category | tooling |
| triggers | ["graphql codegen","codegen","typed graphql","fragment colocation","gql.tada"] |
| inputs | ["GraphQL schema or operation definitions","Code generation configuration needs","Type-safe query/mutation patterns","Fragment colocation strategy questions"] |
| outputs | ["GraphQL codegen configuration files","Typed operations and fragment definitions","Custom scalar type mappings","Client-side cache integration patterns"] |
| linksTo | ["graphql","typescript-patterns"] |
| linkedFrom | [] |
| riskLevel | low |
| memoryReadPolicy | selective |
| memoryWritePolicy | none |
| sideEffects | [] |
Provide expert guidance on GraphQL code generation for type-safe client operations, fragment colocation, schema-first development, and integration with TypeScript. Covers GraphQL Codegen, gql.tada, and typed-document-node approaches.
codegen.ts configuration:
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
schema: process.env.GRAPHQL_SCHEMA_URL || "./schema.graphql",
documents: ["src/**/*.{ts,tsx}", "!src/gql/**/*"],
ignoreNoDocuments: true,
generates: {
"./src/gql/": {
preset: "client",
presetConfig: {
fragmentMasking: { unmaskFunctionName: "getFragmentData" },
},
config: {
scalars: {
DateTime: "string",
UUID: "string",
JSON: "Record<string, unknown>",
Decimal: "string",
},
enumsAsTypes: true,
skipTypename: false,
dedupeFragments: true,
nonOptionalTypename: ,
},
},
: {
: [],
: {
: ,
: ,
},
},
},
: {
: [],
},
};
config;
package.json scripts:
{
"scripts": {
"codegen": "graphql-codegen --config codegen.ts",
"codegen:watch": "graphql-codegen --config codegen.ts --watch"
}
}
Colocate fragments with the components that use them:
// components/UserCard.tsx
import { graphql, type FragmentType, getFragmentData } from "@/gql";
export const UserCardFragment = graphql(`
fragment UserCard on User {
id
name
email
avatarUrl
role
createdAt
}
`);
interface UserCardProps {
user: FragmentType<typeof UserCardFragment>;
}
export function UserCard({ user: userRef }: UserCardProps) {
const user = getFragmentData(UserCardFragment, userRef);
return (
<div className="p-6 rounded-xl shadow-sm border">
<img
src={user.avatarUrl}
alt={user.name}
className="w-12 h-12 rounded-full"
/>
<h3 className="text-lg font-semibold">{user.name}</h3>
<p className="text-sm text-gray-600">{user.email}</p>
</div>
);
}
Parent component composes fragments:
// pages/TeamPage.tsx
import { graphql } from "@/gql";
import { useQuery } from "@urql/react";
import { UserCard, UserCardFragment } from "@/components/UserCard";
const TeamQuery = graphql(`
query TeamMembers($teamId: ID!) {
team(id: $teamId) {
id
name
members {
...UserCard
}
}
}
`);
export function TeamPage({ teamId }: { teamId: string }) {
const [{ data, fetching }] = useQuery({
query: TeamQuery,
variables: { teamId },
});
if (fetching) return <Spinner />;
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{data?.team?.members.map((member) => (
<UserCard key={member.id} user={member} />
))}
</div>
);
}
Query with variables and error handling:
import { graphql } from "@/gql";
import { useQuery } from "@urql/react";
const OrdersQuery = graphql(`
query Orders($filters: OrderFiltersInput!, $pagination: PaginationInput!) {
orders(filters: $filters, pagination: $pagination) {
edges {
node {
id
status
totalFormatted
createdAt
items {
id
product {
name
}
quantity
}
}
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}
`);
export function useOrders(filters: OrderFiltersInput, cursor?: string) {
return useQuery({
query: OrdersQuery,
variables: {
filters,
pagination: { first: 20, after: cursor },
},
});
}
Mutation with optimistic update:
import { graphql } from "@/gql";
import { useMutation } from "@urql/react";
const UpdateOrderStatusMutation = graphql(`
mutation UpdateOrderStatus($input: UpdateOrderStatusInput!) {
updateOrderStatus(input: $input) {
order {
id
status
updatedAt
}
errors {
field
message
}
}
}
`);
export function useUpdateOrderStatus() {
const [result, executeMutation] = useMutation(UpdateOrderStatusMutation);
const updateStatus = async (orderId: string, status: OrderStatus) => {
const { data, error } = await executeMutation({
input: { orderId, status },
});
if (error) throw error;
if (data?.updateOrderStatus.errors?.length) {
throw new Error(data.updateOrderStatus.errors[0].message);
}
return data!.updateOrderStatus.order;
};
return { updateStatus, loading: result.fetching };
}
For projects preferring runtime inference over code generation:
// utils/graphql.ts
import { initGraphQLTada } from "gql.tada";
import type { introspection } from "@/graphql-env";
export const graphql = initGraphQLTada<{
introspection: introspection;
scalars: {
DateTime: string;
UUID: string;
JSON: Record<string, unknown>;
};
}>();
export type { FragmentOf, ResultOf, VariablesOf } from "gql.tada";
export { readFragment } from "gql.tada";
// No codegen step needed — types inferred at write-time
import { graphql, readFragment, type FragmentOf } from "@/utils/graphql";
const UserFragment = graphql(`
fragment UserFields on User {
id
name
email
}
`);
// TypeScript knows the shape automatically
type User = FragmentOf<typeof UserFragment>;
// codegen.ts scalar config
config: {
scalars: {
DateTime: {
input: "string", // what the server accepts
output: "string", // what the server returns
},
Money: {
input: "{ amount: number; currency: string }",
output: "{ amount: number; currency: string }",
},
Upload: "File",
Void: "void",
},
}
// codegen.ts — generate persisted query hashes
generates: {
"./src/gql/": {
preset: "client",
presetConfig: {
persistedDocuments: true, // generates documentId for each operation
},
},
"./persisted-documents.json": {
plugins: ["persisted-operations"],
},
}
// Client setup with automatic persisted queries
import { createClient, fetchExchange } from "@urql/core";
import { persistedExchange } from "@urql/exchange-persisted";
const client = createClient({
url: "/graphql",
exchanges: [
persistedExchange({
preferGetForPersistedQueries: true,
enforcePersistedQueries: true,
}),
fetchExchange,
],
});
// test/helpers/graphql.ts — type-safe mock factories
import type { OrdersQuery } from "@/gql/graphql";
type OrderNode = NonNullable<
OrdersQuery["orders"]
>["edges"][number]["node"];
export function buildMockOrder(overrides: Partial<OrderNode> = {}): OrderNode {
return {
__typename: "Order",
id: "order-1",
status: "PENDING",
totalFormatted: "$99.00",
createdAt: new Date().toISOString(),
items: [],
...overrides,
};
}
client preset — It generates a single graphql() function with fragment masking, simplifying imports.any types in generated output.graphql-codegen to your CI pipeline and fail on type errors.enumsAsTypes over TypeScript enums — String union types are more ergonomic than TS enums.dedupeFragments to avoid duplicate fragment definitions in operations.codegen:watch alongside your dev server for instant type updates.| Pitfall | Problem | Fix |
|---|---|---|
| Stale generated types | Types out of sync with schema | Run codegen in CI, use watch mode locally |
| Missing scalar mappings | Custom scalars typed as any | Configure all custom scalars in codegen config |
| No fragment colocation | Monolithic queries that over-fetch | Split into component-level fragments |
| Importing from wrong path | Using raw gql tag instead of generated | Always import graphql from @/gql |
| Fragment name collisions | Two fragments with the same name | Prefix fragments with component name: UserCard not User |
| Ignoring fragment masking | Accessing fields not in the component's fragment | Use getFragmentData() to unmask properly |
| No persisted queries | Arbitrary queries accepted by server | Enable persisted documents and enforce on server |
| Circular fragment deps | Codegen fails on circular references | Restructure fragments to avoid cycles |