assets:precompileの結果を1世代だけ残す

Sprocketsは assets:clean[0] しても1時間以内に作成したassetsは消してくれません。

参照: https://github.com/rails/sprockets/blob/v4.0.2/lib/sprockets/manifest.rb#L245

さらに assets:clean の後に webpacker:clean を実行してくれるけど、引数は伝搬してくれない。

参考: https://github.com/rails/webpacker/blob/v6.0.0.pre.2/lib/tasks/webpacker/clean.rake#L19-L21

webpacker:clean に引数を伝搬させる

webpackerが登録してるProcを削除し、 enhance でタスクを登録し直す。

# Rakefile

assets_clean = Rake::Task['assets:clean']
assets_clean.actions.reject! { |act| act.source_location[0].include?('webpacker/clean.rake') }
assets_clean.enhance(['webpacker:clean'])

assets:clean[keep,age] に対応させる

with_loggerやmanifestを使えるように binding を取得して頑張る。

# Rakefile

assets_clean = Rake::Task['assets:clean']
assets_clean.arg_names << :age
pos = assets_clean.actions.index { |act| act.source_location[0].include?('sprockets/rails/task.rb') }
act = assets_clean.actions[pos]
assets_clean.actions[pos] = lambda do |_t, args, **opts|
  keep = Integer(args.keep || act.binding.eval('self.keep'))
  age = Integer(args.age || 3600)

  act.binding.eval(<<~RUBY)
    with_logger do
      manifest.clean(#{keep}, #{age})
    end
  RUBY
end

まとめ

これにより bin/rails assets:precompile assets:clean[0] を実行すると、1世代だけassetsを残せる。