Корпоративный сайт — визитная карточка бизнеса. Его цели: создать доверие, предоставить информацию и привлечь клиентов. Astro идеально подходит: молниеносная загрузка, отличное SEO, простое управление контентом через Headless CMS.
Почему Astro для корпоративного сайта?
- PageSpeed 100 — скорость влияет на конверсию и SEO
- Безопасность — нет PHP, нет БД в боевом контуре
- Стоимость — Cloudflare Pages бесплатно или ~$5/мес
- Управление контентом — Headless CMS для нетехнических редакторов
- SEO — структурированные данные, ситмап, канонические URL из коробки
Типовая структура корпоративного сайта
company-site/
├── src/
│ ├── content/
│ │ ├── pages/ # Статичные страницы (Услуги, О нас)
│ │ ├── news/ # Новости и пресс-релизы
│ │ ├── cases/ # Кейсы / Портфолио
│ │ └── team/ # Команда
│ ├── pages/
│ │ ├── index.astro # Главная
│ │ ├── about.astro # О компании
│ │ ├── services/
│ │ │ ├── index.astro # Все услуги
│ │ │ └── [slug].astro# Страница услуги
│ │ ├── cases/
│ │ │ ├── index.astro # Кейсы
│ │ │ └── [slug].astro# Детальный кейс
│ │ ├── news/
│ │ │ ├── index.astro # Новости
│ │ │ └── [slug].astro# Новость
│ │ ├── team.astro # Команда
│ │ ├── contacts.astro # Контакты + форма
│ │ └── careers.astro # Вакансии
│ └── components/
│ ├── Header.astro
│ ├── Footer.astro
│ ├── Hero.astro
│ ├── ServiceCard.astro
│ ├── CaseCard.astro
│ ├── TeamMember.astro
│ └── ContactForm.tsx # Preact-остров Content Collections для всех разделов
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
// Услуги
const services = defineCollection({
loader: glob({ pattern: '**/*.mdx', base: './src/content/services' }),
schema: ({ image }) =>
z.object({
title: z.string(),
shortDescription: z.string().max(200),
icon: z.string(), // material-symbols имя иконки
cover: image().optional(),
featured: z.boolean().default(false),
order: z.number().default(999),
}),
});
// Кейсы
const cases = defineCollection({
loader: glob({ pattern: '**/*.mdx', base: './src/content/cases' }),
schema: ({ image }) =>
z.object({
title: z.string(),
client: z.string(),
industry: z.string(),
result: z.string(), // Ключевой результат одной строкой
tags: z.array(z.string()),
cover: image(),
date: z.coerce.date(),
featured: z.boolean().default(false),
}),
});
// Новости
const news = defineCollection({
loader: glob({ pattern: '**/*.mdx', base: './src/content/news' }),
schema: z.object({
title: z.string(),
description: z.string(),
date: z.coerce.date(),
category: z.enum(['Новость', 'Пресс-релиз', 'Событие']),
draft: z.boolean().default(false),
}),
});
// Команда
const team = defineCollection({
loader: glob({ pattern: '**/*.mdx', base: './src/content/team' }),
schema: ({ image }) =>
z.object({
name: z.string(),
position: z.string(),
photo: image(),
linkedin: z.string().url().optional(),
email: z.string().email().optional(),
order: z.number().default(999),
}),
});
export const collections = { services, cases, news, team }; Главная страница
---
// src/pages/index.astro
import { getCollection } from 'astro:content';
import BaseLayout from '../layouts/BaseLayout.astro';
import Hero from '../components/Hero.astro';
import ServiceCard from '../components/ServiceCard.astro';
import CaseCard from '../components/CaseCard.astro';
import ContactForm from '../components/ContactForm.tsx';
// Данные из Content Collections
const services = await getCollection('services', (s) => s.data.featured);
const cases = await getCollection('cases', (c) => c.data.featured);
const sortedServices = services.sort((a, b) => a.data.order - b.data.order);
---
<BaseLayout
title="Название компании — Описание деятельности"
description="Чем занимается компания, её ключевые преимущества"
>
<!-- Hero: ценностное предложение -->
<Hero
headline="Разрабатываем цифровые продукты для бизнеса"
subheadline="200+ проектов с 2015 года. От стартапа до enterprise"
cta={{ label: 'Обсудить проект', href: '#contact' }}
/>
<!-- Услуги -->
<section id="services">
<h2>Что мы делаем</h2>
<div class="grid grid-cols-3">
{
sortedServices.map((s) => (
<ServiceCard
title={s.data.title}
description={s.data.shortDescription}
icon={s.data.icon}
slug={s.id.replace('.mdx', '')}
/>
))
}
</div>
</section>
<!-- Кейсы -->
<section id="cases">
<h2>Наши проекты</h2>
<div class="grid grid-cols-2">
{cases.map((c) => <CaseCard case={c} />)}
</div>
<a href="/cases/">Все проекты →</a>
</section>
<!-- Форма контакта — Preact-остров -->
<section id="contact">
<h2>Обсудим ваш проект</h2>
<ContactForm
client:visible
fields={['name', 'company', 'email', 'phone', 'message']}
submitTo="/api/contact"
/>
</section>
</BaseLayout> Structured Data (JSON-LD) для компании
---
// src/layouts/BaseLayout.astro
const organizationSchema = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Название компании',
url: 'https://company.ru',
logo: 'https://company.ru/logo.png',
contactPoint: {
'@type': 'ContactPoint',
telephone: '+7-XXX-XXX-XX-XX',
contactType: 'sales',
availableLanguage: 'Russian',
},
address: {
'@type': 'PostalAddress',
addressLocality: 'Москва',
addressCountry: 'RU',
},
sameAs: [
'https://vk.com/company',
'https://t.me/company',
'https://linkedin.com/company/company',
],
};
---
<script type="application/ld+json" set:html={JSON.stringify(organizationSchema)} /> Headless CMS для редакторов
Для нетехнических редакторов контента подключите Keystatic или Decap CMS:
# Keystatic — Git-based, работает локально
npm install @keystatic/core @keystatic/astro Редакторы получают удобный визуальный интерфейс, а контент хранится в Git — никаких баз данных в боевом контуре.
Подробнее — в статье Headless CMS для Astro.
Форма обратной связи с Telegram-уведомлениями
// src/pages/api/contact.ts
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const data = await request.json();
const { name, company, email, phone, message } = data;
// Отправка в Telegram через Bot API
const botToken = import.meta.env.TELEGRAM_BOT_TOKEN;
const chatId = import.meta.env.TELEGRAM_CHAT_ID;
const text = `
🔔 *Новая заявка с сайта*
👤 *Имя:* ${name}
🏢 *Компания:* ${company || 'Не указана'}
📧 *Email:* ${email}
📱 *Телефон:* ${phone || 'Не указан'}
💬 *Сообщение:*
${message}
`.trim();
await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
text,
parse_mode: 'Markdown',
}),
});
return new Response(JSON.stringify({ ok: true }));
}; Мультиязычность (i18n)
Для международных компаний — встроенный i18n Astro:
// astro.config.mjs
export default defineConfig({
i18n: {
defaultLocale: 'ru',
locales: ['ru', 'en'],
routing: {
prefixDefaultLocale: false, // /ru/ убрать, /en/ оставить
},
},
}); src/pages/
├── index.astro → https://company.ru/
├── en/
│ └── index.astro → https://company.ru/en/ SEO для корпоративного сайта
Ключевые точки:
- Главная →
WebSite+OrganizationJSON-LD - Услуги →
ServiceJSON-LD с описанием и ценой - Кейсы →
ArticleилиCreativeWorkJSON-LD - Команда →
PersonJSON-LD для каждого сотрудника - Контакты →
ContactPageJSON-LD с адресом и телефоном
Деплой и обновление контента
Рабочий процесс:
- Редактор вносит изменения через CMS (Keystatic/Decap)
- Изменения коммитятся в Git
- GitHub Actions или Cloudflare Pages автоматически пересобирают сайт (~30-60 сек)
- Изменения видны пользователям
# .github/workflows/deploy.yml
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
projectName: company-site
directory: dist Итог
Корпоративный сайт на Astro — современная альтернатива WordPress для бизнеса. PageSpeed 100, встроенная безопасность, минимальный хостинг и удобная CMS для редакторов делают этот стек оптимальным для компаний любого размера. Начните с нескольких страниц и расширяйте по мере роста.