Статьи

Мой опыт работы с Jekyll

Вчера я писал в блоге о новом сервисе статического хостинга Surge . Чтобы протестировать его, я решил перестроить поваренную книгу JavaScript как статический сайт. (Что, честно говоря, было глупым решением. Использование Surge занимает около пяти минут. Моя перезапись заняла около пяти часов. ;)Я решил попробовать Джекилла и решил поделиться своими мыслями о платформе. Очевидно, я » Мы только что создали один сайт с этим, так что возьмите то, что я говорю, с недоверием, но если вы планируете создать статический сайт, возможно, этот пост будет полезен.

Джекил

Jekyll, как и HarpJS , запускается через инструмент командной строки. В отличие от Harp, Jekyll — инструмент на основе Ruby, но вам не нужно знать Ruby, чтобы использовать его. У меня был какой-то ускоренный курс в Ruby, когда я работал с ним, но это только из-за некоторых требований, которые я предъявлял при создании своего сайта. Полные требования задокументированы с большим красным флажком, означающим отсутствие поддержки Windows. Есть неофициальная поддержка , но я бы с осторожностью отнесся к Jekyll, если вам нужна поддержка разработчиков на платформе Windows.

После установки вы можете запустить сервер Jekyll из командной строки и начать работать. Jekyll будет автоматически обновляться, пока вы работаете, поэтому он быстро запускается и работает. Говоря о тестировании, в командной строке есть опция для создания сайта по умолчанию, просто сделайте jekyll new directoryname.

С этого момента вы можете начать печатать и тестировать результаты в браузере. Я предполагаю, что большинство моих читателей уже знакомы с тем, почему такие инструменты хороши, но в противном случае смысл статического генератора сайтов — позволить вам создавать сайты аналогично динамическим приложениям на стороне сервера. но с плоским, статическим файлом в качестве вывода. На практике это означает, что я могу создать шаблон и просто использовать токен, например {{body}}, который будет заменен содержимым страницы. Я могу написать страницу и просто включить соответствующие данные для этой страницы, и при просмотре в браузере она автоматически будет добавлена ​​в шаблон. Это не обязательно что-то особенное — это 101-уровневый PHP / ColdFusion / Node материал, но инструмент генератора будет выплевывать плоские HTML-файлы, которые затем могут быть размещены на таких вещах, как S3, Google Cloud или, конечно, Surge.

Для своих шаблонов Jekyll допускает Markdown и Liquid . Он не поддерживает Джейд, потому что Джейд злой и вонючий, и его нигде не следует поддерживать. Я обнаружил, что жидкость очень хороша. У вас есть основы (вывод переменных, циклы, условные выражения), а также некоторые мощные фильтры. Например, это будет заголовок в виде строки: {{title | использовать заглавные буквы}} . Это сделает усечение: {{content | усечение: 200, ‘…’}} . Вы можете сделать это с помощью шаблонов EJS в HarpJS (но я не знал этого до сегодняшнего дня!).

Другое большое изменение в Jekyll — это то, как он обрабатывает данные для контента. В Harp это разделено на файл, уникальный для папки. В Jekyll это делается через «передний план», в основном форматированный контент вверху страницы. Первоначально я предпочитал путь Арфы, но чем больше я играл с Джекиллом, тем более естественным было включение его в сам контент.

Вы можете, если хотите, также включать случайные файлы данных, что круто. Если вам нужно что-то, что не связано с контентом, вы можете абстрагировать его в файл JSON или YAML и использовать на своем сайте. Черт, вы даже можете использовать CSV.

В качестве тривиального примера файла Liquid приведу очень простую страницу, которую я использую для того, чтобы поблагодарить людей после отправки контента. В нем вообще нет ничего динамического, но содержимое вверху сообщает Jekyll, какой шаблон использовать, и передает значение заголовка.

---
layout: default
title: Thank You!
---

<p>
Thanks for sending your content submission. I'll try to respond as soon as possible. If
for some reason I don't get back to you, please feel free to drop me a line via email (raymondcamden at gmail dot com).
</p>

Вот немного более сложный пример, макет по умолчанию для сайта. Обратите внимание на использование переменных и условий для определения того, какую вкладку выделять.

