Статьи

WordPress -> Ghost -> Арфа (часть 2)

Я написал о переходе от WordPress к Ghost, а затем к Harp в первой части , в этом посте подробно описываются некоторые особенности реализации моего блога.

Технический обзор

Я использую Harp, с которым невероятно легко работать, но я также использую Harp в качестве зависимости внутри своего собственного веб-сервера пользовательских узлов, что позволяет мне добавить несколько свистков в мою реализацию.

Пользовательская перезапись URL

Поскольку я портировал существующий блог, я хотел убедиться, что URL-адреса не изменились. Это означает, что поддерживается мой старый / год / месяц / день / название формата. Что мне не нравилось на протяжении многих лет, но когда я перешел на Арфу, я решил убрать дату из тела своих постов и разрешить URL-адресу указывать эти метаданные.

Я также хотел разместить свои старые загрузки и демонстрации на Amazon S3, но URL-адреса из старых сообщений будут относиться к моему блогу, поэтому мне нужно было переписать их.

Я разветвлял router @ npm, чтобы создать router-stupid @ npm — который по сути тот же, слегка урезанный, но важный: если вы измените req.url в обработчике маршрутов, это повлияет на последующие сопоставленные маршруты.

Перенаправление просто:

/* redirect to s3 hosted urls */
route.all('/demo/{filename}', function (req, res, next) {
  res.writeHead(302, { 'location': 'http://download.remysharp.com/' + req.params.filename });
  res.end();
});

Поддерживать формат URL моей базы данных было сложнее. Фактический файл находится в / blog / <title>, поэтому, когда URL попадает на мой статический сервер, он должен быть в этой форме. Поэтому для поддержки URL базы данных требуется:

  1. Формат URL правильный
  2. Заголовок сообщения фактически находит сообщение
  3. Дата в URL совпадает с датой публикации
/* main url handler: /{year}/{month}/{day}/{post} */
route.all(/^\/([0-9]{4})\/([0-9]{1,2})\/([0-9]{1,2})\/(
 
  .*?)(\/)?$/, 
  function (req, res, next) {
  var params = req.params;

  // the title slug of the url
  var post = blogs
];

  // make sure we have a real post before even proceeding
  if (post && post.date) {
    // test if the date matches

    // post.date is a timestamp, so splitting gets us the date
    var date = moment(post.date.split(' ')[0]);

    var requestDate = params.slice(1, 4).join('-');

    // compare the date of post _in the same format_ as requestDate
    if (date.format('YYYY-MM-DD') !== requestDate) {
      // if it's not good, move on - will likely result in a 404
      return next();
    }

    // if there's a trailing slash, remove it and redirect
    if (params[5] === '/') {
      res.writeHead(302, { 'location': req.url.replace(/(.)\/$/, '$1')});
      res.end();
      return;
    }

    // this now allows Harp to pick up the correct post
    req.url = '/blog/' + params[4];
  }

  // then let the rest of the router do it's work
  next();
});
 

Статическое кеширование

Используя Harp в предыдущих проектах (документация JS Bin , наш сайт событий и мой бизнес-сайт ) и создал harp-static @ npm, который использует st @ npm для кэширования и обслуживания статических файлов.

Так что в моем пользовательском сервере, я указываю все маршруты вплоть до ст служил содержание. Я также поддерживаю переход по URL-адресам без .html в конце, опять же, чтобы мои старые URL-адреса работали. Я бы порекомендовал проверить статический источник арфы, если это вас интересует.

Использование специальных помощников внутри Арфы

В настоящее время, если вы хотите использовать библиотеку внутри Harp, такую ​​как moment.js , можно обойти это путем создания .jade- файла с источником moment.js (в данном случае) в качестве скрипта. По сути, минимизированный однострочный файл с префиксом .

Затем включите библиотеку в общий файл, такой как макет, и у вас будет доступный помощник:

!- load the moment.js library for server side access
!= partial('/js/moment')

Кроме того, это сломалось бы во время компиляции в статические файлы. Я уверен, что это связано с моим настраиваемым процессом обслуживания, но путь будет каким-то образом неправильным (поэтому библиотека не будет загружаться, и далее в моем коде в Jade будут исключения из-за того, что библиотека не существует).

