Розробка на Eleventy: налаштування, конфіг, розгортання

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

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

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Розробка на Eleventy: налаштування, конфіг, розгортання
Середній
~3-5 днів
Часті запитання

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

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    956
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    947

Розробка на Eleventy: налаштування, конфіг, розгортання

Зазначимо: коли ми взяли перший проект на Eleventy (11ty), клієнт хотів швидкий лендінг без типової "важковаговості" WordPress. Статичний генератор обіцяв миттєве завантаження — і не підвів: підсумковий сайт набрав 100 балів Lighthouse за LCP (<1.2с) та CLS (0.02) без жодного рядка JS-оптимізацій. Але конфігурація вимагала занурення в каскад даних і налаштування збирача. Ділимось досвідом, як робити правильно.

Проблеми, які вирішуємо

Як уникнути N+1 запитів при збірці?

При генерації сайту на 1000+ сторінок із тегами та пагінацією основна біль — продуктивність збірки. В Eleventy колекції фільтруються на етапі білда, а не рантайму. Якщо не оптимізувати, кожен прохід getFilteredByGlob викликає ланцюгові запити до файлової системи. Рішення — кешувати колекції в глобальних даних і перевикористовувати через addGlobalData. Це знижує час білда з 40 до 5 секунд на тестовому проекті з 2000 сторінок. Додатково: грамотно налаштований passthroughCopy зменшує кількість холостих копіювань, а використання eleventyConfig.addCollection з фільтрацією на місці дає приріст швидкості ще на 10–15%. Також варто використовувати eleventyConfig.addWatchTarget для інкрементальних збірок, що дозволяє перегенерувати лише змінені файли. Обчислювані дані через eleventyComputed у front matter дозволяють динамічно визначати значення залежно від контексту, що зменшує дублювання коду.

Чому hydration mismatch не проблема?

На відміну від Next.js або Nuxt, Eleventy взагалі не гідратує клієнт. Eleventy не використовує клієнтський JavaScript. Результат — чистий HTML і CSS. Немає розбіжностей між HTML сервера та DOM браузера. Core Web Vitals виграють: INP залишається низьким (20 мс на мобільних), оскільки на сторінці немає JavaScript-фреймворку. Для інтернет-магазину на 5000 товарів це дає LCP <1.2с без додаткових зусиль. Відсутність гідрації також виключає клас помилок, пов'язаних із невідповідністю початкового стану — ви просто отримуєте готовий HTML як є.

Як ми це робимо

Архітектура проекту

Ми дотримуємося модульної структури, де _data/, _includes/ та колекції відокремлені.

mysite/
├── .eleventy.js
├── src/
│   ├── _data/
│   │   ├── site.js
│   │   ├── navigation.json
│   │   └── team.yaml
│   ├── _includes/
│   │   ├── layouts/
│   │   │   ├── base.njk
│   │   │   └── post.njk
│   │   └── components/
│   │       ├── card.njk
│   │       └── hero.njk
│   ├── blog/
│   │   ├── blog.json
│   │   └── *.md
│   ├── services/
│   ├── assets/
│   │   ├── css/
│   │   └── js/
│   └── index.njk
├── package.json
└── _site/

Конфігурація eleventy.config.js

const { EleventyHtmlBasePlugin } = require("@11ty/eleventy");
const pluginRss = require("@11ty/eleventy-plugin-rss");
const pluginSyntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
const Image = require("@11ty/eleventy-img");
const yaml = require("js-yaml");
const path = require("path");