<!doctype html>
<html lang="en">
    <head>
        <title>{{page.title}}</title>
    <link rel="stylesheet" href="/css/bootstrap.min.css" type="text/css" />
    <link rel="stylesheet" href="/css/app.css" type="text/css" />
    <script src="/js/jquery-2.0.2.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>

    <script src="/js/prism.js"></script>
    <link rel="stylesheet" href="/css/prism.css" />
    <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.javascriptcookbook.com/rss" />
    </head>
    
    <body>
    <div class="container">
      
      <div class="navbar navbar-inverse">
        <div class="navbar-inner">
          <div class="container" style="width: auto;">
          <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </a>
          <a class="brand" href="/">JavaScript Cookbook</a>
          <div class="nav-collapse">
            <ul class="nav">
            <li {% if page.url == '/index.html' %}class="active"{% endif %}><a href="/">Home</a></li>
            <li {% if page.url == '/submit.html' %}class="active"{% endif %}}><a href="/submit.html">Submit</a></li>
            <li {% if page.url == '/about.html' %}class="active"{% endif %}><a href="/about.html">About</a></li>
            
            </ul>
            <form class="navbar-search pull-right" action="/search.html" method="get">
            <input type="search" class="search-query span2" placeholder="Search" name="search">
            </form>
          </div><!-- /.nav-collapse -->
          </div>
        </div><!-- /navbar-inner -->
        </div><!-- /navbar -->

        {{content}} 
    
    </div>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-70863-21', 'javascriptcookbook.com');
  ga('send', 'pageview');

</script>
    
    </body>
</html>

Один из круче аспектов жидкости — assignоператор. Учитывая, что у вас есть доступ к данным о вашем сайте, например, к списку статей, вы можете быстро нарезать их на части в своем шаблоне. Хотя Jekyll облегчает работу с сообщениями в блоге, мой контент был немного другим. Мне нужен был быстрый способ получить весь контент моей статьи и отсортировать его по дате последнего опубликования. Вот как генерируются «Последние статьи».

<h3>Latest Articles</h3>

{% assign sorted = (site.pages | where:"layout","article" | sort: 'published' | reverse) %}

{% for page in sorted limit:5 %}
    <p>
    <a href="{{page.dir}}">{{page.title}}</a> - {{page.published | date: "%-m/%-d/%y at %I:%M" }}
    </p>
{% endfor %}

Как я уже сказал, эта assignкоманда просто делает меня счастливым во всем.

Так что все это хорошо, но есть одна особенность Jekyll, которая заставляет меня думать, что это может быть лучший инструмент для работы, которую я когда-либо видел, — плагины. Jekyll позволяет вам создавать на сервере несколько дополнений для таких вещей, как:

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

Эти плагины должны быть написаны на Ruby, но даже с моим абсолютным недостатком знания языка я смог создать два плагина для завершения своего сайта. Позвольте мне быть ясным — без этих плагинов я не смог бы завершить преобразование. (Ну, мне бы пришлось проделать гораздо больше работы.) Позвольте привести конкретный пример того, как это помогает.

Одна из проблем, с которой вы сталкиваетесь при использовании генераторов статического сайта, заключается в том, что им требуется один файл на URL. Я имею в виду следующее: для каждой страницы моего сайта, от домашней страницы до страницы «О нас», для каждой части содержимого блога у вас будет один физический файл. Это конечно хорошо. Я просто добавляю файл, пишу свое содержимое и знаю, что получаю преимущества автоматической разметки, подстановки переменных и т. Д. Но в некоторых случаях это требование является помехой.

Представьте, что у вас есть N статей. Каждая статья имеет набор назначенных тегов. В Harp это будет определено в вашем файле данных, в Jekyll это будет просто вопрос. Вот пример из одной из статей Aookbook:

---
layout: article
title: Check if a value is an array
published: 2014-10-23T21:18:46.858Z
author: Maciek
sourceurl: 
tags: 
id: 544970b682f286f555000001
sesURL: Check-if-a-value-is-an-array
moreinfo: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
---

