Разработка кастомных Ruby-плагинов для Jekyll под ключ

Стандартные инструменты Jekyll не всегда справляются с нестандартными задачами, заставляя вручную выполнять рутинные операции. Мы разрабатываем кастомные Ruby-плагины под ключ, которые расширяют возможности вашего сайта и автоматизируют процессы. Наша команда берёт на себя весь цикл — от аудита и проектирования до внедрения и последующей поддержки, обеспечивая надёжное решение, которое масштабируется вместе с вашим проектом.

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка кастомных Ruby-плагинов для Jekyll под ключ
Средний
~2-3 дня
Часто задаваемые вопросы

Почему нужен кастомный плагин Jekyll?

Представьте: на блоге 150 постов, разбитых по 20 тегам. Без кастомного плагина придётся вручную создавать index.md для каждого тега. Это неэффективно и чревато ошибками. Jekyll написан на Ruby и предоставляет полноценный Jekyll Plugins API через плагины. Плагины — это Ruby-классы, которые встраиваются в pipeline генерации сайта. Через них можно добавить новые теги Liquid, фильтры, генераторы страниц, конверторы форматов и хуки. GitHub Pages не запускает произвольные плагины (только белый список) — поэтому для их использования нужен собственный CI/CD. Мы разрабатываем кастомные плагины под ключ: от идеи до деплоя с тестами и документацией. Наши инженеры имеют 10+ лет опыта с Ruby и Jekyll, что гарантирует стабильность и производительность. Использование кастомных плагинов сокращает время сборки на 40% и ускоряет генерацию страниц в среднем в 2 раза. В одном из проектов для крупного медиа мы заменили набор из 5 готовых плагинов одним кастомным, что уменьшило время сборки с 12 до 7 минут и устранило конфликты зависимостей.

Сравнение с готовыми плагинами: когда кастомный лучше?

Готовые плагины из RubyGems экономят время, но часто не удовлетворяют специфическим требованиям. Кастомный плагин, написанный под вашу архитектуру, работает в среднем в 2 раза быстрее при генерации страниц тегов и не содержит лишнего кода. Он избавляет от конфликтов версий и позволяет точно контролировать поведение. Если нужно что-то уникальное — кастомный плагин оказывается единственным рабочим вариантом.

Типы плагинов и когда что использовать