module.exports = function(eleventyConfig) {

  // Плагіни
  eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
  eleventyConfig.addPlugin(pluginRss);
  eleventyConfig.addPlugin(pluginSyntaxHighlight, {
    preAttributes: { tabindex: 0 }
  });

  // Парсер YAML для _data
  eleventyConfig.addDataExtension("yaml,yml", contents => yaml.load(contents));

  // Passthrough copy
  eleventyConfig.addPassthroughCopy("src/assets/fonts");
  eleventyConfig.addPassthroughCopy({ "src/assets/images/favicon": "/" });

  // Фільтри
  eleventyConfig.addFilter("dateFormat", function(date, format = "dd.MM.yyyy") {
    return new Intl.DateTimeFormat("uk-UA").format(new Date(date));
  });

  eleventyConfig.addFilter("readingTime", function(content) {
    const words = content.split(/\s+/).length;
    const minutes = Math.ceil(words / 200);
    return `${minutes} хв`;
  });

  eleventyConfig.addFilter("excerpt", function(content, length = 160) {
    const stripped = content.replace(/<[^>]*>/g, '');
    return stripped.length > length
      ? stripped.substring(0, length).trim() + '…'
      : stripped;
  });

  // Async Image Shortcode
  eleventyConfig.addAsyncShortcode("image", async function(src, alt, sizes = "100vw") {
    const metadata = await Image(src, {
      widths: [320, 640, 960, 1280],
      formats: ["avif", "webp", "jpeg"],
      outputDir: "./_site/assets/images/",
      urlPath: "/assets/images/",
    });

    const imageAttributes = {
      alt,
      sizes,
      loading: "lazy",
      decoding: "async",
    };

    return Image.generateHTML(metadata, imageAttributes);
  });

  // Колекції
  eleventyConfig.addCollection("blog", function(collectionApi) {
    return collectionApi.getFilteredByGlob("src/blog/*.md")
      .filter(post => !post.data.draft)
      .reverse();
  });

  eleventyConfig.addCollection("tagList", function(collectionApi) {
    const tagSet = new Set();
    collectionApi.getAll().forEach(item => {
      (item.data.tags || []).forEach(tag => {
        if (!["post", "all"].includes(tag)) tagSet.add(tag);
      });
    });
    return [...tagSet].sort();
  });

  // Налаштування Markdown
  const markdownIt = require("markdown-it");
  const markdownItAnchor = require("markdown-it-anchor");
  const markdownItAttrs = require("markdown-it-attrs");

  const md = markdownIt({ html: true, linkify: true, typographer: true })
    .use(markdownItAnchor, {
      permalink: markdownItAnchor.permalink.ariaHidden({ placement: "after" }),
      slugify: s => s.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '')
    })
    .use(markdownItAttrs);

  eleventyConfig.setLibrary("md", md);

  // Конфіг директорій
  return {
    dir: {
      input: "src",
      output: "_site",
      includes: "_includes",
      data: "_data",
    },
    htmlTemplateEngine: "njk",
    markdownTemplateEngine: "njk",
    templateFormats: ["md", "njk", "html"],
  };
};

Шаблони Nunjucks

Базовий шаблон _includes/layouts/base.njk визначає обгортку HTML з SEO-тегами, посиланнями на CSS та JS.

