From fa8b07ce30a05f37e78c79014c3b25851875028d Mon Sep 17 00:00:00 2001 From: schneems Date: Fri, 25 Sep 2020 16:14:08 -0500 Subject: [PATCH] List manifest locations when asset is not found When using an asset manifest file `config.assets.compile = false` the developer might not know that a `assets:precompile` manifest file is being used, or they might not know which file (if there are multiple). To help debug this situation we can detect which asset resolution strategies contain a "file" and output the location of that file: ``` The asset "does_not_exist.js" is not present in the asset pipeline. Checked in manifest file: /Users/rschneeman/Documents/projects/sprockets-rails/tmp/app/public/assets/.sprockets-manifest-7bdd432004acd447a520e289399bcf62.json ``` I lost about 30 minutes debugging an error I was seeing locally while running with RAILS_ENV=production. It was telling me a file "was not present in the asset pipeline" which I took to mean it wasn't in `app/assets` or maybe the config declaration was wrong. Everything looked right, it wasn't until much later I realized that I had somehow gotten an old manifest file generated from an older `assets:precompile`run so it was checking that file to see if the asset was "present in the pipeline". By adding the location of the manifest file to the output, it's more likely that I would have realized that sprockets was only checking that file and that the solution was to re-generate it. --- lib/sprockets/rails/helper.rb | 14 +++++++++++++- sprockets-rails.gemspec | 1 + test/test_railtie.rb | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/sprockets/rails/helper.rb b/lib/sprockets/rails/helper.rb index ee7c5f32..963b3b31 100644 --- a/lib/sprockets/rails/helper.rb +++ b/lib/sprockets/rails/helper.rb @@ -80,7 +80,11 @@ def compute_asset_path(path, options = {}) if asset_path = resolve_asset_path(path, debug) File.join(assets_prefix || "/", legacy_debug_path(asset_path, debug)) else - message = "The asset #{ path.inspect } is not present in the asset pipeline.\n" + message = String.new("The asset #{ path.inspect } is not present in the asset pipeline.\n") + asset_resolver_strategies.each do |strat| + message << "Checked in manifest file: #{strat.filename}\n" if strat.filename + end + raise AssetNotFound, message unless unknown_asset_fallback if respond_to?(:public_compute_asset_path) @@ -284,6 +288,10 @@ def initialize(view) raise ArgumentError, 'config.assets.resolve_with includes :manifest, but app.assets_manifest is nil' unless @manifest end + def filename + @manifest.try(:filename) + end + def asset_path(path, digest, allow_non_precompiled = false) if digest digest_path path, allow_non_precompiled @@ -320,6 +328,10 @@ def initialize(view) @check_precompiled_asset = view.check_precompiled_asset end + def filename + nil + end + def asset_path(path, digest, allow_non_precompiled = false) # Digests enabled? Do the work to calculate the full asset path. if digest diff --git a/sprockets-rails.gemspec b/sprockets-rails.gemspec index 4cc9b265..5b6adf61 100644 --- a/sprockets-rails.gemspec +++ b/sprockets-rails.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |s| s.add_development_dependency "rake" s.add_development_dependency "sass" s.add_development_dependency "uglifier" + s.add_development_dependency "m" s.author = "Joshua Peek" s.email = "josh@joshpeek.com" diff --git a/test/test_railtie.rb b/test/test_railtie.rb index a792b8b4..7d0ca161 100644 --- a/test/test_railtie.rb +++ b/test/test_railtie.rb @@ -290,6 +290,25 @@ def test_action_view_helper_when_no_compile assert_equal app.assets_manifest, @view.assets_manifest end + def test_lists_manifest_files_on_failed_asset_lookup_in_prod + app.configure do + config.assets.compile = false + config.assets.unknown_asset_fallback = false + end + + assert_equal false, app.config.assets.compile + + app.initialize! + + @view = ActionView::Base.new + error = assert_raises do + @view.asset_path("does_not_exist.js") + end + + assert_match(/Checked in manifest/, error.message) + assert_match(/\.sprockets-manifest-/, error.message) + end + def test_sprockets_context_helper app.initialize!