Прекомпиляция HTML шаблонов в Ruby on Rails

Assets Pipeline - это своего рода фреймворк внутри Ruby on Rails, одной из задач которого является конкатенация и минификация (компрессия) CSS и JavaScript ресурсов перед запуском приложения, скажем на продакшн сервере. Все это замечательно работает "из коробки" и не требует дополнительных настроек со стороны разработчика. Однако в данном посте я расскажу как расширить стандартный процесс компиляции ресурсов из Assets Pipeline для обработки других типов файлов на примере HTML.

В моем случае приложение использует Angular на клиенте и асинхронно загружает HTML-представления с сервера. Решение о том чтобы хранить эти представления в Assets Pipeline было обусловлено несколькими причинами. Первая и самая важная - это возможность ссылаться на HTML-шаблоны из .erb файлов с помощью asset_path("templates/example.html"). Вторая причина - это поддержка версионности для всех ресурсов в Assets Pipeline. Ну и наконец третья - это возможность минифицировать HTML файлы при запуске приложения rake assets:precompile.

За процесс конкатенации и минификации CSS и JavaScript ресурсов в Assets Pipeline отвечает библиотека Sprockets. Не углубляясь в подробности, давайте создадим новый процессор /lib/sprockets/html_processor.rb для минификации HTML ресурсов.

class HtmlProcessor < Sprockets::Processor
  def evaluate(context, locals)
    HtmlMinifier.minify(data, {
      removeComments: true,
      collapseWhitespace: true,
      preserveLineBreaks: true
    })
  end
end

Мы расширили класс Sprockets::Processor и определили метод evaluate. Значением переменной data является содержимое текущего обрабатываемого HTML файла. Минификация происходит с помощью библиотеки html_minifier, поэтому в Gemfile предварительно нужно добавить следующую строку:

gem 'html_minifier'

Следующим шагом станет регистрация только что созданного процессора HtmlProcessor. Для этого в /config/initializers/assets.rb добавляем:

# Custom processors.
Rails.application.config.assets.configure do |env|
  env.register_preprocessor 'text/html', HtmlProcessor
end

Здесь мы явно указываем что файлы с mime-типом text/html должно быть обработаны с помощью HtmlProcessor. Если вы запустите rake assets:precompile, то убедитесь что скомпилированные HTML ресурсы в /public/assets/... будут минифицированы.

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

Update #1

Описанный выше процессор HtmlProcessor справедлив для Sprockets версии 2.x. Если у вас библиотека Sprockets версии 3.x, то необходимо внести следующие изменения:

class HtmlProcessor
  def self.call(input)
    HtmlCompressor::Compressor.new(
      remove_multi_spaces: true,
      remove_comments: true,
      preserve_line_breaks: true
    ).compress(input[:data])
  end
end

Теперь не надо расширять Sprockets::Processor, а имя метода должно быть call с единственным аргументом input. Содержимое компилируемого ресурса "достается" из input[:data].