
דפוסים שאני משתמש בהם כדי לשמור על פרויקט Next.js App Router נקי: TypeScript מחמיר, תוכן שמגיע מ‑Sanity, שאילתות GROQ יציבות, ומה עושים כשה‑CMS משתנה מהר יותר מהקוד.
אפליקציות מונעות‑תוכן נשברות כשה‑schema משתנה וה‑UI לא עומד בקצב. המטרה שלי היא לשמור על Type Safety, בלי לעצור את מי שמנהל את התוכן ב‑Sanity.
- סכמות ברורות עם שדות חובה ו‑IDs יציבים.
- שאילתות GROQ מפורשות וצפויות.
- TypeScript שמכבד “תוכן חסר” (nullable) בצורה בטוחה.
- אמת ב‑CMS במקום fallback שמקודד בקוד.
- לטפל ב‑nulls ב‑UI, אבל לתקן תוכן ב‑Sanity.
- להוסיף שדות עם schema deploy ואז לבצע backfill לדוקומנטים.
- להשתמש ב‑CI/CD כדי לתפוס רגרסיות מוקדם.
- לשמור על SSG ככל האפשר כדי לקבל ביצועים צפויים.
1import { defineField, defineType } from 'sanity';
2
3// הגדרת schema עם תמיכה מלאה ב-TypeScript
4export const postSchema = defineType({
5 name: 'post',
6 title: 'Blog Post',
7 type: 'document',
8 fields: [
9 defineField({
10 name: 'title',
11 title: 'כותרת',
12 type: 'string',
13 validation: (Rule) => Rule.required().max(80),
14 }),
15 defineField({
16 name: 'slug',
17 title: 'Slug',
18 type: 'slug',
19 options: {
20 source: 'title',
21 maxLength: 96,
22 },
23 validation: (Rule) => Rule.required(),
24 }),
25 defineField({
26 name: 'content',
27 title: 'תוכן',
28 type: 'array',
29 of: [
30 { type: 'block' },
31 { type: 'image' },
32 { type: 'codeBlock' },
33 ],
34 }),
35 ],
36});1import { defineQuery } from 'next-sanity';
2import { sanityFetchStatic } from '@/sanity/lib/staticFetch';
3
4// ✅ שאילת GROQ עם defineQuery לזיהוי טיפוסים אוטומטי
5const POST_QUERY = defineQuery(`
6 *[_type == "post" && slug.current == $slug][0]{
7 title,
8 "slug": slug.current,
9 publishedAt,
10 "author": author->{
11 name,
12 image,
13 bio
14 },
15 content,
16 _updatedAt
17 }
18`);
19
20// TypeScript מזהה את סוג ההחזרה מהשאילתה!
21export async function getPost(slug: string) {
22 const post = await sanityFetchStatic({
23 query: POST_QUERY,
24 params: { slug },
25 });
26
27 // ✅ גישה type-safe: TypeScript יודע ש-post.author.name קיים
28 return post;
29}1import { z } from 'zod';
2
3// הגדרת Zod schema לאימות runtime
4const PostSchema = z.object({
5 _id: z.string(),
6 _type: z.literal('post'),
7 title: z.string().max(80),
8 slug: z.object({
9 current: z.string(),
10 }),
11 content: z.array(
12 z.discriminatedUnion('_type', [
13 z.object({
14 _type: z.literal('block'),
15 _key: z.string(),
16 }),
17 z.object({
18 _type: z.literal('codeBlock'),
19 _key: z.string(),
20 code: z.string(),
21 language: z.string(),
22 }),
23 ])
24 ),
25});
26
27type Post = z.infer<typeof PostSchema>;
28
29// אימות נתוני Sanity ב-runtime
30export function validatePost(data: unknown): Post {
31 try {
32 return PostSchema.parse(data);
33 } catch (error) {
34 if (error instanceof z.ZodError) {
35 console.error('אימות נתוני Sanity נכשל:', error.errors);
36 }
37 throw new Error('נתוני פוסט לא תקינים מ-Sanity');
38 }
39}רוצה ייעוץ? לחץ כאן לקביעת שיחה.
קבע שיחה
מדריך מעודכן ל-WebMCP: מה חדש ב-Early Preview של Chrome, איך מתחילים נכון, איך זה עוזר למפתחים ולמשתמשים, ומה ההבדל מול אינטגרציית MCP ב-backend.

כישורי סוכנים הופכים סוכן AI לאמין: תהליכים חוזרים, הגנות ברירת־מחדל ופחות "שיחות" עם הפרומפט. דוגמה מ‑Claude Code Skills וכללי React של Vercel לצמצום רגרסיות.

מדריך פרקטי לשיפור העבודה היומיומית: חיבור Slack, Jira, Monday.com ו‑GitHub באמצעות סוכני AI מבוססי MCP לקבלת התראות חכמות, סנכרון סטטוסים, לולאות פידבק לסקירות קוד ומשימות Follow‑up אוטומטיות.
בכל מקום שבו אתה נמצא, בוא נעבוד יחד על הפרויקט הבא שלך.
מעדיף לדבר ישירות? קבע שיחה ונדבר על הפרויקט שלך בלייב.
קבע שיחה