Подробное знакомство с генератором статических сайтов Eleventy
Опубликовано: 2022-03-10Но сначала — давайте быстро рассмотрим, что подразумевается под «статическим сайтом», а затем то, что предоставляет генератор. Статический сайт состоит из статического контента — например, HTML, CSS, ресурсы и весь контент уже скомпилированы вместе перед отправкой на хост веб-сайта. Это отличается от динамического сайта, который компилирует эти вещи из запросов к базе данных во время выполнения (например, WordPress) или извлекает контент из API на стороне клиента (например, фреймворки JavaScript без рендеринга на стороне сервера).
Генератор статических сайтов — это среда и процессор сборки для компиляции вашего контента в статический HTML. Обычно они предлагают помощников для обеспечения гибкости при написании вашего контента (например, поддержку Markdown) и включают методы для шаблонов. Таким образом, вместо того, чтобы писать HTML-страницы одну за другой и копировать и вставлять повторяющиеся части, генератор будет поддерживать разбиение этих вещей на компоненты с помощью определенного языка шаблонов. Затем процесс сборки генератора соберет все вместе и выведет окончательный HTML-код, который можно загрузить на веб-хост для использования в качестве веб-сайта. В зависимости от используемого вами веб-хостинга этот процесс сборки может выполняться даже хостом.
Существует множество генераторов статических сайтов. Возможно, вы слышали или даже использовали такие, как Jekyll, Hugo, Gatsby, Next и Nuxt. Полный список предоставлен Jamstack.org.
Что отличает Eleventy от других генераторов статических сайтов?
Eleventy исключительно быстр как во время сборки, так и в браузере. Это во многом благодаря тому, что для обслуживания контента не требуется загрузка пакета JavaScript на стороне клиента (по сравнению с чем-то вроде Gatsby). Рендеринг на стороне сервера здесь даже не вызывает беспокойства, поскольку создание страницы файловой системы по умолчанию использует статический HTML.
Что действительно делает Eleventy уникальным, так это возможность выбирать и смешивать до десяти различных языков шаблонов:
Смешение языков может происходить в одном файле или между макетами. Например, я часто пишу свой основной контент с помощью Markdown, который встраивается в макет Nunjucks. В некоторых проектах я нашел полезной возможность перебирать некоторые данные с помощью Nunjucks, находясь в файле Markdown. Эта возможность комбинировать языки очень эффективна и позволяет вам разработать рабочий процесс записи и сборки, который лучше всего подходит для вас и вашего проекта.
Eleventy включает флаг --serve
, который использует BrowserSync для обеспечения локального обслуживания сайта и горячей перезагрузки при изменении файла. Это очень удобно, и о нем стоит помнить, если вы ищете не генератор статических сайтов, а, возможно, обновление таких инструментов сборки, как Gulp.
В рамках нулевой конфигурации все файлы вашего сайта могут находиться в корневом каталоге вашего проекта. Чтобы изменить входной и выходной каталоги, вы можете создать конфигурацию Eleventy, которая, как ожидается, будет корневым файлом с именем .eleventy.js
. Вот краткий фрагмент, показывающий, как сделать эту модификацию:
module.exports = function (eleventyConfig) { return { dir: { // default: [site root] input: "src", // default: _site output: "public", }, }; };
Как отмечалось ранее, поведением по умолчанию является создание страницы файловой системы, что, как правило, очень полезно, особенно для быстрого начала работы. Это легко переопределить, назначив пользовательскую permalink
, и это можно сделать для каждого файла, для всего каталога или динамически для набора данных. Постоянные ссылки также предлагают еще одну суперсилу, которую мы немного рассмотрим!
Уникально то, что во время сборки вы можете подготовить контент, данные и преобразовать этот контент и данные с помощью JavaScript и фильтров и шорткодов (мы поговорим об этом позже). Опять же, все это происходит без добавления пакета JavaScript на стороне клиента, но при этом позволяет использовать JavaScript в качестве языка шаблонов.
Важное примечание : вы можете успешно использовать Eleventy, не зная JavaScript или совсем не зная его.
В отличие от других SSG, таких как Gatsby, или таких сред, как WordPress, для большинства сайтов Eleventy не требуются какие-либо плагины. Доступны некоторые плагины, но они не нужны для основной функциональности.
При создании с Eleventy вы можете добавлять функции по мере необходимости. На самом деле, вы можете просто использовать HTML и никогда не работать ни с одним из других языков шаблонов. Eleventy настолько сложен, насколько этого требует ваш проект!
Понимание основных концепций Eleventy
Давайте рассмотрим несколько терминов и концепций, которые помогут вам добиться успеха в создании ваших проектов Eleventy.
Макеты и шаблоны
Вы можете считать эти термины взаимозаменяемыми, но в контексте Eleventy они имеют контекстуальное значение:
- Шаблон — это общий термин для всех файлов содержимого.
- Макеты — это специальные шаблоны, которые оборачивают другой контент.
Например, шаблон относится ко всем вашим файлам Markdown, тогда как макет может быть файлом Nunjucks, который содержит шаблон HTML5 и слот для содержимого шаблона. Мы узнаем, как это сделать, в разделе «Начало работы».
Фильтры и шорткоды
Это дополнительные способы изменения вывода содержимого и создания повторно используемых частей шаблона. Они доступны для использования с шаблонами Nunjucks, Liquid, Handlebars и JavaScript. Фильтры и шорткоды определяются в .eleventy.js
.
Помимо переменных и операторов, доступных на выбранном вами языке шаблонов, Eleventy унифицирует концепцию фильтров для ранее перечисленных языков. Фильтры преобразуют контент каким-то образом, зависящим от типа контента. Например, вы можете создать фильтр, предназначенный для строк, чтобы сделать их прописными. Или у вас может быть фильтр, предназначенный для использования в массивах, чтобы изменить то, что возвращается, например, выбрать случайный элемент. Некоторые фильтры предоставляются Eleventy, некоторые из них мы будем использовать в руководстве по началу работы.
Шорткоды позволяют создавать многократно используемые части шаблона и могут принимать аргументы. Они могут быть как автономными, так и парными, что означает, что они заключают содержимое в начальный и конечный теги.
Один из моих любимых шорткодов — отображать текущий год — это означает, что в нижнем колонтитуле больше не будет устаревших лет авторского права! Вот как создать шорткод year
:
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);
Чтобы использовать его в шаблоне Nunjucks или Liquid, он выглядит так: {% year %}
.
Вы можете просмотреть документы Eleventy для примеров парных шорткодов.
Коллекции
Коллекции — это группы связанного контента, которые обычно создаются во вступительной части путем определения tags
. Варианты синтаксиса тегов включают отдельные строки, однострочные массивы — ["tagA", "tagB"]
— для нескольких тегов или списки в стиле YAML для назначения нескольких тегов. Например, я могу создать коллекцию «страницы», добавив следующий заголовок ко всему контенту, который я хочу включить в эту коллекцию:
--- tags: pages ---
После того, как вы определили коллекцию, вы можете получить к ней доступ через выбранный вами язык шаблонов в объекте глобальных collections
. Чтобы получить доступ к нашей коллекции «pages», она будет выглядеть как collections.pages
. Это возвращает массив данных этой коллекции, и поэтому вы можете выполнять операции с массивом, например циклически перебирать его, например, для создания списка ссылок или карточек-тизеров статей. Вы даже можете подавить обычный вывод файлов и использовать только коллекции для управления отображением данных, что полезно для управления одностраничным содержимым сайта.
Пользовательские данные
До сих пор мы говорили о создании контента в виде файлов, но Eleventy также упрощает поддержку различных источников данных. Это называется «пользовательские данные» и хранится в виде экспорта модуля JavaScript или файлов JSON в каталоге _data
.
Пользовательские данные можно использовать для:
- Определите базовый массив JSON.
- Возвращает результаты операции выборки.
- Извлекайте и переформатируйте контент из безголовой CMS.
Eleventy делает все данные из _data
доступными в переменной, соответствующей имени файла. Например, если я создам posts.json
, я смогу получить к нему доступ в своих шаблонах как posts
. Используя Nunjucks, вот пример перебора данных posts
:
{% for post in posts %} {{ post.title }} {% endfor %}
Разбиение на страницы и создание страниц из данных
В терминах Eleventy разбиение на страницы означает перебор набора данных и определение шаблона для вывода этого «фрагмента» данных. Это делается с помощью специального файла, который определяет нумерацию страниц во фронтмастере. Файл также включает в себя настройку предполагаемого вывода данных, что означает, что он также становится собственным шаблоном. Мы можем определить макет для отправки контента, а также добавить теги для создания коллекции для удобства поиска и гибкости вывода.
Примечание . Если вы используете пользовательские данные для извлечения контента из CMS, то разбиение на страницы — это метод Eleventy, который вам нужен для динамического преобразования этих данных в страницы.
Вот пример ссылки на пользовательские данные наших posts
, которые, как мы предполагаем, мы извлекаем из безголовой CMS. Важно отметить, что для size
установлено значение 1, что означает, что каждый «фрагмент разбиения на страницы» должен создавать одну страницу вывода. Затем мы используем alias
для создания ссылки на текущий элемент в цикле разбиения на страницы, а затем используем эту ссылку в определении permalink
и теле шаблона.
Файл, определяющий разбиение на страницы, может находиться где угодно в вашем входном каталоге. Мое организационное предпочтение — создать каталог generate
, а затем назвать его так же, как коллекцию, которую он будет создавать. Рассмотрим следующее как src/generate/posts.njk
:
--- pagination: data: posts size: 1 alias: post addAllPagesToCollections: true permalink: "/{{ post.title | slug }}/" tags: posts layout: post templateEngineOverride: njk, md --- {{ post.body | safe }}
В этом случае permalink
назначает страницу для вывода непосредственно из корня сайта. Вы можете изменить это, добавив префикс, такой как /posts/{{ post.title | slug }}
/posts/{{ post.title | slug }}
, например.
Кроме того, если вы хотите, чтобы все сгенерированные страницы были доступны в коллекции, созданной с помощью тегов, вы должны установить для addAllPagesToCollections
значение true
, чтобы включить больше, чем первый элемент.
Наконец, если ваш контент поступает в формате Markdown вместо предварительно скомпилированного HTML, вам нужно будет использовать templateEngineOverride
. В примере фрагмента я установил его на njk, md
что означает, что содержимое шаблона необходимо будет обрабатывать как Nunjucks для преобразования переменной, так и Markdown для компиляции содержимого, возвращаемого в переменной.
Если вам интересно, что означает safe
, мы собираемся узнать, что дальше!
Как начать работу с одиннадцатью
Итак, вы готовы приступить к работе над своим первым проектом Eleventy! Этот краткий учебник поможет вам создать начальную структуру для продолжения построения. Мы будем использовать концепции, о которых мы уже узнали, а также добавим несколько новых идей.
Первое важное замечание здесь заключается в том, что Eleventy — это пакет с ограниченной областью действия, поэтому вот команда установки:
npm install @11ty/eleventy
Далее, удобное удобство, которое я люблю делать, это добавить следующие скрипты в мой package.json
:
"scripts": { "start": "eleventy --serve", "build": "eleventy" }
Как упоминалось ранее, флаг --serve
активирует локальный сервер через BrowserSync.
Я предпочитаю обновлять каталоги ввода/вывода, как мы уже рассматривали, поэтому теперь пришло время создать некоторый контент в src
или во входном каталоге по вашему выбору.
Чтобы сделать наш проект более гибким и масштабируемым с самого начала, я бы предложил создать хотя бы один макет, содержащий шаблон HTML5. Макеты должны быть определены в непосредственно вызываемом _includes
, который является одним из нескольких ожидаемых каталогов.
Условие, которое вы часто встретите среди новичков, называется base
макета. Я предпочитаю делать это файлом Nunjucks.
Вот пример base.njk
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ title }}</title> </head> <body> <header> <h1>{{ title }}</h1> </header> <main> {{ content | safe }} </main> </body> </html>
Двойные фигурные скобки — это синтаксис Nunjucks для переменных. Здесь мы подготовили входящую переменную title
, которая вскоре будет предоставлена во вступительной части. Переменная content
предоставляется Eleventy и отмечает слот, куда должен помещаться весь входящий контент, не относящийся к главной теме. Важно отметить, что это используется в сочетании с предоставленным safe
фильтром, который предотвращает экранирование скомпилированного HTML, а не его рендеринг.
Теперь пришло время создать индекс нашего сайта, который мы добавим как index.md
:
--- title: Hello Smashing Readers! layout: base.njk --- Thanks for reading — hope you're excited to try Eleventy!
Обратите внимание, что во вступительной части мы добавили заголовок, а также определили макет.
На этом этапе мы можем запустить наш проект с добавленным скриптом: npm start
. Это запустит BrowserSync для настройки localhost:8080
(если он доступен), но вам нужно будет вручную открыть его в браузере. Ознакомьтесь с этим кратким советом, если вы хотите, чтобы браузер открывался автоматически.
Последним важным шагом является добавление таблицы стилей. В настоящее время CSS не распознается как автоматически подключаемый тип файла, поэтому у нас будет один дополнительный шаг настройки после создания таблицы стилей.
Вы можете добавить файл CSS в любое место во входном каталоге, например css/style.css
. Затем откройте .eleventy.js
(или создайте его в корне проекта, если вы не выполняли настройку ввода/вывода) и добавьте следующее:
module.exports = function (eleventyConfig) { eleventyConfig.addPassthroughCopy("./src/css/"); eleventyConfig.addWatchTarget("./src/css/"); // - input/output customization if using - };
Во-первых, мы добавляем каталог css
в качестве «сквозной копии», что означает, что Eleventy должен включить его в отправку в выходной каталог. Затем мы также добавляем его в качестве «наблюдаемой цели», чтобы, когда мы вносим изменения в наши стили во время выполнения нашей команды start
, Eleventy инициировала перестройку для обновления нашего локального сайта.
Наконец, нам нужно не забыть добавить ссылку на нашу таблицу стилей в наш base
макет:
<link rel="stylesheet" href="{{ '/css/style.css' | url }}" />
Когда мы определяем местоположение таблицы стилей, мы пропускаем ее через фильтр url
-адресов Eleventy, который корректирует относительный путь к файлу по мере необходимости при сборке.
Далее давайте создадим тип записи «страницы», чтобы немного больше изучить использование коллекций и макетов. Для этого добавьте каталог pages
и создайте один или два файла Markdown, включая ключ title
, но не макет.
На этот раз мы собираемся использовать немного другой метод для определения макета — файл каталога данных . Этот файл обычно имеет формат JSON и позволяет нам добавлять данные, которые должны применяться ко всем файлам в каталоге, что предотвращает их дублирование в разных файлах. Файл должен называться так же, как каталог, для которого он будет использоваться, поэтому создайте файл pages.json
и добавьте следующее содержимое:
{ "layout": "page.njk", "tags": "pages" }
Мы также пошли дальше и определили теги для создания коллекции «страницы». Но макет, который мы определили, на самом деле еще не существует, поэтому создайте _includes/page.njk
и добавьте следующее:
--- layout: base.njk --- <article> {{ content | safe }} </article>
Здесь мы используем концепцию цепочки макетов Eleventy, чтобы иметь возможность повторно использовать наш base
шаблон, а также добавить уникальный элемент для нашего макета page
, которым является <article>
. Это означает, что все содержимое наших страниц будет использовать как макет page
, так и base
макеты.
Цепочка макетов уменьшает дублирование, позволяя повторно использовать шаблоны и структуры макетов базового сайта.
Теперь, когда мы создали содержимое для типа содержимого pages
и определили его как коллекцию «страницы» с помощью тегов, давайте посмотрим, как мы можем получить доступ к этой коллекции. Здесь мы будем использовать Nunjucks для циклического просмотра коллекции и вывода списка ссылок на каждую страницу. Этот цикл будет добавлен в наш файл index.md
.
{% for post in collections.post -%} - [{{ post.data.title }}]({{ post.url }}) {% endfor %}
Однако мы сделали кое-что уникальное, а именно то, что внутренняя часть цикла фактически переключается обратно на Markdown для отображения ссылок. Это не обязательный способ обработки этого сценария, но он может быть очень удобным! Иногда, в зависимости от сложности, это может не сработать. Настоящая причина в том, что средство визуализации Markdown по умолчанию использует язык шаблонов Liquid , поэтому, если вы используете функции Nunjucks помимо базовых циклов, вам придется сообщить Eleventy, как обрабатывать файл.
В предыдущем разделе о нумерации страниц мы уже рассмотрели решение для этого. И это для использования templateEngineOverride
, чтобы указать, что файл должен обрабатываться как Nunjucks, так и Markdown. Следующее полное решение должно быть помещено во вступительную часть шаблона: templateEngineOverride: njk, md
.
На данный момент вы создали базовый многостраничный сайт! Если вам нужно использовать внешние данные, вернитесь к разделу о нумерации страниц.
Другие способы начать проект Eleventy
В то время как некоторые другие генераторы статических сайтов и среды, такие как WordPress, имеют понятие «темы», Eleventy использует термин «стартер». Существует растущая коллекция на выбор, и многие из них можно найти в списке документов Eleventy.
Я предпочитаю использовать Sass с моими проектами Eleventy, и у меня есть стартовый Sass, если вы хотите посмотреть, как добавить его в процесс сборки. Другие могут добавить Gulp, если они привыкли к этому конвейеру сборки для активов и обработки.
Я также создал минимальную программу для начинающих, которая включает в себя функции, обсуждаемые в этой статье, и имеет сходство с результатом обучения. В нем также есть небольшой пример извлечения внешних данных и показано, как добавить часть для отображения навигации по сайту на основе коллекции.
Расширение основ
После того, как вы поэкспериментировали с созданием своего первого сайта с некоторым базовым контентом и, возможно, некоторыми пользовательскими данными, полезно знать дополнительные способы работы с этим контентом. Вот краткий обзор некоторых других концепций, о которых следует знать.
Изменение типа вывода файла с помощью постоянных ссылок
Я упоминал ранее, что постоянные ссылки обладают суперсилой. И это то, что вы можете использовать их для вывода типов файлов, отличных от HTML.
Два полезных примера — создание RSS-канала и карты сайта, оба из которых обычно представляют собой XML-файлы. Что действительно полезно, так это то, что вы можете продолжать использовать язык шаблонов по вашему выбору для создания этих файлов, поэтому вы можете циклически перебирать данные страницы с помощью Nunjucks, чтобы, например, поддерживать актуальность вашего RSS-канала.
Настройка коллекций
Иногда использования тегов для создания коллекций может быть недостаточно. Или вы можете создать отфильтрованные варианты существующей коллекции. Мы можем изменять или создавать коллекции, используя ряд предоставленных функций. Они будут жить в файле конфигурации .eleventy.js
.
В этом примере мы используем функцию addCollection
для фильтрации элементов в существующей коллекции. Новая коллекция будет основана на наличии customKey
во вступительной части. Этот ключ возвращается из объекта data
, который прикреплен ко всему сгенерированному содержимому Eleventy.
eleventyConfig.addCollection("specialCollection", function (collection) { return collection.getAll().filter((post) => post.data.customKey); });
Вы можете ознакомиться с другими способами создания, изменения и использования коллекций в документации Eleventy.
Работа с каскадом данных
Eleventy имеет более полное представление о том, как данные компилируются для шаблона, называемого каскадом данных , который мы только начали изучать в этом руководстве. Вы получите максимальную отдачу от Eleventy, если ознакомитесь с тем, как это работает, начиная с документации. У Бена Майерса также есть отличное руководство по пониманию каскада данных.
Рекомендуемые одиннадцать плагинов
Во вступлении я кратко упомянул, что есть доступные плагины, но они не всегда нужны. Тем не менее, есть несколько, которые я обычно использую в большинстве проектов, в том числе:
- @11ty/eleventy-plugin-rss Если вы хотите иметь RSS-канал, этот официальный плагин предоставляет несколько фильтров, которые помогут вам создать канал. Связанный репозиторий включает образец фида, который вы также можете найти в некоторых стартовых приложениях.
- @11ty/eleventy-plugin-syntaxhighlight Вместо того, чтобы загружать Prism как скрипт для подсветки кода, этот плагин позволяет применять эту обработку как часть процесса сборки Eleventy. Это означает, что блоки кода преобразуются для включения классов для применения темы Prism заранее, поэтому вам нужно будет только добавить тему Prism CSS по вашему выбору.
- @11tyrocks/eleventy-plugin-social-images Функция, которую я искал в начале своего исследования Eleventy, заключалась в возможности создавать изображения для обмена в социальных сетях. Это привело меня к созданию плагина, который использует Puppeteer за кулисами для создания моментального снимка. Плагин поставляется с готовыми шаблонами, а также с параметрами конфигурации для определения собственного файла шаблона.
Я бы также рекомендовал ознакомиться с остальными официальными плагинами Eleventy, поскольку они удовлетворяют другие общие потребности, включая навигацию и обработку изображений.
Решите, подходит ли одиннадцать для вашего проекта
Eleventy, как и большинство статических сайтов, лучше всего подходит для контента, который обычно не нужно обслуживать динамически или по требованию. Это не означает, что весь сайт должен быть статичным или что не существует способов сделать контент динамичным. Вы по-прежнему можете загружать JavaScript, чтобы активировать динамическое содержимое, например получение из API или создание интерактивных виджетов. Вы также можете использовать такие сервисы, как IFTTT или Zapier, чтобы упростить перестройку своего сайта, если ваш хост поддерживает сборку веб-перехватчиков и у вас есть части, которые вы хотите обновлять по расписанию.
Благодаря пользовательским данным и нумерации страниц мы увидели, что можно легко включать внешние данные, например, из безголовой CMS или любого другого API. Таким образом, несмотря на то, что он будет обслуживаться статически, у вас по-прежнему будет большая гибкость в том, где вы извлекаете контент и как вы им управляете.
Что мне больше всего нравится в Eleventy, так это то, что он не навязывает много мнений о том, как я должен структурировать свой сайт, за исключением нескольких ожидаемых каталогов, о которых мы говорили для _includes
и _data
(и вы также можете обновить соглашение об именах для них). Это также может быть полезно, если вы хотите перенести сайт и потенциально можете переместить некоторую существующую файловую структуру. Однако, если вы предпочитаете более самоуверенную архитектуру, вы можете выбрать другой вариант.
Мне также нравится, как я могу формировать Eleventy, чтобы он соответствовал моей ментальной модели для данного проекта, используя несколько языков шаблонов, а также фильтры, шорткоды и макеты. Стартеры также помогают дать толчок, чтобы вы могли сосредоточиться на том, что действительно важно: на вашем контенте. И высокая производительность чисто статического вывода также является большим преимуществом.
Если вам нужно немного больше в процессе сборки, вы можете добавить другие знакомые инструменты, такие как Webpack, Gulp или Parcel. Возможно, вы сможете найти стартер, который уже включает эти вещи. Имейте в виду, что вы также можете использовать скрипты Node, которые уже встроены в процесс сборки Eleventy.
Eleventy очень хорошо справляется с созданием большого количества страниц. Он использовался для некоторых крупных и сложных сайтов, таких как web.dev Google и маркетинговый сайт Netlify. Я также использовал Eleventy для некоторых нетрадиционных целей, таких как генераторы электронной почты и веб-компонентов, наряду с некоторыми другими, которые описаны в этом обзоре.
Дополнительные ресурсы
Я надеюсь, что это руководство заинтересовало вас и подготовило к использованию Eleventy! Он включал в себя множество моментов, которые мне было немного сложно раскрыть, когда я создавал свой первый проект с его помощью. С тех пор, как я впервые нашел Eleventy в апреле 2020 года, я создал более 20 проектов Eleventy, включая стартеры, плагины, сторонние проекты и учебные материалы. Многие из них можно найти на моем сайте 11ty.Rocks, где также есть руководства и советы. Одиннадцать — это то, что мне очень нравится обсуждать, поэтому не стесняйтесь обращаться к нам в Твиттере!
Ниже приведены дополнительные ресурсы, которые помогут вам в вашем путешествии, чтобы узнать и получить максимальную отдачу от Eleventy:
- Энди Белл предлагает очень подробный платный курс «Learn Eleventy From Scratch».
- Серия учебных пособий Татьяны Мак, начинающаяся с «Руководства по Eleventy для начинающих», содержит подробные объяснения, которые предполагают отсутствие опыта работы с генераторами статических сайтов.
- Брайан Робинсон предлагает курс YouTube по преобразованию бесплатной HTML-темы в сайт Eleventy.
Напоследок хочу отметить, что сообщество Eleventy небольшое, но активное! Если у вас когда-нибудь возникнут трудности с поиском какой-либо информации, вы можете отправить свой вопрос в официальном аккаунте @eleven_ty в Твиттере. Создатель Eleventy, Зак Лезерман, быстро отвечает на вопросы или вопросы в прямом эфире, чтобы помочь вам вернуться на правильный путь!