Разработка сайта на CMS Sanity

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка сайта на CMS Sanity
Средняя
~1-2 недели
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка сайта на CMS Sanity

Sanity — headless CMS с реальным временем, написанный на TypeScript. Контентная схема описывается в коде (TypeScript/JavaScript), Sanity Studio — кастомизируемый React-редактор. GROQ — собственный язык запросов, мощнее REST для сложных структур. Контент хранится в облаке Sanity (Content Lake), локальное хранение не поддерживается.

Архитектура

Sanity Studio (React SPA)    Next.js Frontend
         ↕                         ↕
   Content Lake (Sanity Cloud)
         ↕ GROQ / REST API
   CDN (image CDN встроен)

Sanity Studio — это React-приложение, которое деплоится отдельно или embed в Next.js. Studio — это не "admin panel из коробки" — она конфигурируется под каждый проект.

Создание проекта

npm create sanity@latest -- --template clean --create-project "My Site" --dataset production
# Создаст проект в sanity.io и локальную Studio

cd my-site
npm run dev  # Studio: http://localhost:3333

Схема документа

// schemas/post.ts
import { defineType, defineField } from 'sanity'

export const postType = defineType({
  name: 'post',
  title: 'Статья',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Заголовок',
      type: 'string',
      validation: rule => rule.required().min(5).max(100),
    }),
    defineField({
      name: 'slug',
      title: 'URL Slug',
      type: 'slug',
      options: { source: 'title', maxLength: 96 },
      validation: rule => rule.required(),
    }),
    defineField({
      name: 'author',
      type: 'reference',
      to: [{ type: 'author' }],
    }),
    defineField({
      name: 'mainImage',
      type: 'image',
      options: { hotspot: true },
      fields: [
        defineField({ name: 'alt', type: 'string', title: 'Alt text' }),
      ],
    }),
    defineField({
      name: 'categories',
      type: 'array',
      of: [{ type: 'reference', to: [{ type: 'category' }] }],
    }),
    defineField({
      name: 'publishedAt',
      type: 'datetime',
    }),
    defineField({
      name: 'body',
      type: 'blockContent',  // Portable Text
    }),
    defineField({
      name: 'excerpt',
      type: 'text',
      rows: 4,
    }),
  ],
  preview: {
    select: { title: 'title', author: 'author.name', media: 'mainImage' },
    prepare: ({ title, author, media }) => ({
      title,
      subtitle: author ? `by ${author}` : '',
      media,
    }),
  },
})

Конфигурация Studio

// sanity.config.ts
import { defineConfig } from 'sanity'
import { structureTool } from 'sanity/structure'
import { visionTool } from '@sanity/vision'
import { postType } from './schemas/post'
import { authorType } from './schemas/author'
import { categoryType } from './schemas/category'

export default defineConfig({
  name: 'default',
  title: 'My Site CMS',
  projectId: process.env.SANITY_STUDIO_PROJECT_ID!,
  dataset: 'production',
  plugins: [
    structureTool({
      structure: S => S.list()
        .title('Контент')
        .items([
          S.documentTypeListItem('post').title('Статьи'),
          S.documentTypeListItem('author').title('Авторы'),
          S.divider(),
          S.documentTypeListItem('category').title('Категории'),
        ]),
    }),
    visionTool(),  // GROQ playground
  ],
  schema: { types: [postType, authorType, categoryType] },
})

GROQ запросы

// Все опубликованные статьи с populate
*[_type == "post" && publishedAt < now() && !(_id in path("drafts.**"))] | order(publishedAt desc) [0...12] {
  _id,
  title,
  "slug": slug.current,
  publishedAt,
  excerpt,
  "mainImage": mainImage { ..., "url": asset->url, "blurHash": asset->metadata.blurHash },
  "author": author->{ name, "avatar": image.asset->url },
  "categories": categories[]->{ title, slug }
}

Интеграция с Next.js

npm install @sanity/client next-sanity @portabletext/react
// lib/sanity.ts
import { createClient } from '@sanity/client'
import imageUrlBuilder from '@sanity/image-url'

export const sanityClient = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production',
  apiVersion: '2024-01-01',
  useCdn: process.env.NODE_ENV === 'production',
  token: process.env.SANITY_API_TOKEN,  // для черновиков
})

const builder = imageUrlBuilder(sanityClient)
export const urlFor = (source: any) => builder.image(source)
// app/blog/[slug]/page.tsx
import { sanityClient, urlFor } from '@/lib/sanity'
import { PortableText } from '@portabletext/react'
import { notFound } from 'next/navigation'

const query = `*[_type == "post" && slug.current == $slug][0] {
  _id, title, publishedAt, body,
  "mainImage": mainImage { ..., "url": asset->url },
  "author": author->{ name },
  "categories": categories[]->{ title }
}`

export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await sanityClient.fetch(query, { slug: params.slug })
  if (!post) notFound()

  return (
    <article>
      <h1>{post.title}</h1>
      {post.mainImage?.url && (
        <img src={urlFor(post.mainImage).width(1200).height(630).url()} alt={post.title} />
      )}
      <PortableText value={post.body} />
    </article>
  )
}

export async function generateStaticParams() {
  const slugs = await sanityClient.fetch(`*[_type == "post"].slug.current`)
  return slugs.map((slug: string) => ({ slug }))
}

Типичный стек

Слой Технология
CMS Sanity 3.x
Studio Embedded в Next.js или отдельный деплой
Frontend Next.js 14 App Router
Изображения Sanity Image CDN (встроен)
Поиск GROQ / Algolia
Деплой Vercel (Next.js) + sanity.io (Studio)

Отличия от Strapi/Directus

  • Контент хранится только в Sanity Cloud (SaaS), нет self-hosted варианта с БД
  • GROQ-запросы мощнее REST для сложных структур данных
  • Real-time коллаборация в Studio из коробки
  • Portable Text — формат rich text с кастомными блоками
  • Платные планы: бесплатный (3 пользователя, 5 датасетов), платный от $15/мес

Сроки

Базовый сайт с 3–5 типами документов и Next.js фронтендом — 2–3 недели. Сложный проект с кастомными Studio плагинами и Visual Editing — 4–6 недель.