Теперь представьте, что я хочу сделать одну страницу для каждого тега. Обычно я должен был бы:

  • Разберись со всеми моими тегами. Это не обязательно плохо — у вас может быть только 5-10 статических тегов.
  • Создайте каждый файл для тега с именем sometag.html.
  • Напишите код, который отбрасывает контент и отображает элементы, соответствующие этому тегу.
  • Включите этот код на каждой странице. И Harp, и Jekyll поддерживают языки шаблонов, которые облегчают эту задачу.

В конце у меня есть N страниц, по одной на каждый тег. Если я удаляю тег или добавляю его, я должен не забыть создать новый плоский файл. Не конец света, но то, что вы могли забыть.

С Jekyll я могу использовать плагин для создания генератора. Это будет выполняться при запуске сервера и при изменении ситуации, и может динамически добавлять новые страницы в систему. Вот плагин, который я написал для решения проблемы с тегами. Имейте в виду, я, вероятно, лучше танцую балет, чем Руби.

module Jekyll

  class TagPage < Page
    def initialize(site, base, dir, tag, pages)
      @site = site
      @base = base
      @dir = dir
      @name = 'index.html'

      #print "Running Tag page for "+tag+" "+pages.length.to_s+"\n"

      self.process(@name)
      self.read_yaml(File.join(base, '_layouts'), "tag.html")
      self.data['tag'] = tag
      self.data['title'] = tag
      self.data['pages'] = pages
    end
  end

  class TagPageGenerator < Generator
    safe true

    def generate(site)

      dir = "tag/"

      #create unique array of tags
      unique_tags = {}
      site.pages.each do |page|
        if page.data.key? 'layout' and page.data["layout"] == 'article' 
          #print page.data
          #print "\n"
          page.data["tags"].each do |tag|
            if !unique_tags.include?(tag)
              unique_tags[tag] = []
            end
            unique_tags[tag].push(page)
          end
        end

      end

      #print "unique tags: "+unique_tags.keys.join(",") + "\n"

      #create page for each
      unique_tags.keys.each do |tag|
        site.pages << TagPage.new(site, site.source, File.join(dir, tag), tag, unique_tags[tag])
      end

    end
  end

end

Вот и все! (Большое спасибо Райану Моррисси за его [a href = «http://ryancmorrissey.com/blog/2014/01/20/auto-create-jekyll-category-and-tag-pages/»] сообщение в блоге о это — я вырвал свой исходный код из него.)

Еще один пример поддержки плагинов — добавление собственных тегов. Мне нужен был способ создать уникальный список тегов для домашней страницы. Я написал этот плагин, который добавляет taglistв Liquid для моего сайта.

module Jekyll
  class TagListTag < Liquid::Tag
    def initialize(tag_name, text, tokens)
      super
    end

    def render(context)
      tags = []
      context.registers[:site].pages.each do |page| 
        if page.data.key?'layout' and page.data["layout"] == 'article'
          if page.data.key?'tags'
            page.data["tags"].each do |tag|
              if !tags.include?tag
                tags.push(tag)
              end
            end
          end
        end
      end
      tags = tags.sort
      #now output list
      s = ""
      tags.each do |tag|
        s += "<li><a href='/tag/" + tag + "'>" + tag + "</a></li>"
      end
      return s
    end

  end
end

Liquid::Template.register_tag('taglist', Jekyll::TagListTag)

Опять же — я, вероятно, пишу довольно дерьмовый Ruby — но мне нравится, что я смог расширить Jekyll таким образом. Если бы Арфа могла добавить это — и позволить мне использовать JavaScript — это было бы убийственно.

И это было действительно так. Я преобразовал свою форму для использования FormKeep и преобразовал поиск для использования системы пользовательского поиска Google. Вы можете увидеть окончательный результат здесь: http://aloof-zephyr.surge.sh/ .

Так как в кулинарной книге JavaScript не было нужного мне трафика (подсказка — я все еще ищу контент!), Я буду указывать домен на статическую версию, чтобы у меня было немного меньше Node. После того, как я добавлю поддержку Grunt и добавлю Surge, я могу написать сообщение и запустить его через 30 секунд. Я не могу ждать.

PS Я не включил почтовый индекс версии Jekyll, но если кому-то понравится, просто спросите.