Тип Суперкласс Применение
Generator Jekyll::Generator Создание страниц программно, агрегация данных
Converter Jekyll::Converter Новые форматы контента (AsciiDoc, reStructuredText)
Command Jekyll::Command Новые CLI-команды (jekyll mycommand)
Tag Liquid::Tag Кастомные теги {% mytag %}
Block Liquid::Block Теги с контентом {% block %}...{% endblock %}
Filter включение в Liquid::Template.register_filter Кастомные фильтры `{{ value

Примеры плагинов

Фильтр для форматирования чисел

Фильтр для форматирования числа в российский формат:

# _plugins/filters/number_format.rb
module NumberFormatFilter
  def ru_number(number, decimals = 0)
    return number unless number.is_a?(Numeric)
    formatted = number.to_f.round(decimals)
    parts = formatted.to_s.split('.')
    integer_part = parts[0].gsub(/(\d)(?=(\d{3})+$)/, '\\1 ')
    if decimals > 0 && parts[1]
      "#{integer_part},#{parts[1].ljust(decimals, '0')}"
    else
      integer_part
    end
  end

  def ru_currency(number, currency = '₽')
    "#{ru_number(number)} #{currency}"
  end

  def reading_time(content)
    words = content.split.length
    minutes = (words / 200.0).ceil
    "#{minutes} мин"
  end
end

Liquid::Template.register_filter(NumberFormatFilter)

Кастомный тег для вставки видео

Тег с lazy loading:

# _plugins/tags/video_embed.rb
module Jekyll
  class VideoEmbedTag < Liquid::Tag
    PROVIDERS = {
      'youtube' => 'https://www.youtube.com/embed/%s',
      'vimeo' => 'https://player.vimeo.com/video/%s',
    }.freeze

    def initialize(tag_name, markup, tokens)
      super
      @params = {}
      markup.scan(/(\w+)="([^"]*)"/) do |key, value|
        @params[key] = value
      end
    end

    def render(context)
      provider = @params['provider'] || 'youtube'
      video_id = @params['id']
      title = @params['title'] || 'Видео'
      aspect = @params['aspect'] || '16-9'
      return "<!-- video_embed: missing id -->" unless video_id
      url = format(PROVIDERS[provider], video_id)
      <<~HTML
        <div class="video-embed video-embed--#{aspect}">
          <iframe src="#{url}" title="#{title}" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen loading="lazy" ></iframe>
        </div>
      HTML
    end
  end
end

Liquid::Template.register_tag('video_embed', Jekyll::VideoEmbedTag)

Generator для страниц тегов

Jekyll нативно генерирует _site/tags/ только через сторонние плагины. Реализация:

# _plugins/generators/tag_pages.rb
module Jekyll
  class TagPageGenerator < Generator
    safe true
    priority :low

    def generate(site)
      all_tags = site.posts.docs.flat_map { |post| post.data['tags'] || [] }.uniq.sort
      all_tags.each do |tag|
        site.pages << TagPage.new(site, site.source, tag)
      end
      site.pages << TagIndexPage.new(site, site.source, all_tags)
    end
  end

  class TagPage < Page
    def initialize(site, base, tag)
      @site = site
      @base = base
      @dir = File.join('tags', Jekyll::Utils.slugify(tag))
      @name = 'index.html'

      process(@name)
      read_yaml(File.join(base, '_layouts'), 'tag.html')

      self.data['tag'] = tag
      self.data['title'] = "Посты с тегом: #{tag}"
      self.data['description'] = "Все материалы по теме «#{tag}»"
      self.data['tag_posts'] = site.posts.docs.select { |post| (post.data['tags'] || []).include?(tag) }.sort_by { |post| post.date }.reverse
    end
  end

  class TagIndexPage < Page
    def initialize(site, base, tags)
      @site = site
      @base = base
      @dir = 'tags'
      @name = 'index.html'

      process(@name)
      read_yaml(File.join(base, '_layouts'), 'tags-index.html')

      self.data['title'] = 'Все теги'
      self.data['tags_with_counts'] = tags.map { |tag|
        count = site.posts.docs.count { |post| (post.data['tags'] || []).include?(tag) }
        { 'name' => tag, 'slug' => Jekyll::Utils.slugify(tag), 'count' => count }
      }.sort_by { |t| -t['count'] }
    end
  end
end

Хуки для постобработки

# _plugins/hooks/minify_html.rb
Jekyll::Hooks.register [:pages, :documents], :post_render do |doc|
  next unless doc.output_ext == '.html'
  next if doc.output.nil? || doc.output.empty?
  doc.output = doc.output
    .gsub(/>\s+</, '><')
    .gsub(/\s{2,}/, ' ')
    .strip
end

Jekyll::Hooks.register :site, :post_write do |site|
  puts " Сайт собран: #{site.pages.length} страниц, #{site.posts.docs.length} постов"
  puts " Выходная директория: #{site.dest}"
end

Тестирование плагинов

Пример теста для фильтра:

# spec/plugins/number_format_spec.rb
require 'jekyll'
require_relative '../../_plugins/filters/number_format'

RSpec.describe NumberFormatFilter do
  include NumberFormatFilter

  describe '#ru_number' do
    it 'форматирует тысячи с пробелом' do
      expect(ru_number(1234567)).to eq('1 234 567')
    end

    it 'форматирует десятичные дроби' do
      expect(ru_number(1234.5, 2)).to eq('1 234,50')
    end
  end

  describe '#reading_time' do
    it 'вычисляет время чтения' do
      content = Array.new(400, 'слово').join(' ')
      expect(reading_time(content)).to eq('2 мин')
    end
  end
end

Как разрабатывается кастомный плагин?

Процесс разработки включает несколько этапов. Сначала мы анализируем задачу: какие данные нужно обрабатывать, как часто меняется контент, требуется ли интеграция с внешними API. Затем проектируем архитектуру плагина: выбираем тип (Generator, Converter, Tag, Filter), определяем конфигурацию и хуки. Пишем код на Ruby с соблюдением принципов SOLID. После реализации добавляем модульные тесты RSpec с покрытием не менее 95% — это обязательное условие. Финальный шаг — интеграция в ваш проект: настройка Gemfile или директории _plugins/, а также CI/CD для автоматической сборки и деплоя. Для одного из клиентов мы разработали плагин-агрегатор новостей из 5 источников: он парсит RSS, создаёт новые страницы с контентом и генерирует XML-карту сайта за 3 секунды при каждой сборке. Весь процесс от ТЗ до деплоя занял 10 дней.

Пример настройки CI/CD для GitHub Actions
---
name: Build Jekyll site
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
      - run: bundle exec jekyll build
      - uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./_site

Почему стоит заказать разработку у нас?

Наши инженеры имеют 10+ лет опыта с Ruby и Jekyll. Мы гарантируем стабильность и производительность: используем ленивую загрузку данных, кеширование и оптимизацию запросов. В каждом проекте мы предоставляем документацию и проводим обучение команды. Свяжитесь с нами для консультации по вашему проекту. Закажите разработку плагина под ключ — мы подготовим код, тесты и CI/CD.

Как интегрировать плагин в проект?

Плагин устанавливается через Gemfile или копируется в _plugins/. После подключения достаточно добавить конфигурацию в _config.yml. Для CI/CD потребуется шаг установки gem-зависимостей. Если вы планируете использовать плагин на GitHub Pages, понадобится сторонний CI, так как Pages не поддерживает произвольные плагины.

Сроки разработки

Тип плагина Ориентировочное время
Фильтр или простой тег 0.5–1 день
Тег с параметрами 1–2 дня
Generator для страниц 2–3 дня
Конвертер формата 3–5 дней
Сложный плагин с API и тестами 1–2 недели

Свяжитесь с нами для консультации по вашему проекту. Получите оценку задачи за 1 день.

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

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

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060