Somente pré-compilar ativos quando necessário (Rails 4, Capistrano 3)

O problema

rake assets:precompile pode ocupar uma grande parte do tempo de implementações de aplicativos Rails com Capistano, mesmo em implementações onde os ativos não mudaram!

Outras soluções para pular a pré-compilação desnecessária de ativos parecem depender do Capistrano 2.

A solução

Faça estas alterações em seu deploy.rbarquivo:

Etapa 1: defina os locais para procurar mudanças relevantes para acionar uma pré-compilação

set :assets_dependencies, %w(app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb)

Etapa 2: limpar a tarefa de pré-compilação de implantação anterior

Rake::Task["deploy:assets:precompile"].clear_actions

Etapa 3: definir a nova tarefa de pré-compilação de implantação

3a: Defina um erro personalizado que podemos usar para ter vários pontos de saída para uma pré-compilação de ativo

class PrecompileRequired < StandardError; end

3b: Pré-compilar se for a primeira implantação

latest_release = capture(:ls, '-xr', releases_path).split[1]
raise
PrecompileRequired unless latest_release

3c: Pré-compilar se a implantação anterior falhou ao concluir a pré-compilação do ativo

latest_release_path = releases_path.join(latest_release)
execute
(:ls, latest_release_path.join('assets_manifest_backup')) rescue raise(PrecompileRequired)

3d: pré-compilar se houver uma diferença em asset_dependencies definido na etapa 1 em comparação com a implantação anterior

fetch(:assets_dependencies).each do |dep|
execute
(:diff, '-Naur', release_path.join(dep), latest_release_path.join(dep)) rescue raise(PrecompileRequired)
end

3e: Se nenhuma das condições acima for atendida, copie os ativos da implantação anterior

execute(:cp, '-r', latest_release_path.join('public', fetch(:assets_prefix)), release_path.join('public', fetch(:assets_prefix)))

3f: Se uma pré-compilação for necessária, faça!

rescue PrecompileRequired
execute
(:rake, "assets:precompile")
end

Todos juntos agora:

# set the locations that we will look for changed assets to determine whether to precompile
set
:assets_dependencies, %w(app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb)

# clear the previous precompile task
Rake::Task["deploy:assets:precompile"].clear_actions
class PrecompileRequired < StandardError; end

namespace
:deploy do
namespace
:assets do
desc
"Precompile assets"
task
:precompile do
on roles
(fetch(:assets_roles)) do
within release_path
do
with rails_env
: fetch(:rails_env) do
begin
# find the most recent release
latest_release
= capture(:ls, '-xr', releases_path).split[1]

# precompile if this is the first deploy
raise
PrecompileRequired unless latest_release

latest_release_path
= releases_path.join(latest_release)

# precompile if the previous deploy failed to finish precompiling
execute
(:ls, latest_release_path.join('assets_manifest_backup')) rescue raise(PrecompileRequired)

fetch
(:assets_dependencies).each do |dep|
# execute raises if there is a diff
execute
(:diff, '-Naur', release_path.join(dep), latest_release_path.join(dep)) rescue raise(PrecompileRequired)
end

info
("Skipping asset precompile, no asset diff found")

# copy over all of the assets from the last release
execute
(:cp, '-r', latest_release_path.join('public', fetch(:assets_prefix)), release_path.join('public', fetch(:assets_prefix)))
rescue PrecompileRequired
execute
(:rake, "assets:precompile")
end
end
end
end
end
end
end