diff --git a/.agents/skills/vercel-react-best-practices/AGENTS.md b/.agents/skills/vercel-react-best-practices/AGENTS.md index 4e340a5..26c329d 100644 --- a/.agents/skills/vercel-react-best-practices/AGENTS.md +++ b/.agents/skills/vercel-react-best-practices/AGENTS.md @@ -118,7 +118,7 @@ This is a specialization of [Defer Await Until Needed](./async-defer-await.md) f **Incorrect:** ```typescript -const someFlag = await getFlag() +const someFlag = await getFlag(); if (someFlag && someCondition) { // ... @@ -129,7 +129,7 @@ if (someFlag && someCondition) { ```typescript if (someCondition) { - const someFlag = await getFlag() + const someFlag = await getFlag(); if (someFlag) { // ... } @@ -150,15 +150,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); } ``` @@ -168,12 +168,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); } ``` @@ -182,35 +182,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); } ``` @@ -227,38 +227,39 @@ 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); + }, +}); ``` **Alternative without extra dependencies:** ```typescript -const userPromise = fetchUser() -const profilePromise = userPromise.then(user => fetchProfile(user.id)) +const userPromise = fetchUser(); +const profilePromise = userPromise.then((user) => fetchProfile(user.id)); const [user, config, profile] = await Promise.all([ userPromise, fetchConfig(), - profilePromise -]) + profilePromise, +]); ``` We can also create all the promises first, and do `Promise.all()` at the end. @@ -275,10 +276,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 }); } ``` @@ -286,14 +287,14 @@ export async function GET(request: Request) { ```typescript export async function GET(request: Request) { - const sessionPromise = auth() - const configPromise = fetchConfig() - const session = await sessionPromise + 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 }) + fetchData(session.user.id), + ]); + return Response.json({ data, config }); } ``` @@ -308,9 +309,9 @@ 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** @@ -319,8 +320,8 @@ const comments = await fetchComments() const [user, posts, comments] = await Promise.all([ fetchUser(), fetchPosts(), - fetchComments() -]) + fetchComments(), +]); ``` ### 1.6 Strategic Suspense Boundaries @@ -333,8 +334,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 (