Wintersmith — генератор статических сайтов на Node.js
Оригинал статьи: Getting Started with Wintersmith: A Node.js-based Static Site Generator
Оглавление:Я много говорил и писал на тему статических сайтов в последнее время. В общем, я рекомендую всем Jekyll, как наиболее стабильный и функциональный генератор на даный момент. Но многих разработчиков останавливает то, что он написан на Ruby. И многие спрашивают: “Есть ли альтернатива, основанная на JavaScript и доступная через npm?”.
В этой статье, первой в серии из двух частей, мы рассмотрим такой вариант: Wintersmith. Это производительный генератор статических сайтов, у которого есть один очень серьезный недостаток — отсутствие детальной документации. Надеюсь, что эта статья позволит людям, знакомым с JavaScript, начать работать с Wintersmith.
Образец сайта
Для этой статьи я сделал пример сайта, который вы можете найти здесь. Это фан-сайт Adventure Time! и выглядит он так:
Целью нашего проекта является сборка этого сайта с использованием генераторов статических сайтов для их сравнения. Этот сайт прост, но в нем есть определенные вещи, которые должны быть и в Wintersmith:
- Собственные глобальные метаданные— возможность глобально задавать собственные метаданные, доступные для шаблонов;
- Собственные метаданные постов— возможность задавать собственные метаданные для поста, доступные при выводе поста отдельно или в списке;
- Наборы данных — возможность добавлять контент, не являющийся постом или страницей, а собственным типом данных (в нашем случае это данные о персонажах). Все данные о персонажах, контент и изображения взяты из Adventure Time! wiki. Дизайн взят из бесплатного шаблона HTML5UP.
Как настроить Wintersmith
Одним из преимуществ базирования Wintersmith на Node.js и npm является простота установки. Для этого достаточно выполнить в консоли следующую команду (в Windows можно обойтись без sudo
):
$ sudo npm install -g wintersmith
Все! Теперь вы можете начинать новый проект.
Создание сайта
Для создания нового сайта на базе Wintersmith достаточно следующей команды:
$ wintersmith new [project name]
Для нашего тестового сайта мы используем имя “wintersmithsite”, поэтому команда будет такой:
$ wintersmith new wintersmithsite
Команда создаст каталог с именем проекта и поместит в него набор файлов, которые мы можем модифицировать в ходе построения сайта.
Если мы взглянем на сгенерированные сайты, мы увидим, что Wintersmith размещает конфигурацию, шаблоны и плагины в корневой каталог, а содержимое сайта в специальный каталог “contents”.
Тестирование сайта
Для запуска сайта на локальном сервере, перейдите в его каталог и запустите предпросмотр:
$ cd wintersmithsite
$ wintersmith preview
По умолчанию , локальный сервер запускает на порту 8080, поэтому наш сайт доступен по адресу http://localhost:8080
. При желании мы можем задать другой порт с опцией -p
. Кроме того, по умолчанию сервер настроен на выдачу в консоль детальных сообщений об ошибках и загруженных ресурсах. Об остальных опциях сервера можно узнать, вызвав помощь:
$ wintersmith preview -help
Настраивать опции сайта можно также путем редактирования файла config.json
, расположенного в корне проекта.
Основы шаблонов
В качестве шаблонизатора по умолчанию Wintersmith использует Jade (ныне также известный как pug, на русском можно почитать перевод документации или введение). Им же мы будем пользоваться для примеров в этой статье, но учтите, что в Wintersmith достаточно плагинов на случай, если вы предпочитаете иной шаблонизатор.
Шаблоны располагаются в каталоге templates
в корне сайта. Jade достаточно минималистичный шаблонизатор — в нем нет скобок и закрывающих тегов, для правильного вывода важны отступы. Рассмотрим его основы, чтобы перейти к созданию шаблонов.
Вывод данных
В Jade есть много способов для вывода данных из переменных. Наиболее традиционный это присваивание значения переменной тегу в шаблоне. Например, в следующем примере шаблон templates/article.jade
поместит название статьи внутрь тега <h2>
:
h2= page.title
По умолчанию содержимое переменной экранируется перед выводом. Это значит, что если внутри переменной есть HTML, то теги не будут выводится, на выходе будет только простой текст. Если нам нужен рендеринг содержимого, мы должны прямо указать это в шаблоне, добавив восклицательный знак, в нашем файле templates/article.jade
это будет выглядеть так:
section.content!= typogr(page.html).typogrify()
Мы можем делать тоже самое с атрибутами. Следующий пример из templates/partials/homepagemiddle.jade
создает тег <a>
с атрибутом href
, содержащим адрес статьи.
a(href= article.url, class="image featured")
Если вам интересно, как сделать переменные доступными объекту страницы по умолчанию, это описано в документации. Отдельно замечу,что переменная article
не дефолтная, а результат цикла, позднее мы это рассмотрим.
Другой способ вывода переменных в Jade это #{ variableName }
. При этом весь контент экранируется (в нашем примере этот метод не применялся).
Если же вы хотите, чтобы контент выводился неочищенным, используйте синтаксис !{ variableName }
. Например, если мы выводим основное содержимое поста, мы хотим, чтобы все теги рендерились. Вот пример из templates/partials/homepagemiddle.jade
:
!{ typogr(article.intro).typogrify() }
Весь код, находящийся до вертикальной черты будет выведен как простой текст.
Модули npm
Вы, наверное, заинтересовались, как вызывается typogrify()
. В Wintersmith можно использовать модули npm. В сгенерированном нами сайте используются три модуля: typogr (именно его мы и использовали выше), Moment.js (об этом модуле есть статья) и Underscore.
Давайте взглянем, как используется Moment.js для форматирования даты внутри шаблона templates/partials/homepagemiddle.jade
:
p= "Posted " + moment.utc(article.date).format('MMM DD, YYYY')
Moment.js предлагает широкий функционал, в который входит не только форматирование, и все это доступно внутри ваших шаблонов. И мы не ограничены одним только Moment.js: мы можем добавить любой модуль npm командой require
внутри config.json
, установить через npm install
и затем использовать в шаблонах.
Вложения
Для удобства поддержки и многократного использования повторяющихся фрагментов, мы можем разбить наши шаблоны с помощью вложений. Код из шаблона templates/index.jade
подключает шаблон templates/partials/header.jade
(расширение файла jade
при подключении не указывается):
include ./partials/header
Jade также поддерживает наследование,с помощью чего создаются отдельные блоки многократно используемого кода. Детали описаны в документации.
Условия
Иногда вам нужно изменять вывод шаблона в зависимости от каких-либо условий. В Jade для этого есть условное ветвление. Jade поддерживает if
, else if
, else
и unless
(отрицательная форма if
).
Пример из templates/partials/header.jade
выводит баннер везде, кроме page
(так как все посты относятся к типу page
, баннер будет выведен только на домашней странице):
if !page
section(id="banner")
header
h2 Explore the Land of Ooo...
p ...and its many kingdoms!
Это же условие можно реализовать с помощью unless page
.
Jade также поддерживает блоки условий case
, подробности, как всегда, в документации.
Циклы
Циклы активно используются в наших шаблонах, пробегаем ли мы ими по постам или данным. В Jade есть циклы each
и while
.
Следующий пример из файла templates/partials/homepagemiddle.jade
выводит все символьные данные с помощью цикла each
. В середине домашней страницы мы отобразим каждый символ вместе с его изображением, названием и описанием. Цикл each
проходит через каждый объект в массиве и назначает его значение переменной character
, тем самым получая доступ ко всем свойствам элементов.
each character in contents.characters
div(class="4u")
section(class="box")
span(class="image featured")
img(src= character.metadata.image)
header
h3= character.metadata.name
p= character.metadata.description
К сожалению, нельзя добавить лимит или сдвиг для этого цикла. Это можно сделать скомбинировав переменные и условия, в следующем примере мы так покажем только первые два поста. Учтите, что тире перед объявлением переменных (i
и articles
) показывает, что они будут работать на сервере все время компиляции. Это значит, что на готовой странице сайта этот код выводиться не будет.
- var i=0
- var articles = env.helpers.getArticles(contents);
each article in articles
- i++
if i<3
div(class="6u")
section(class="box")
a(href= article.url, class="image featured")
img(src= article.metadata.banner)
header
h3= article.title
p= "Posted " + moment.utc(article.date).format('MMM DD, YYYY')
| !{ typogr(article.intro).typogrify() }
footer
ul(class="actions")
li
a(href= article.url, class="button icon fa-file-text") Continue Reading
Мы используем env.helpers.getArticles(contents);
для получения массива статей в каталоге contents/articles. Это не документировано, метод берет начало из плагина разбивки страниц, настраиваемого в config.json
.
Следующий и последний пример в нашей статье показывает имитацию лимита и отступа в цикле одновременно (пропускаются первые две статьи, затем выводятся пять):
- var i=0
- var articles = env.helpers.getArticles(contents);
each article in articles
-i++
if (i>2) && (i<8)
li
span(class="date")
!=moment.utc(article.date).format('MMM')
strong= moment.utc(article.date).format('DD')
h3
a(href=article.url)= article.title
p= article.metadata.shortdesc
Заключение
В этой статье мы познакомились с Wintersmith, генератором статических сайтов на Node.js. Мы рассмотрели установку и начало работы, а также обсудили некоторые особенности Jade, дефолтного шаблонизатора в Wintersmith. В следующей части, я покажу, как создавать посты, используя Markdown, как настраивать собственные метаданные, как провести сборку и развертывание сайта.
Как вы заметили, одним из наиболее интересных преимуществ Wintersmith является возможность использования модулей npm. Это значительно расширяет возможности разработчиков по настройке и добавлению функционала на сайт.
Серия статей: "Генератор статических сайтов Wintersmith":
- Wintersmith — генератор статических сайтов на Node.js
- Посты, данные и метаданные в Wintersmith