Статьи

Как создать статический сайт с Metalsmith

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

Статический сайт может быть подходящим для ряда проектов, включая:

  • Небольшой сайт или личный блог. Сайты с несколькими десятками страниц, редкими постами и одним или двумя авторами могут быть идеальными.
  • Техническая документация, такая как REST API.
  • Прототипы приложений, требующие ряда просмотров веб-страниц.
  • Электронная книга — файлы Markdown могут быть преобразованы в PDF или другие форматы, а также в HTML.

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

Почему Металлсмит?

Бесспорным чемпионом статического сайта является Jekyll — проект Ruby, запущенный в 2008 году. Вам не обязательно требовать знания Ruby для использования Jekyll, но это поможет. К счастью, существует широкий спектр генераторов статических сайтов с открытым исходным кодом для большинства популярных языков. Опции JavaScript включают в себя Hexo , Harp и Assemble . Вы также можете использовать инструмент сборки, такой как Gulp, для более простых проектов.

Я выбрал Metalsmith для этого урока, потому что он:

  1. не предназначен для конкретных типов проектов, таких как блоги
  2. поддерживает широкий спектр параметров шаблона и формата данных
  3. легкий
  4. имеет мало зависимостей
  5. использует модульную структуру
  6. предлагает простую архитектуру плагинов, и
  7. легко начать.

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

Я использовал Metalsmith пару раз — пожалуйста, не думайте, что это лучший способ построить каждый статический сайт!

Установите Metalsmith

Убедитесь, что у вас установлен Node.js (например, с помощью nvm ), затем создайте новый каталог проекта, например, project и инициализируйте файл package.json :

 cd project && cd project npm init -y 

Теперь установите Metalsmith и различные плагины, которые мы будем использовать для создания нашего сайта. Эти:

  • Metalsmith-assets — включает статические активы в вашу сборку Metalsmith.
  • Metallsith-Browser-Sync — включает BrowserSync в ваш рабочий процесс
  • Metalsmith-collection — добавляет коллекции файлов в глобальные метаданные.
  • metallmith-feed — генерирует RSS-канал для коллекции
  • metallmith-html-minifier — минимизирует HTML-файлы, используя kangax / html-minifier
  • metalmith-in-place — отображает синтаксис шаблонов в исходных файлах
  • Metalsmith-Layouts — применяет макеты к вашим исходным файлам.
  • Metalsmith-mapsite — генерирует файл sitemap.xml
  • metalmith-markdown — конвертирует файлы уценки
  • metalmith-permalinks — применяет пользовательский шаблон постоянных ссылок к файлам
  • Metallsith-Publish — добавляет поддержку черновика, частных и будущих сообщений
  • metallmith-word-count — вычисляет количество слов / среднее время чтения всех абзацев в файле HTML
 npm install --save-dev metalsmith metalsmith-assets metalsmith-browser-sync metalsmith-collections metalsmith-feed metalsmith-html-minifier metalsmith-in-place metalsmith-layouts metalsmith-mapsite metalsmith-markdown metalsmith-permalinks metalsmith-publish metalsmith-word-count handlebars 

Структура проекта

Мы будем использовать следующую структуру для каталогов source ( src ) и build ( build ) в рамках проекта.

Вы можете создать свои файлы примеров, как описано ниже, или скопировать их непосредственно из каталога src демонстрации .

страницы

Файлы разметки страницы содержатся в src/html . Он может содержать один уровень подкаталогов для каждого раздела сайта, т.е.

  • src/html/start — страницы, описывающие проект в определенном порядке
  • src/html/article — разные статьи в обратном хронологическом порядке
  • src/html/contact — страница с одним контактом

Каждый каталог содержит один файл index.md который является страницей по умолчанию для этого раздела. Другие страницы могут использовать любое уникальное имя.

Процесс сборки преобразует эти файлы в постоянные ссылки на основе каталогов, например

  • src/html/start/index.md становится /start/index.html
  • src/html/start/installation.md становится /start/installation/index.html

Каждый файл Markdown содержит содержимое и метаинформацию, известную как «front-material», вверху между --- маркерами, например

 --- title: My page title description: A description of this page. layout: page.html priority: 0.9 date: 2016-04-19 publish: draft --- This is a demonstration page. ## Example title Body text. 

Большая часть переднего вопроса является необязательной, но вы можете установить:

  • priority : число от 0 (низкий) до 1 (высокий), которое мы будем использовать для упорядочения меню и определения файлов сайтов XML.
  • publish : можно установить draft , private или будущую дату, чтобы гарантировать, что она не будет опубликована, пока не потребуется.
  • date : дата статьи. Если ничего не установлено, мы будем использовать любую будущую дату публикации или дату создания файла.
  • layout : шаблон HTML для использования.

Шаблоны

Шаблоны HTML-страниц содержатся в src/template . Были определены два шаблона:

