Категории

Несколько билдов в одном Astro

🔹 Вариант 1. Два проекта внутри одного монорепо

  • Создаёшь в корне что-то вроде:
    /apps
      /site1
      /site2
    /packages
      /ui   (общие компоненты)
  • В apps/site1 и apps/site2 будут свои astro.config.mjs, страницы и сборка.
  • Общие компоненты подключаются через packages/ui.
  • Билд каждого проекта делается отдельно:
    cd apps/site1 && npm run build
    cd apps/site2 && npm run build
  • На деплое просто указываешь разные выходные папки (dist) на разные URL.

👉 Это самый гибкий и правильный способ, если проекты реально разные.


🔹 Вариант 2. Один проект, разные “режимы”

Если у тебя один astro-проект, но нужны два билда:

  • Можно завести несколько astro.config.mjs (например astro.config.site1.mjs и astro.config.site2.mjs).
  • В package.json прописать разные скрипты:
    {
      "scripts": {
        "build:site1": "astro build --config astro.config.site1.mjs",
        "build:site2": "astro build --config astro.config.site2.mjs"
      }
    }
  • В каждом конфиге указывать:
    • свой base или site для генерации ссылок,
    • разные entry-папки для страниц (src/pages_site1, src/pages_site2),
    • но общий доступ к компонентам (src/components).

🔹 Вариант 3. Один билд → разные домены

Если проекты отличаются только роутингом или контентом, можно:

  • Сгенерировать один билд и раздавать его под разными URL через настройки хостинга/прокси.
  • Но это подходит только если проекты почти идентичные.

✅ Итого: да, в Astro можно держать несколько “проектов” в одном репо и даже собирать их из одних и тех же компонентов. Выбор подхода зависит от того, насколько сильно эти проекты должны различаться.

Отлично 👍
Если контент отличается, а дизайн и компоненты общие — тебе подойдёт вариант 2 с двумя конфигами. Ниже пример структуры и настроек.


📁 Структура проекта

project/
├─ src/
│  ├─ components/      # общие компоненты
│  ├─ pages_site1/     # страницы первого сайта
│  ├─ pages_site2/     # страницы второго сайта
│  └─ layouts/         # общие лейауты
├─ astro.config.site1.mjs
├─ astro.config.site2.mjs
├─ package.json

⚙️ Конфиги

astro.config.site1.mjs

import { defineConfig } from "astro/config";

export default defineConfig({
  root: "./src/pages_site1", // где искать страницы
  outDir: "./dist/site1", // куда билдить
  site: "https://site1.example.com", // URL для генерации ссылок
});

astro.config.site2.mjs

import { defineConfig } from "astro/config";

export default defineConfig({
  root: "./src/pages_site2",
  outDir: "./dist/site2",
  site: "https://site2.example.com",
});

📜 Скрипты в package.json

{
  "scripts": {
    "dev:site1": "astro dev --config astro.config.site1.mjs",
    "dev:site2": "astro dev --config astro.config.site2.mjs",
    "build:site1": "astro build --config astro.config.site1.mjs",
    "build:site2": "astro build --config astro.config.site2.mjs"
  }
}

✅ Как это работает

  • npm run dev:site1 → поднимается dev-сервер для первого сайта.
  • npm run dev:site2 → dev-сервер второго.
  • После билда ты получаешь:
    dist/
      site1/
      site2/
    которые можно залить на разные URL.

👉 В src/components/ и src/layouts/ кладёшь общие части.
👉 В src/pages_site1/ и src/pages_site2/ кладёшь уникальные страницы и контент.
👉 Если нужен общий контент (например Markdown-посты) — можно завести ещё src/content/ и подключать оттуда.


Отличный вопрос 👌

Для локальной разработки у тебя будет два дев-сервера, каждый со своим конфигом. То есть ты выбираешь, какой проект сейчас разрабатывать.


🔹 Вариант 1. Запуск через скрипты

В package.json мы уже прописали:

{
  "scripts": {
    "dev:site1": "astro dev --config astro.config.site1.mjs --port 4321",
    "dev:site2": "astro dev --config astro.config.site2.mjs --port 4322"
  }
}
  • npm run dev:site1 → поднимается сервер для сайта 1 (например на http://localhost:4321).
  • npm run dev:site2 → поднимается сервер для сайта 2 (например на http://localhost:4322).

👉 Порты лучше указать разные, иначе Astro будет ругаться на конфликт.


🔹 Вариант 2. Параллельный запуск

Если хочется одновременно держать оба проекта поднятыми, можно поставить concurrently:

npm install concurrently --save-dev

И добавить в package.json:

{
  "scripts": {
    "dev:site1": "astro dev --config astro.config.site1.mjs --port 4321",
    "dev:site2": "astro dev --config astro.config.site2.mjs --port 4322",
    "dev:all": "concurrently \"npm run dev:site1\" \"npm run dev:site2\""
  }
}

Теперь npm run dev:all запустит оба проекта одновременно.


🔹 Вариант 3. Monorepo (NX / Turborepo / pnpm workspaces)

Если захочешь разнести сайты по папкам /apps/site1 и /apps/site2, то дев-серверы будут запускаться отдельно из каждой папки. Это чуть более “enterprise”, но и чище для больших проектов.


Да, всё верно 👍
В одном Astro-проекте ты можешь держать несколько конфигураций билдов, хоть десяток.

Astro устроен так, что:

🔹 Почему это работает

  • Изоляция билдов
    Каждый билд использует свой astro.config.*.mjs и собирается в свою папку (dist/site1, dist/site2, …). Поэтому никакого конфликта нет — сборки полностью независимы.
  • Компоненты на React / Vue / Svelte / Solid и т.д.
    Astro рендерит их в “острова” (islands). Каждый остров получает свою среду выполнения, поэтому React-компоненты не пересекаются с Vue или Svelte.
    Даже если ты в site1 используешь React, а в site2 — Vue, это будет работать без проблем.
  • Оптимизация бандла
    При сборке Astro автоматически включит только те зависимости, которые реально нужны конкретному сайту. Например, если в site1 у тебя нет Vue-компонентов, Vue в бандл не попадёт.

🔹 Возможные нюансы

  • Если у тебя общие компоненты (например src/components/Button.astro) и они зависят от конкретного фреймворка, то при сборке других сайтов этот фреймворк может подтянуться.
    👉 Решается разделением: components/react/, components/vue/, и подключаешь только нужное.
  • Если используешь разные CSS-фреймворки (например Tailwind и UnoCSS в разных сайтах) — тогда лучше держать отдельные конфиги (иначе могут наложиться стили).

🔹 Вывод

👉 Да, можно в одном Astro-проекте держать несколько билдов, хоть на разные домены.
👉 Конфликтов между React / Vue / Svelte не будет — Astro сам разделяет их окружения.
👉 Главное — грамотно организовать структуру и конфиги, чтобы каждая сборка тянула только нужное.


О, супер-идея 🚀
Astro как раз отлично подходит для подхода “constructor / design system → несколько сайтов”. Ты можешь держать общую библиотеку компонентов, а затем собирать из них разные билды (сайты), каждый со своим контентом и конфигом.


📁 Структура проекта с 3 сайтами

Пример: один сайт на React-компонентах, второй на Vue, третий — чисто на Markdown+Astro.

project/
├─ src/
│  ├─ components/
│  │  ├─ ui/           # универсальные Astro-компоненты
│  │  ├─ react/        # React-компоненты
│  │  ├─ vue/          # Vue-компоненты
│  │  └─ svelte/       # (по желанию)
│  ├─ layouts/         # общие лейауты
│  ├─ pages_site1/     # сайт 1 (React)
│  ├─ pages_site2/     # сайт 2 (Vue)
│  ├─ pages_site3/     # сайт 3 (Markdown)
│  └─ content/         # общий контент (md/mdx)
├─ astro.config.site1.mjs
├─ astro.config.site2.mjs
├─ astro.config.site3.mjs
├─ package.json

⚙️ Конфиги

astro.config.site1.mjs — сайт с React

import { defineConfig } from "astro/config";
import react from "@astrojs/react";

export default defineConfig({
  root: "./src/pages_site1",
  outDir: "./dist/site1",
  integrations: [react()],
  site: "https://site1.example.com",
});

astro.config.site2.mjs — сайт с Vue

import { defineConfig } from "astro/config";
import vue from "@astrojs/vue";

export default defineConfig({
  root: "./src/pages_site2",
  outDir: "./dist/site2",
  integrations: [vue()],
  site: "https://site2.example.com",
});

astro.config.site3.mjs — чисто Markdown + Astro

import { defineConfig } from "astro/config";

export default defineConfig({
  root: "./src/pages_site3",
  outDir: "./dist/site3",
  site: "https://site3.example.com",
});

📜 package.json

{
  "scripts": {
    "dev:site1": "astro dev --config astro.config.site1.mjs --port 4321",
    "dev:site2": "astro dev --config astro.config.site2.mjs --port 4322",
    "dev:site3": "astro dev --config astro.config.site3.mjs --port 4323",
    "build:site1": "astro build --config astro.config.site1.mjs",
    "build:site2": "astro build --config astro.config.site2.mjs",
    "build:site3": "astro build --config astro.config.site3.mjs"
  }
}

🔨 Использование конструктора

  • В /src/components/ui/ кладёшь “чистые” Astro-компоненты (Header.astro, Footer.astro, Card.astro).
  • В /src/components/react/ и /src/components/vue/ — более сложные интерактивные элементы.
  • В каждой pages_siteX ты собираешь страницы из этого конструктора:
    ---
    import Header from '../components/ui/Header.astro';
    import FancyChart from '../components/react/FancyChart.jsx';
    ---
    <Header title="Мой React-сайт" />
    <FancyChart />

Astro при сборке:

  • В site1 подтянет React и только те компоненты, что реально нужны.
  • В site2 подтянет Vue и только используемые компоненты.
  • В site3 не будет ни React, ни Vue (только Astro + Markdown).

✅ Что это даёт

  • Единый набор компонентов = меньше дублирования.
  • Можно делать новые сайты “из кубиков”, не копируя код.
  • Каждая сборка остаётся изолированной → нет конфликтов React/Vue/Svelte.
  • Проект масштабируется: можно хоть 10 билдов собрать.

Крутой вопрос 🙌
Если ты делаешь конструктор и хочешь собирать сайты из «кубиков», то репо действительно может быстро раздуться. Но есть несколько способов держать его в порядке.


🔹 Как не разрастить репо

  1. Монорепо-подход
    Вместо одного жирного Astro-проекта можно завести структуру вида:

    /apps
      /site1
      /site2
      /site3
    /packages
      /ui         # общие Astro-компоненты
      /blocks     # готовые секции (hero, gallery, form и т.п.)
      /content    # общий контент (md/mdx, json, yml)

    → Тогда новые сайты живут в /apps, а компоненты переиспользуются из /packages.

  2. Хранить контент отдельно

    • Саму «сборку» сайтов держать в Astro-репо.
    • А контент (JSON/MD/MDX/другой формат) можно вынести в отдельный репозиторий или CMS (например Sanity, Contentful, Strapi).
    • Astro будет просто подтягивать данные во время билда.
  3. Компоненты-«кирпичи»

    • Вместо копипаста страниц — делать универсальные блоки: Hero.astro, Features.astro, CTA.astro.
    • Страницы описывать декларативно в JSON/MDX → меньше кода, меньше дублирования.

🔹 Пример: генерация страницы из JSON

/src/content/pages/landing.json

{
  "title": "Главная страница",
  "blocks": [
    {
      "type": "Hero",
      "props": { "title": "Добро пожаловать", "subtitle": "Сайт №1" }
    },
    {
      "type": "Features",
      "props": { "items": ["Быстро", "Удобно", "Надёжно"] }
    },
    { "type": "CTA", "props": { "button": "Попробовать" } }
  ]
}

/src/pages/[slug].astro

---
import blocks from '../components/blocks'; // словарь: { Hero, Features, CTA }
import pageData from '../content/pages/landing.json';

const { title, blocks: pageBlocks } = pageData;
---

<html>
  <head><title>{title}</title></head>
  <body>
    {pageBlocks.map(({ type, props }) => {
      const Block = blocks[type];
      return <Block {...props} />;
    })}
  </body>
</html>

/src/components/blocks/index.js

import Hero from "./Hero.astro";
import Features from "./Features.astro";
import CTA from "./CTA.astro";

export default { Hero, Features, CTA };

🔹 Вариант с MD/MDX (для себя)

Astro уже из коробки поддерживает Markdown:

src/content/blog/post1.md
src/content/pages/landing.mdx

А ты можешь их обогащать JSX/компонентами.

post1.md:

---
title: "Первый пост"
date: "2025-09-09"
---

Привет! Это мой первый пост.  
<Hero title="MDX блок внутри Markdown" />

🔹 Вариант с CMS (для заказчиков)

Astro умеет подключаться к любым headless CMS через fetch/SDK:

Популярные варианты:

  • Sanity → удобно для структурированного контента (гибкая схема).
  • Contentful → стабильная SaaS CMS, UI понятен заказчикам.
  • Strapi → self-hosted, если нужен полный контроль.
  • Directus → похож на Strapi, но очень простой UI.

Пример (Astro + Sanity):

// src/lib/sanity.js
import { createClient } from "@sanity/client";

export const client = createClient({
  projectId: "xxxx",
  dataset: "production",
  apiVersion: "2025-09-01",
  useCdn: true,
});
---
import { client } from "../lib/sanity";

const posts = await client.fetch(`*[_type == "post"]{title, body}`);
---

<ul>
  {posts.map(post => <li>{post.title}</li>)}
</ul>

🔹 Гибридная модель

Ты можешь настроить разные источники в одном проекте:

  • MD/MDX для системных страниц (тебе удобно быстро править).
  • CMS для заказчика → он меняет контент без Git.

Например:

  • src/content/pages/*.mdx — твои тестовые страницы.
  • CMS (Sanity/Contentful) → блог/портфолио/новости, которые заказчик меняет.

Astro всё это стянет во время билда → сайты собираются в единый билд.