תוספי Ruby מותאמים אישית לפיתוח Jekyll

כלי Jekyll סטנדרטיים לא תמיד מתמודדים עם משימות לא שגרתיות, מה שמאלץ לבצע פעולות שגרתיות ידניות. אנחנו בונים תוספי Ruby מותאמים אישית במפתח מלא שמרחיבים את יכולות האתר שלך ומאוטמים תהליכים. הצוות שלנו מטפל בכל המחזור—מבדיקת צרכים ועד תכנון, הטמעה ותמיכה שוטפת—ומספק פתרון אמין שגדל עם הפרויקט שלך.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
תוספי Ruby מותאמים אישית לפיתוח Jekyll
בינוני
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1307
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

למה צריך פלאגין Jekyll מותאם אישית?

דמיינו בלוג עם 150 פוסטים ב-20 תגיות. ללא פלאגין מותאם אישית, תצטרכו ליצור ידנית Jekyll::Generator עבור כל תגית. זה לא יעיל ומועד לשגיאות. Jekyll כתוב ב-Ruby ומספק Jekyll Plugins API מלא דרך פלאגינים. פלאגינים הם מחלקות Ruby שמתחברות לצינור יצירת האתר. הם מאפשרים הוספת תגיות Liquid חדשות, מסננים, מחוללי עמודים, ממירי פורמט ו-hooks. GitHub Pages לא מריץ פלאגינים שרירותיים (רק רשימה לבנה), ולכן השימוש בהם דורש CI/CD משלכם. אנו מפתחים פלאגינים מותאמים אישית במפתח מלא: מרעיון ועד פריסה עם בדיקות ותיעוד. למהנדסים שלנו יש ניסיון של 10+ שנים עם Ruby ו-Jekyll, מה שמבטיח יציבות וביצועים. שימוש בפלאגינים מותאמים אישית מקצר את זמן הבנייה ב-40% ומאיץ את יצירת העמודים בממוצע פי 2. בפרויקט אחד עבור חברת מדיה גדולה, החלפנו סט של 5 פלאגינים מוכנים בפלאגין מותאם אחד, וקיצרנו את זמן הבנייה מ-12 ל-7 דקות וביטלנו התנגשויות תלויות.

מותאם אישית לעומת פלאגינים מוכנים: מתי מותאם עדיף?

פלאגינים מוכנים מ-RubyGems חוסכים זמן, אך לעתים קרובות לא עומדים בדרישות ספציפיות. פלאגין מותאם אישית שנכתב עבור הארכיטקטורה שלכם רץ בממוצע פי 2 מהר יותר ביצירת עמודי תגיות ואינו מכיל קוד מיותר. הוא מונע התנגשויות גרסאות ונותן לכם שליטה מדויקת על ההתנהגות. אם אתם צריכים משהו ייחודי, פלאגין מותאם אישית הוא לעתים קרובות האפשרות היחידה.

סוגי פלאגינים ומתי להשתמש במה

סוג מחלקת-על מקרה שימוש
מחולל Jekyll::Converter יצירת עמודים פרוגרמטית, איסוף נתונים
ממיר Jekyll::Command פורמטי תוכן חדשים (AsciiDoc, reStructuredText)
פקודה jekyll mycommand פקודות CLI חדשות (Liquid::Tag)
תגית {% mytag %} תגיות מותאמות אישית Liquid::Block
בלוק {% block %}...{% endblock %} תגיות עם תוכן Liquid::Template.register_filter
מסנן כלול ב-# _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) מסננים מותאמים אישית `{{ 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)

תגית מותאמת אישית להטמעת סרטונים

תגית עם טעינה עצלה:

# _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)

מחולל לעמודי תגיות

Jekyll יוצר # _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) באופן טבעי רק דרך פלאגינים של צד שלישי. יישום:

# _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

Hooks לעיבוד לאחר

# _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

איך מפתחים פלאגין מותאם אישית?

תהליך הפיתוח כולל מספר שלבים. ראשית, אנו מנתחים את המשימה: איזה נתונים צריך לעבד, באיזו תדירות התוכן משתנה, האם נדרשת אינטגרציה עם APIs חיצוניים. לאחר מכן אנו מתכננים את ארכיטקטורת הפלאגין: בוחרים את הסוג (מחולל, ממיר, תגית, מסנן), מגדירים קונפיגורציה ו-hooks. אנו כותבים קוד Ruby בהתאם לעקרונות SOLID. לאחר היישום, אנו מוסיפים בדיקות יחידה RSpec עם כיסוי של לפחות 95% — זה חובה. השלב האחרון הוא אינטגרציה לפרויקט שלכם: הגדרת Gemfile או תיקיית _site/tags/, יחד עם 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. אנו מבטיחים יציבות וביצועים: אנו משתמשים בטעינת נתונים עצלה, caching ואופטימיזציית שאילתות. כל פרויקט כולל תיעוד והדרכת צוות. צרו קשר לייעוץ על הפרויקט שלכם. הזמינו פיתוח פלאגין במפתח מלא — נספק קוד, בדיקות ו-CI/CD.

איך לשלב את הפלאגין בפרויקט?

התקינו את הפלאגין דרך Gemfile או העתיקו אותו לתיקיית # _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 . עבור CI/CD, נדרש שלב להתקנת תלויות gem. אם אתם מתכננים להשתמש בפלאגין ב-GitHub Pages, תצטרכו CI של צד שלישי, מכיוון ש-Pages לא תומך בפלאגינים שרירותיים.

לוחות זמנים לפיתוח

סוג פלאגין זמן משוער
מסנן או תגית פשוטה 0.5–1 יום
תגית עם פרמטרים 1–2 ימים
מחולל לעמודים 2–3 ימים
ממיר פורמט 3–5 ימים
פלאגין מורכב עם API ובדיקות 1–2 שבועות

צרו קשר לייעוץ על הפרויקט שלכם. קבלו הערכת משימה תוך יום אחד.