diff --git a/.github/skills/vercel-react-best-practices/AGENTS.md b/.github/skills/vercel-react-best-practices/AGENTS.md index f9b9e99..07b11fe 100644 --- a/.github/skills/vercel-react-best-practices/AGENTS.md +++ b/.github/skills/vercel-react-best-practices/AGENTS.md @@ -94,15 +94,15 @@ Move `await` operations into the branches where they're actually used to avoid b ```typescript async function handleRequest(userId: string, skipProcessing: boolean) { - const userData = await fetchUserData(userId) - + const userData = await fetchUserData(userId); + if (skipProcessing) { // Returns immediately but still waited for userData - return { skipped: true } + return { skipped: true }; } - + // Only this branch uses userData - return processUserData(userData) + return processUserData(userData); } ``` @@ -112,12 +112,12 @@ async function handleRequest(userId: string, skipProcessing: boolean) { async function handleRequest(userId: string, skipProcessing: boolean) { if (skipProcessing) { // Returns immediately without waiting - return { skipped: true } + return { skipped: true }; } - + // Fetch only when needed - const userData = await fetchUserData(userId) - return processUserData(userData) + const userData = await fetchUserData(userId); + return processUserData(userData); } ``` @@ -126,35 +126,35 @@ async function handleRequest(userId: string, skipProcessing: boolean) { ```typescript // Incorrect: always fetches permissions async function updateResource(resourceId: string, userId: string) { - const permissions = await fetchPermissions(userId) - const resource = await getResource(resourceId) - + const permissions = await fetchPermissions(userId); + const resource = await getResource(resourceId); + if (!resource) { - return { error: 'Not found' } + return { error: "Not found" }; } - + if (!permissions.canEdit) { - return { error: 'Forbidden' } + return { error: "Forbidden" }; } - - return await updateResourceData(resource, permissions) + + return await updateResourceData(resource, permissions); } // Correct: fetches only when needed async function updateResource(resourceId: string, userId: string) { - const resource = await getResource(resourceId) - + const resource = await getResource(resourceId); + if (!resource) { - return { error: 'Not found' } + return { error: "Not found" }; } - - const permissions = await fetchPermissions(userId) - + + const permissions = await fetchPermissions(userId); + if (!permissions.canEdit) { - return { error: 'Forbidden' } + return { error: "Forbidden" }; } - - return await updateResourceData(resource, permissions) + + return await updateResourceData(resource, permissions); } ``` @@ -169,25 +169,26 @@ For operations with partial dependencies, use `better-all` to maximize paralleli **Incorrect: profile waits for config unnecessarily** ```typescript -const [user, config] = await Promise.all([ - fetchUser(), - fetchConfig() -]) -const profile = await fetchProfile(user.id) +const [user, config] = await Promise.all([fetchUser(), fetchConfig()]); +const profile = await fetchProfile(user.id); ``` **Correct: config and profile run in parallel** ```typescript -import { all } from 'better-all' +import { all } from "better-all"; const { user, config, profile } = await all({ - async user() { return fetchUser() }, - async config() { return fetchConfig() }, + async user() { + return fetchUser(); + }, + async config() { + return fetchConfig(); + }, async profile() { - return fetchProfile((await this.$.user).id) - } -}) + return fetchProfile((await this.$.user).id); + }, +}); ``` Reference: [https://github.com/shuding/better-all](https://github.com/shuding/better-all) @@ -202,10 +203,10 @@ In API routes and Server Actions, start independent operations immediately, even ```typescript export async function GET(request: Request) { - const session = await auth() - const config = await fetchConfig() - const data = await fetchData(session.user.id) - return Response.json({ data, config }) + const session = await auth(); + const config = await fetchConfig(); + const data = await fetchData(session.user.id); + return Response.json({ data, config }); } ``` @@ -213,14 +214,11 @@ export async function GET(request: Request) { ```typescript export async function GET(request: Request) { - const sessionPromise = auth() - const configPromise = fetchConfig() - const session = await sessionPromise - const [config, data] = await Promise.all([ - configPromise, - fetchData(session.user.id) - ]) - return Response.json({ data, config }) + const sessionPromise = auth(); + const configPromise = fetchConfig(); + const session = await sessionPromise; + const [config, data] = await Promise.all([configPromise, fetchData(session.user.id)]); + return Response.json({ data, config }); } ``` @@ -235,19 +233,15 @@ When async operations have no interdependencies, execute them concurrently using **Incorrect: sequential execution, 3 round trips** ```typescript -const user = await fetchUser() -const posts = await fetchPosts() -const comments = await fetchComments() +const user = await fetchUser(); +const posts = await fetchPosts(); +const comments = await fetchComments(); ``` **Correct: parallel execution, 1 round trip** ```typescript -const [user, posts, comments] = await Promise.all([ - fetchUser(), - fetchPosts(), - fetchComments() -]) +const [user, posts, comments] = await Promise.all([fetchUser(), fetchPosts(), fetchComments()]); ``` ### 1.5 Strategic Suspense Boundaries @@ -260,8 +254,8 @@ Instead of awaiting data in async components before returning JSX, use Suspense ```tsx async function Page() { - const data = await fetchData() // Blocks entire page - + const data = await fetchData(); // Blocks entire page + return (