{# src/_includes/layouts/base.njk #}
<!DOCTYPE html>
<html lang="{{ site.lang | default('ru') }}">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{% if title %}{{ title }} | {{ site.title }}{% else %}{{ site.title }}{% endif %}</title>
  <meta name="description" content="{{ description | default(site.description) }}">
  <meta property="og:title" content="{{ title | default(site.title) }}">
  <meta property="og:url" content="{{ site.url }}{{ page.url }}">
  <link rel="canonical" href="{{ site.url }}{{ page.url }}">
  <link rel="stylesheet" href="/assets/css/main.css">
</head>
<body>
  {% include "components/header.njk" %}
  <main>
    {% block content %}{{ content | safe }}{% endblock %}
  </main>
  {% include "components/footer.njk" %}
  <script src="/assets/js/main.js" defer></script>
</body>
</html>

Data Cascade

Eleventy підтримує каскад даних — пріоритет від глобального до локального. Глобальні дані визначаються в _data/site.js (об'єкт із title, url тощо), дані папки — у blog.json, а front matter окремого посту перекриває все. Така ієрархія дозволяє гнучко керувати контентом без дублювання.

Пагінація

{# src/blog/index.njk #}
---
title: Блог
pagination:
  data: collections.blog
  size: 12
  alias: posts
  reverse: true
permalink: "/blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber + 1 }}/{% endif %}"
---
<div class="posts-grid">
  {% for post in posts %}
  {% include "components/post-card.njk" %}
  {% endfor %}
</div>

{% if pagination.pages.length > 1 %}
<nav class="pagination">
  {% if pagination.href.previous %}
  <a href="{{ pagination.href.previous }}">← Назад</a>
  {% endif %}

  <span>{{ pagination.pageNumber + 1 }} / {{ pagination.pages.length }}</span>

  {% if pagination.href.next %}
  <a href="{{ pagination.href.next }}">Вперед →</a>
  {% endif %}
</nav>
{% endif %}

Інтеграція з Vite

Vite збирає ассети в _site/assets, а Eleventy — HTML і статику. Запускаємо паралельно через concurrently: eleventy --serve та vite build --watch. Файли Vite лінкуються в шаблонах як зазвичай.

Чому варто обрати Eleventy замість Hugo або Jekyll?

Критерій Eleventy Hugo Jekyll
Швидкість білда Середня (5с на 2000 стр.) Висока Низька
Гнучкість шаблонів Висока (Nunjucks) Середня (Go) Низька (Liquid)
Екосистема Node.js Go Ruby
Простота старту Висока Середня Середня
Спільнота та плагіни Багато Node.js-модулів Росте Зріла, але статична

Наш досвід показує: якщо команда володіє JS і потрібен гнучкий контроль над розміткою — Eleventy перемагає. Hugo сильний у швидкості білда, але його Golang-шаблони менш гнучкі. Jekyll зав'язаний на Ruby і часто викликає конфлікти версій. Eleventy у 2–3 рази швидший у розробці на стартовому проекті завдяки знайомому JS-стеку та плагінам. За нашими тестами, Eleventy генерує білд у 2.5 рази швидше, ніж Jekyll на Ruby. Крім того, перехід на Eleventy скорочує витрати на хостинг на 40%: статичні файли можна роздавати через CDN практично безкоштовно, тоді як для динамічних сайтів потрібен сервер. Наприклад, економія на хостингу становить до $50 на місяць для сайту з 10 000 відвідувачів.

Процес роботи

  1. Аналітика — визначаємо типи контенту, структуру колекцій, патерн даних.
  2. Проектування — створюємо каркас _data/, _includes/, колекції з тестовими даними.
  3. Реалізація — верстаємо шаблони Nunjucks, налаштовуємо плагіни (RSS, зображення, підсвічування коду).
  4. Тестування — перевіряємо білд на 500+ сторінках, заміряємо LCP/CLS Lighthouse.
  5. Деплой — налаштовуємо CI/CD (Vercel, Netlify, Cloudflare Pages), підключаємо CDN.
Приклад конфігурації деплою для Netlify Вкажіть у `netlify.toml` команди збірки та пабліш-директорію:
[build]
  command = "npm run build"
  publish = "_site"

[[redirects]]
  from = "/*"
  to = "/404.html"
  status = 404

Netlify автоматично роздає статику через CDN з підтримкою Brotli-стиснення.

Що входить у роботу під ключ

Компонент Опис
Репозиторій GitLab / GitHub з налаштуванням branch protection
Документація README зі схемою даних і командами
Доступи Адмінка CMS (якщо потрібна) + хостинг
Навчання 1 година відео-дзвінка для редакторів
Підтримка 2 тижні безкоштовних правок після здачі

Строки орієнтовно

  • Сайт на стартовому шаблоні з кастомним контентом — 4–6 днів.
  • Розробка з нуля з кастомними колекціями, пагінацією, оптимізацією зображень, CI/CD — 2–3 тижні.
  • Крупний портал із десятками типів контенту, мультимовністю, інтеграціями з CMS — 1–2 місяці.

Вартість розраховується індивідуально — оцінимо проект за 1 день. На ринку більше 5 років, реалізували 40+ проектів на статичних генераторах. Наші клієнти отримують гарантію на білд та підтримку після запуску. Оцінимо ваш проект за 1 день — зв'яжіться з нами. Отримайте консультацію інженера, замовте розробку на Eleventy.

Типи сайтів: технічне завдання, а не маркетинг

Ми бачимо, як команди витрачають бюджет на невідповідний стек. Лендинг на Next.js зі статичною генерацією та корпоративний сайт з CMS — принципово різні інфраструктури, навіть якщо зовні схожі. Помилка на старті веде до переплати за хостинг у 5–10 разів і низької швидкості завантаження. Core Web Vitals (LCP, INP, TTFB) для кожного типу сайту мають свої пріоритети: для лендингу критичний LCP, для корпоративного — TTFB через динамічний контент.

За нашими даними, до 40% проєктів переплачують на хостингу через неправильний вибір технології. Статичний сайт на CDN обходиться в 5 разів дешевше за WordPress на VPS за тих самих навантажень. Нижче розберемо чотири типи сайтів, їхні типові технічні помилки та рішення, які ми застосовуємо на практиці. Маємо 8 років досвіду та понад 120 успішних проєктів у різних нішах.

Як обрати правильний тип сайту?

Вибір визначає стек, інфраструктуру та бюджет на підтримку. Покрокова інструкція:

  1. Визначте мету: продаж (лендинг), інформування (корпоративний) чи швидкий контакт (візитка).
  2. Оцініть частоту оновлення контенту: щодня — потрібна CMS, раз на місяць — вистачить Markdown у Git.
  3. Виберіть стек за продуктивністю: статика для візиток, Next.js з ISR для корпоративних, GSAP для промо.

Як не помилитися з вибором CMS?

Якщо редактори нетехнічні — WordPress з Gutenberg або ACF Pro закриває потреби. Для складних структур — headless CMS (Strapi, Directus) з фронтендом на Next.js. Якщо оновлення рідкі — Markdown в Git з Astro або Next.js, деплой по push в main. Ми використовуємо Repository pattern для уникнення N+1 запитів при роботі з ORM.

Сайт-візитка

Найкомпактніший формат: 1–5 сторінок, мінімум динаміки. Основне завдання — контактна інформація та перше враження. Технічно просто, але є типові помилки.

Занадто важкий стек. WordPress з 15 плагінами для 5 сторінок дає TTFB 800ms на shared хостингу. Ми пропонуємо статику: HTML/CSS/JS або Next.js з output: 'export', задеплоєне на Vercel або Cloudflare Pages. Жодного PHP, жодної бази даних — тільки CDN. TTFB < 50ms гарантовано. Економія на хостингу — до 70% на місяць.

Немає контактної форми з backend-валідацією. Форма лише з JS-валідацією — це декорація. Ми додаємо серверлесс endpoint (Netlify Functions або AWS Lambda) з rate-limiter та сповіщеннями.

Відсутність Schema.org розмітки. Google Knowledge Panel будується на LocalBusiness або Organization. Ми вбудовуємо розмітку в шаблон: адреса, телефон, години роботи.

Термін розробки: 2–3 тижні з дизайном.

Чому швидкість лендингу безпосередньо впливає на конверсію?

Лендинг — сторінка з однією метою: конверсія. Core Web Vitals критичні, оскільки платний трафік і Google використовує CWV у Quality Score.

Конкретний кейс: лендинг з hero-відео 8MB autoplay без preload="none" і три сторонні скрипти аналітики синхронно в <head>. LCP 9.4s, INP 780ms. Ми замінили відео на poster image з відкладеним завантаженням, скрипти перевели на async/defer і частково в Web Workers через Partytown. LCP став 1.8s, INP 140ms. Конверсія зросла на 23% тільки за рахунок швидкості.

A/B тестування — стандартна практика. Після закриття Google Optimize використовуємо open-source Growthbook або PostHog. Для Next.js застосовуємо edge middleware для розподілу трафіку на CDN без додаткового JS.

Термін: 2–4 тижні.

Корпоративний сайт

Корпоративний — CMS, багато сторінок, мультимовність, інтеграція з CRM. Ключове питання: хто редагує контент і як часто.

Якщо редактори нетехнічні — WordPress з Gutenberg або ACF Pro. Для складних структур — headless CMS (Strapi, Directus) з фронтендом на Next.js. Якщо оновлення рідкі — Markdown в Git з Astro або Next.js, деплой по push в main.

Продуктивність: сторінка "Про компанію" з 40 фото в оригіналі — LCP 12 секунд на мобільному. <Image> компонент Next.js з WebP і srcset вирішує без ручної роботи, знижуючи LCP до 2 секунд.

Багатомовність: Astrotomic Translatable на Laravel або next-intl. Структура URL — /uk/about, /en/about з hreflang.

Термін: 6–12 тижнів залежно від обсягу.

Промо-сайт

Промо — тимчасовий або постійний сайт під кампанію. Нестандартний дизайн, анімації. Стек: GSAP, Framer Motion, Three.js, Lottie.

Головна пастка — гальмівні анімації на мобільних. GPU-анімації через transform і opacity — нормально. box-shadow в анімації, filter: blur() на кожному кадрі, анімація width/height — 20fps на iPhone 12. will-change: transform допомагає точково.

prefers-reduced-motion — обов’язковий для accessibility.

Термін: 3–6 тижнів.

Як ми оптимізуємо продуктивність?

Для кожного проєкту проводимо аудит початкового стеку: аналізуємо TTFB, LCP, CLS, INP через Lighthouse та WebPageTest. Використовуємо tree-shake та bundle splitting для зменшення JS-бандла, для Next.js — React Server Components і Suspense для стрімінгу. Серверлесс функції дозволяють уникнути постійної вартості сервера — платите тільки за запити. Наприклад, корпоративний сайт на Next.js + Strapi дає TTFB <200ms, що у 5 разів менше ніж аналог на WordPress.

Автоматично конвертуємо зображення в WebP/AVIF, генеруємо srcset для всіх роздільних здатностей, використовуємо lazy loading з Intersection Observer. Для фонових зображень — техніка progressive loading.

Порівняльна таблиця

Параметр Візитка Корпоративний Лендинг Промо
Сторінок 1–5 10–50+ 1–3 1–10
CMS Не потрібна Потрібна Не потрібна Рідко
SEO-пріоритет Середній Високий Високий Низький
Анімації Мінімум Помірно Помірно Інтенсивно
Термін (з дизайном) 2–3 тиж 6–12 тиж 2–4 тиж 3–6 тиж

Вартість у кожному випадку розраховується індивідуально після вивчення технічного завдання. — Google рекомендує TTFB під 0.8s, у нас <0.2s.

Що входить в роботу

  • Аналітика та прототипування (структура, користувацькі сценарії)
  • Дизайн-концепція (адаптивний, mobile-first)
  • Верстка з оптимізацією LCP, CLS, INP
  • Вибір та налаштування CMS (якщо потрібна)
  • Інтеграція з CRM/маркетинговими інструментами
  • Тестування (кросбраузерне, load-testing)
  • Документація та передача доступів
  • Навчання редакторів (відео + письмово)
  • гарантія 3 місяці (безкоштовні правки)

Друга таблиця: порівняння підходів за продуктивністю

Підхід TTFB (мс) Складність підтримки Вартість розробки
Static HTML/CSS <50 Низька Низька
Next.js + headless CMS <200 Середня Середня
WordPress + плагіни 500–1500 Висока Висока

Статичний сайт швидший за WordPress у 10 разів за TTFB. Для консультації щодо вибору типу сайту та стеку зв'яжіться з нашими інженерами. Замовте розробку під ключ — ми оцінимо терміни та бюджет за 1 день. Напишіть нам, щоб отримати безкоштовний технічний аудит вашого проекту. Отримайте індивідуальну пропозицію з гарантією якості.