Используется система шаблонов Handlebars, хотя поддерживаются альтернативные варианты. Типичный шаблон требует тег {{{ contents }}} чтобы включить содержимое страницы, а также любые внешние значения, такие как {{ title }} :

 <!DOCTYPE html> <html lang="en"> <head> {{> meta }} </head> <body> {{> header }} <main> <article> {{#if title}} <h1>{{ title }}</h1> {{/if}} {{{ contents }}} </article> </main> {{> footer }} </body> </html> 

Ссылки на {{> meta }} , {{> header }} и {{> footer }} являются частичными …

Partials

Частицы — или файлы фрагментов HTML — содержатся в src/partials . Они в основном используются в шаблонах, но также могут быть включены в контентные страницы с помощью кода:

 {{> partialname }} 

где partialname имя — это имя файла в каталоге src/partials .

Статические активы

Статические ресурсы, такие как изображения, файлы CSS и JavaScript, содержатся в src/assets . Все файлы и подкаталоги будут скопированы в корень сайта как есть.

Пользовательские плагины

Пользовательские плагины, необходимые для создания сайта, содержатся в каталоге lib .

Каталог сборки

Сайт будет встроен в каталог build . Мы создадим сайт двумя способами:

  • Режим разработки: HTML не будет минимизирован, и будет запущен тестовый веб-сервер.
  • NODE_ENV режим: если NODE_ENV установлен на NODE_ENV , каталог build стирается и генерируются окончательные свернутые файлы.

Определение вашего первого файла сборки

Базовый пример с именем build.js может быть создан в корневом каталоге вашего проекта:

 // basic build 'use strict'; var metalsmith = require('metalsmith'), markdown = require('metalsmith-markdown'), ms = metalsmith(__dirname) // the working directory .clean(true) // clean the build directory .source('src/html/') // the page source directory .destination('build/') // the destination directory .use(markdown()) // convert markdown to HTML .build(function(err) { // build the site if (err) throw err; // and throw errors }); 

Запустите его, используя node ./build.js и в каталоге build будет создан статический сайт. Уценка будет проанализирована в HTML, но она не будет использоваться, потому что мы не включили шаблоны в наш процесс сборки.

Плагины Metalsmith

Внешне файлы сборки Metalsmith похожи на те, что используются в Gulp (хотя он не использует потоки). Плагин вызывается путем передачи его методу use Metalsmith с любыми подходящими аргументами. Сам плагин должен возвращать другую функцию, которая принимает три параметра:

  • массив files содержащий информацию о каждой странице
  • объект metalsmith содержащий глобальную информацию, такую ​​как метаданные, и
  • готовая функция, которая должна быть вызвана, когда плагин закончил работу

Этот простой пример записывает всю мета и информацию о странице в консоль (это можно определить в build.js ):

 function debug(logToConsole) { return function(files, metalsmith, done) { if (logToConsole) { console.log('\nMETADATA:'); console.log(metalsmith.metadata()); for (var f in files) { console.log('\nFILE:'); console.log(files[f]); } } done(); }; }; 

Код сборки Metalsmith можно обновить, чтобы использовать этот плагин:

 ms = metalsmith(__dirname) // the working directory .clean(true) // clean the build directory .source('src/html/') // the page source directory .destination('build/') // the destination directory .use(markdown()) // convert Markdown to HTML .use(debug(true)) // *** NEW *** output debug information .build(function(err) { // build the site if (err) throw err; // and throw errors }); 

Эта функция отладки может помочь вам создать свои собственные плагины, но большинство функций, которые вам когда-либо могут понадобиться, уже написаны — на веб-сайте Metalsmith имеется длинный список плагинов.

Создание лучшей сборки

Ключевые части файла сборки демонстрационного сайта описаны ниже.

Переменная с именем devBuild устанавливается в значение true если для переменной среды NODE_ENV задано значение production ( export NODE_ENV=production в Mac / Linux или значение set NODE_ENV=production в Windows):

 devBuild = ((process.env.NODE_ENV || '').trim().toLowerCase() !== 'production') 

Основные каталоги определены в объекте dir поэтому мы можем использовать их повторно:

 dir = { base: __dirname + '/', lib: __dirname + '/lib/', source: './src/', dest: './build/' } 

Metalsmith и подключаемые модули загружены. Замечания:

  • отличный тестовый сервер Browsersync требуется только при создании сборки разработки
  • модуль htmlmin HTML, на который ссылается htmlmin требуется только при создании производственной сборки
  • Были определены три пользовательских плагина: setdate , moremeta и debug (более подробно описано ниже)
 metalsmith = require('metalsmith'), markdown = require('metalsmith-markdown'), publish = require('metalsmith-publish'), wordcount = require("metalsmith-word-count"), collections = require('metalsmith-collections'), permalinks = require('metalsmith-permalinks'), inplace = require('metalsmith-in-place'), layouts = require('metalsmith-layouts'), sitemap = require('metalsmith-mapsite'), rssfeed = require('metalsmith-feed'), assets = require('metalsmith-assets'), htmlmin = devBuild ? null : require('metalsmith-html-minifier'), browsersync = devBuild ? require('metalsmith-browser-sync') : null, // custom plugins setdate = require(dir.lib + 'metalsmith-setdate'), moremeta = require(dir.lib + 'metalsmith-moremeta'), debug = consoleLog ? require(dir.lib + 'metalsmith-debug') : null, 

Объект siteMeta определяется информацией, которая применяется к каждой странице. Важными значениями являются domain и rootpath которые устанавливаются в соответствии с разработкой или производственной сборкой:

 siteMeta = { devBuild: devBuild, version: pkg.version, name: 'Static site', desc: 'A demonstration static site built using Metalsmith', author: , contact: 'https://twitter.com/craigbuckler', domain: devBuild ? 'http://127.0.0.1' : 'https://rawgit.com', // set domain rootpath: devBuild ? null : '/sitepoint-editors/metalsmith-demo/master/build/' // set absolute path (null for relative) } 

Объект templateConfig также был определен для установки значений по умолчанию для шаблона. Это будет использоваться metalsmith-in-place и metalsmith-layouts которые включают рендеринг на странице и в шаблонах с помощью Handlebars:

 templateConfig = { engine: 'handlebars', directory: dir.source + 'template/', partials: dir.source + 'partials/', default: 'page.html' } 

Объект Metalsmith теперь запускается, как и раньше, но мы также передаем наш объект siteMeta metadata чтобы информация была доступна на каждой странице. Поэтому мы можем ссылаться на такие элементы, как {{ name }} на любой странице, чтобы получить имя сайта.

 var ms = metalsmith(dir.base) .clean(!devBuild) // clean build before a production build .source(dir.source + 'html/') // source directory (src/html/) .destination(dir.dest) // build directory (build/) .metadata(siteMeta) // add meta data to every page 

Наш первый вызов плагина вызывает metalsmith-publish который удаляет любой файл, для которого значение publish переднего metalsmith-publish имеет draft , private или будущую дату:

 .use(publish()) // draft, private, future-dated 

setdate — это пользовательский плагин, содержащийся в lib / metallmith-setdate.js . Это гарантирует, что для каждого файла установлено значение «дата», даже если ни одно из них не было определено во фронте, возвращаясь к дате publish или времени создания файла, где это возможно:

 .use(setdate()) // set date on every page if not set in front-matter 

metalsmith-collections является одним из наиболее важных плагинов, поскольку он распределяет каждую страницу по категории или таксономии в зависимости от ее расположения в исходном каталоге или других факторов. Он может переупорядочивать файлы с использованием внешнего вида, например date или priority и позволяет вам устанавливать собственные метаданные для этой коллекции. Код определяет:

  • стартовая коллекция для каждого файла в каталоге src/html/start . Он упорядочивает их по значению priority установленному во фронтальной части файла.
  • коллекция статей для каждого файла в каталоге src/html/article . Упорядочивает их по date в обратном хронологическом порядке.
  • коллекция страниц для каждой страницы по умолчанию с именем index.* . Он упорядочивает их по значению priority установленному во фронтальной части файла.
  .use(collections({ // determine page collection/taxonomy page: { pattern: '**/index.*', sortBy: 'priority', reverse: true, refer: false }, start: { pattern: 'start/**/*', sortBy: 'priority', reverse: true, refer: true, metadata: { layout: 'article.html' } }, article: { pattern: 'article/**/*', sortBy: 'date', reverse: true, refer: true, limit: 50, metadata: { layout: 'article.html' } } })) 

Затем идет преобразование Markdown в HTML, за которым metalsmith-permalinks плагин metalsmith-permalinks который определяет структуру каталогов для сборки. Обратите внимание, что :mainCollection устанавливается для каждого файла с помощью moremeta ниже:

  .use(markdown()) // convert Markdown .use(permalinks({ // generate permalinks pattern: ':mainCollection/:title' })) 

metalsmith-word-count подсчитывает количество слов в статье и приблизительно рассчитывает, сколько времени нужно, чтобы прочитать. Аргумент { raw: true } выводит только цифры:

  .use(wordcount({ raw: true })) // word count 

moremeta — это еще один пользовательский плагин, содержащийся в lib / metallmith-moremeta.js . Он добавляет дополнительные метаданные к каждому файлу:

  • root : абсолютный или рассчитанный относительный путь файла к корневому каталогу
  • isPage : установите значение true для страниц раздела по умолчанию с именем index.*
  • mainCollection : имя основной коллекции, start или article
  • layout : если не установлен, шаблон макета может быть определен из метаданных основной коллекции
  • navmain : массив объектов навигации верхнего уровня
  • navsub : массив объектов навигации второго уровня

Код плагина относительно сложен, потому что он обрабатывает навигацию. Существуют более простые варианты, если вам требуется более простая иерархия.

 .use(moremeta()) // determine root paths and navigation 

metalsmith-in-place и metalsmith-layouts на странице и шаблонах соответственно. Передается тот же объект templateConfig определенный выше:

 .use(inplace(templateConfig)) // in-page templating .use(layouts(templateConfig)); // layout templating 

Если htmlmin установлен (в производственной сборке), мы можем минимизировать HTML:

 if (htmlmin) ms.use(htmlmin()); // minify production HTML 

debug — это наш последний пользовательский плагин, содержащийся в lib / metallmith-debug.js . Это похоже на функцию debug описанную выше:

 if (debug) ms.use(debug()); // output page debugging information 

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

 if (browsersync) ms.use(browsersync({ // start test server server: dir.dest, files: [dir.source + '**/*'] })); 

Наконец, мы можем использовать:

  • metalsmith-mapsite для создания metalsmith-mapsite сайта XML
  • metalsmith-feed для создания RSS-канала, содержащего страницы в коллекции статей
  • metalsmith-assets для копирования файлов и каталогов из src/assets напрямую для build без изменений.
 ms .use(sitemap({ // generate sitemap.xml hostname: siteMeta.domain + (siteMeta.rootpath || ''), omitIndex: true })) .use(rssfeed({ // generate RSS feed for articles collection: 'article', site_url: siteMeta.domain + (siteMeta.rootpath || ''), title: siteMeta.name, description: siteMeta.desc })) .use(assets({ // copy assets: CSS, images etc. source: dir.source + 'assets/', destination: './' })) 

Все, что остается, — это последний .build() для создания сайта:

  .build(function(err) { // build if (err) throw err; }); 

По завершении вы можете запустить node ./build.js чтобы снова построить статический сайт.

Гочи

Я многому научился, создав простой веб-сайт Metalsmith, но помнил о следующих проблемах:

Несовместимые плагины

Плагины могут конфликтовать с другими. Например, Metalsmith-rootpath, который вычисляет относительные корневые пути, не очень хорошо работает с metalmith-permalinks, который создает пользовательские структуры каталогов сборки. Я решил эту проблему, написав собственный код вычисления root пути в плагине lib / metallmith-moremeta.js .

Порядок плагинов имеет решающее значение

Плагины могут зависеть друг от друга или конфликтовать, если размещены в неправильном порядке. Например, плагин, генерирующий RSS, должен быть вызван после раскладки металлов, чтобы убедиться, что RSS XML не генерируется в шаблоне страницы.

Browsersync перестраивает проблемы

Когда Browsersync работает и файлы редактируются, коллекции повторно анализируются, но старые данные остаются. Возможно, это проблема с пользовательским плагином lib / metallmith-moremeta.js, но меню и последующие / обратные ссылки будут выброшены из синхронизации. Чтобы это исправить, остановите сборку с помощью Ctrl / Cmd + C и перезапустите сборку.

Вам все еще нужен глоток?

Те, кто использует диспетчер задач, такой как Gulp , заметят, что Metalsmith предлагает знакомый процесс сборки. Есть плагины для предварительной обработки CSS с помощью Sass , минимизации изображений , конкатенации файлов , uglification и многого другого. Этого может быть достаточно для более простых рабочих процессов.

Тем не менее, Gulp имеет более широкий набор плагинов и позволяет выполнять сложные операции сборки, такие как связывание, развертывание и обработка PostCSS с автоматическим префиксом . Существует несколько плагинов интеграции Gulp / Metalsmith, хотя у меня возникло несколько проблем, и они не должны быть необходимыми, потому что задача Gulp может запускать Metalsmith напрямую, например

 var gulp = require('gulp'), metalsmith = require('metalsmith'), publish = require('metalsmith-publish'), markdown = require('metalsmith-markdown'); // build HTML files using Metalsmith gulp.task('html', function() { var ms = metalsmith(dir.base) .clean(false) .source('src/html/') .destination('build') .use(publish()) .use(markdown()) .build(function(err) { if (err) throw err; }); }); 

Этот процесс предотвращает проблемы повторной сборки Browsersync, упомянутые выше. Не забудьте использовать .clean(false) чтобы Metalsmith никогда не стирал папку сборки, когда другие задачи активны.

Металлист для тебя?

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

Создание системы сборки Metalsmith занимает много времени, и мы не учли усилия, связанные с шаблонизацией и развертыванием HTML. Однако, как только у вас есть рабочий процесс, становится невероятно просто добавлять, редактировать и удалять файлы Markdown. Это может быть проще, чем использование CMS, и у вас есть все преимущества статического сайта .