Умный способ обойти это разоблачить глобальный от внешней арфы . Итак, в моем файле server.js (который выполняет всю маршрутизацию и т. Д.) Я требую в moment.js, а затем выставляю его глобально :

// this line, although dirty, ensures that Harp templates
// have access to moment - which given the whole partial
// import hack doesn't work consistently across dynamic vs
// compiled, this is the cleanest solution.
global.moment = moment;

Очень просто, но теперь любой файл, созданный на Harp, имеет доступ к moment.js. Я использую ту же технику, чтобы выставить недавно измененные посты для размещения на главной странице.

Список недавно измененных постов

Лучший способ получить список всех постов за пределами Harp (то есть, когда вам требуется Harp в качестве зависимости), это просто загрузить файл _data.json . Сначала это было неправильно, но это прекрасно:

var blogs = require('./public/blog/_data.json');
var slugs = Object.keys(blogs);

Теперь у меня есть поиск объектов по сообщениям в блоге, и у меня есть массив слагов.

Исходя из этого, я смог fs.stat всех сообщений в блоге и отсортировать их, чтобы получить 3 последних измененных, а затем, используя предыдущий трюк, выставить его глобально, чтобы он был включен в мою домашнюю страницу (где недавний — это глобальный доступ в server.js). ):

each post in recent
  li
    a(href="#{ public.blog._data[post.slug].relative }") #{ public.blog._data[post.slug].title }
    small &nbsp;updated #{ moment(post.date).fromNow() }

Архивировать и помечать страницы без повторения файлов

В этом разделе есть две части. Во-первых, есть поддержка отдельных лет или тегов без дублирования (слишком много) кода. Во-вторых, это код Jade, который запускает распечатку архива.

Сокращение дублирования кода

Я мог бы иметь каталог для каждого года, в котором есть сообщения в блоге (которые у меня есть сейчас), и каждый из них может содержать код листинга архива. Проблема (очевидно) заключается в дублировании кода. Вы исправляете это в одном месте, и (в моем случае, так как у меня 2006-2014) у вас есть 8 файлов для обновления.

Вместо этого один файл index.jade находится в папке с тегами (и аналогично папкам года), которая содержит:

!= partial('../../_partials/tag')

Таким образом, мы загружаем один частичный. Tag.jade файл просто считывает путь запроса, и использует последнюю часть в качестве фильтра против всех сообщений:

tag = filter === undefined ? current.path.slice(-2, -1)[0] : filter;
posts = partial('posts', { filter: function (post) { return post.tags.indexOf(tag) !== -1 } })
.post
  h1.title Tagged with "#{ tag }"
  .post-content
    ul
      while posts.length
        post = posts.shift()
        if post.date
          li
            a(href="#{ post.relative }") #{ post.title }
            small.date #{ moment(post.date).format('D-MMM YYYY')}

Обратите внимание, что частичное (‘posts’) — это волшебное частичное, которое просто возвращает массив сообщений в блоге с примененным фильтром.

Просто. Теперь, если я хочу добавить больше поддержки тегов, я просто создаю каталог и простой index.jade, и он работает.

Распечатка архива

Цикл while, который ищет изменение даты в году, затем работает каждый год, выталкивая из массива постов циклически перебирая все посты месяца.

Это довольно круто (я думаю), потому что оно работает целые годы и все годы: archive.jade

Процесс выпуска на основе Makefile

Отказ от ответственности: это ужасное использование Makefile, оно не использует никаких преимуществ make, и, честно говоря, это может быть скрипт bash. Тем не менее, мне нравится, что я могу запустить make publish .

Принимая свинец из Makefile рецептов для пакетов Node.js , мой Makefile позволяет мне выполнять команды , как:

$ make release-minor publish

В release- * задачи будут:

  1. Увеличьте версию пакета (в соответствии с patch / minor / major)
  2. Компилировать арфу в статические файлы
  3. Зафиксируйте все изменения и отметьте
  4. Нажмите, чтобы GitHub

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

Вот и все! Вот полный исходный код remysharp.com — не стесняйтесь помогать себе во всем, что полезно для ваших собственных блогов или сайтов.