Cache de ativos estáticos no Heroku com Jammit alterando ActionController::Base#page_cache_directory
-
12-11-2019 - |
Pergunta
Estou tentando usar o Jammit para empacotar CSS e JS para um aplicativo Rails implantado no Heroku, que não funciona imediatamente devido ao sistema de arquivos somente leitura do Heroku.Todos os exemplos que vi de como fazer isso recomendam a construção antecipada de todos os arquivos de ativos empacotados.Devido à implantação baseada em Git do Heroku, isso significa que você precisa fazer um commit separado em seu repositório sempre que esses arquivos forem alterados, o que não é uma solução aceitável para mim.Em vez disso, quero alterar o caminho que o Jammit usa para gravar os pacotes em cache. #{Rails.root}/tmp/assets
(alterando ActionController::Base#page_cache_directory
), que pode ser gravado no Heroku.
O que não entendo é como os arquivos em cache serão usados sem atingir a pilha do Rails todas as vezes, mesmo usando o caminho padrão para pacotes em cache.Deixe-me explicar o que quero dizer:
Quando você inclui um pacote usando o auxiliar do Jammit, ele se parece com isto:
<%= include_javascripts :application %>
que gera esta tag de script:
<script src="/assets/application.js" type="text/javascript"></script>
Quando o navegador solicita esse URL, o que realmente acontece é que ele é roteado para Jammit::Controller#package
, que renderiza o conteúdo do pacote para o navegador e então grava uma cópia em cache para #{page_cache_directory}/assets/application.js
.A ideia é que esse arquivo em cache seja construído na primeira solicitação, e as solicitações subsequentes sirvam o arquivo em cache diretamente, sem atingir a pilha do Rails.Examinei o código Jammit e não vejo como isso deveria acontecer.O que impede solicitações subsequentes de /assets/application.js
de simplesmente rotear para Jammit::Controller
novamente e nunca mais usar o arquivo em cache?
Meu palpite é que existe um middleware Rack em algum lugar que não estou vendo que serve o arquivo, se existir, e encaminha a solicitação para o controlador, se não existir.Se for esse o caso, onde está esse código?E como funcionaria ao mudar ActionController::Base#page_cache_directory
(alterando efetivamente onde Jammit grava pacotes em cache)?Desde #{Rails.root}/tmp
estiver acima da raiz do documento público, não há URL mapeada para esse caminho.
Solução
Ótima pergunta!Eu não configurei isso sozinho, mas é algo que pretendo investigar, então você me incentivou a fazer isso.Aqui está o que eu tentaria (eu mesmo tentarei em breve, mas você provavelmente vai me vencer).
config.action_controller.page_cache_directory = "#{Rails.root}/tmp/page_cache"
Agora mude seu config.ru para:
require ::File.expand_path('../config/environment', __FILE__)
run Rack::URLMap.new(
"/" => Your::App.new,
"/assets" => Rack::Directory.new("tmp/page_cache/assets"))
Apenas certifique-se de não ter nada dentro public/assets
, já que isso nunca será atendido.
Notas:
- Isto é para Rails 3.Não tenho certeza da solução no Rails 2.
- Parece
Rack::Directory
define os cabeçalhos de controle de cache para 12 horas para que o Heroku armazene em cache seus ativos no Varnish.Não tenho certeza se o Jammit configura isso em seu controlador, mas mesmo que não o faça, ele será armazenado em cache rapidamente. - Heroku também define
ENV['TMPDIR']
agora também, então você pode usar isso em vez deRails.root + '/tmp'
se você desejar.
Outras dicas
Isso pode ser útil, é para uma joia diferente, mas a ideia é semelhante e estou tentando fazê-la funcionar com os ajudantes de ativos simples.
http://devcenter.heroku.com/articles/using-compass
Infelizmente, parece ser muito difícil fazer com que o Rails faça isso sem corrigir/reescrever o módulo auxiliares de ativos (que se assemelha ao espaguete acoplado).