Skip to content

Commit 7d53c55

Browse files
committed
Merge pull request #84 from schneems/schneems/better-sprockets-errors
Match Dev Asset Experience to Production
2 parents 3a8971a + a87582b commit 7d53c55

File tree

5 files changed

+116
-7
lines changed

5 files changed

+116
-7
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
### Master
2+
3+
* Assets not in the precompile list can be checked for errors by setting
4+
`config.assets.raise_runtime_errors = true` in any environment
5+
6+
*Richard Schneeman*
7+
8+
19
### 2.0.1
210

311
* Allow keep value to be specified for `assets:clean` run with args

lib/sprockets/rails/helper.rb

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Helper
88
# support for Ruby 1.9.3 && Rails 3.0.x
99
@_config = ActiveSupport::InheritableOptions.new({}) unless defined?(ActiveSupport::Configurable::Configuration)
1010
include ActiveSupport::Configurable
11-
config_accessor :raise_runtime_errors
11+
config_accessor :precompile, :assets, :raise_runtime_errors
1212

1313
class DependencyError < StandardError
1414
def initialize(path, dep)
@@ -18,6 +18,15 @@ def initialize(path, dep)
1818
end
1919
end
2020

21+
class AssetFilteredError < StandardError
22+
def initialize(source)
23+
msg = "Asset filtered out and will not be served: " <<
24+
"add `config.assets.precompile += %w( #{source} )` " <<
25+
"to `config/application.rb` and restart your server"
26+
super(msg)
27+
end
28+
end
29+
2130
if defined? ActionView::Helpers::AssetUrlHelper
2231
include ActionView::Helpers::AssetUrlHelper
2332
include ActionView::Helpers::AssetTagHelper
@@ -62,6 +71,21 @@ def compute_asset_path(path, options = {})
6271
end
6372
end
6473

74+
# Computes the full URL to a asset in the public directory. This
75+
# method checks for errors before returning path.
76+
def asset_path(source, options = {})
77+
check_errors_for(source)
78+
path_to_asset(source, options)
79+
end
80+
alias :path_to_asset_with_errors :asset_path
81+
82+
# Computes the full URL to a asset in the public directory. This
83+
# will use +asset_path+ internally, so most of their behaviors
84+
# will be the same.
85+
def asset_url(source, options = {})
86+
path_to_asset_with_errors(source, options.merge(:protocol => :request))
87+
end
88+
6589
# Get digest for asset path.
6690
#
6791
# path - String path
@@ -104,6 +128,7 @@ def javascript_include_tag(*sources)
104128

105129
if options["debug"] != false && request_debug_assets?
106130
sources.map { |source|
131+
check_errors_for(source)
107132
if asset = lookup_asset_for_path(source, :type => :javascript)
108133
asset.to_a.map do |a|
109134
super(path_to_javascript(a.logical_path, :debug => true), options)
@@ -123,9 +148,9 @@ def javascript_include_tag(*sources)
123148
# Eventually will be deprecated and replaced by source maps.
124149
def stylesheet_link_tag(*sources)
125150
options = sources.extract_options!.stringify_keys
126-
127151
if options["debug"] != false && request_debug_assets?
128152
sources.map { |source|
153+
check_errors_for(source)
129154
if asset = lookup_asset_for_path(source, :type => :stylesheet)
130155
asset.to_a.map do |a|
131156
super(path_to_stylesheet(a.logical_path, :debug => true), options)
@@ -141,14 +166,33 @@ def stylesheet_link_tag(*sources)
141166
end
142167

143168
protected
144-
145169
# Checks if the asset is included in the dependencies list.
146170
def check_dependencies!(dep)
147171
if raise_runtime_errors && !_dependency_assets.detect { |asset| asset.include?(dep) }
148172
raise DependencyError.new(self.pathname, dep)
149173
end
150174
end
151175

176+
# Raise errors when source does not exist or is not in the precompiled list
177+
def check_errors_for(source)
178+
source = source.to_s
179+
return source if !self.raise_runtime_errors || source.blank? || source =~ URI_REGEXP
180+
asset = lookup_asset_for_path(source)
181+
182+
if asset && asset_needs_precompile?(source, asset.pathname.to_s)
183+
raise AssetFilteredError.new(source)
184+
end
185+
end
186+
187+
# Returns true when an asset will not be available after precompile is run
188+
def asset_needs_precompile?(source, filename)
189+
if assets_environment && assets_environment.send(:matches_filter, precompile || [], source, filename)
190+
false
191+
else
192+
true
193+
end
194+
end
195+
152196
# Enable split asset debugging. Eventually will be deprecated
153197
# and replaced by source maps in Sprockets 3.x.
154198
def request_debug_assets?

lib/sprockets/railtie.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ def configure(&block)
113113
app.assets = app.assets.index
114114
end
115115

116+
117+
Sprockets::Rails::Helper.precompile ||= app.config.assets.precompile
118+
Sprockets::Rails::Helper.assets ||= app.assets
116119
Sprockets::Rails::Helper.raise_runtime_errors = app.config.assets.raise_runtime_errors
117120

118121
if config.assets.compile

test/fixtures/error/dependency.js.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<%= asset_path("bar.js") %>
1+
<%= asset_path("bar.js") %>

test/test_helper.rb

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,56 @@ def test_stylesheet_path
372372
assert_equal "/assets/foo-#{@foo_css_digest}.css", @view.stylesheet_path("foo")
373373
end
374374

375+
def test_public_folder_fallback_works_correctly
376+
@view.raise_runtime_errors = true
377+
@view.debug_assets = true
378+
379+
@view.asset_path("asset-does-not-exist-foo.js")
380+
@view.asset_url("asset-does-not-exist-foo.js")
381+
@view.stylesheet_link_tag("asset-does-not-exist-foo.js")
382+
@view.javascript_include_tag("asset-does-not-exist-foo.js")
383+
end
384+
385+
def test_asset_not_precompiled_error
386+
@view.raise_runtime_errors = true
387+
@view.precompile = [ lambda {|logical_path| false } ]
388+
@view.assets_environment = @assets
389+
@view.debug_assets = true
390+
391+
assert_raise(Sprockets::Rails::Helper::AssetFilteredError) do
392+
@view.asset_path("foo.js")
393+
end
394+
395+
assert_raise(Sprockets::Rails::Helper::AssetFilteredError) do
396+
@view.asset_url("foo.js")
397+
end
398+
399+
assert_raise(Sprockets::Rails::Helper::AssetFilteredError) do
400+
@view.javascript_include_tag("foo.js")
401+
end
402+
403+
assert_raise(Sprockets::Rails::Helper::AssetFilteredError) do
404+
@view.javascript_include_tag("foo")
405+
end
406+
407+
error = assert_raise(Sprockets::Rails::Helper::AssetFilteredError) do
408+
@view.javascript_include_tag(:foo)
409+
end
410+
411+
assert_raise(Sprockets::Rails::Helper::AssetFilteredError) do
412+
@view.stylesheet_link_tag("foo.js")
413+
end
414+
415+
@view.precompile = [ lambda {|logical_path| true } ]
416+
417+
@view.asset_path("foo.js")
418+
@view.asset_url("foo.js")
419+
@view.javascript_include_tag("foo.js")
420+
@view.javascript_include_tag("foo")
421+
@view.javascript_include_tag(:foo)
422+
@view.stylesheet_link_tag("foo.js")
423+
end
424+
375425
def test_asset_digest_path
376426
assert_equal "foo-#{@foo_js_digest}.js", @view.asset_digest_path("foo.js")
377427
assert_equal "foo-#{@foo_css_digest}.css", @view.asset_digest_path("foo.css")
@@ -384,13 +434,17 @@ def test_asset_digest
384434
end
385435

386436
class ErrorsInHelpersTest < HelperTest
437+
387438
def test_dependency_error
388439
@view.raise_runtime_errors = true
440+
@view.precompile = [ lambda {|logical_path| true } ]
441+
@view.assets_environment = @assets
442+
389443
assert_raise Sprockets::Rails::Helper::DependencyError do
390-
@assets['error/dependency.js'].to_s
444+
@view.asset_path("error/dependency.js")
391445
end
392446

393447
@view.raise_runtime_errors = false
394-
@assets['error/dependency.js'].to_s
448+
@view.asset_path("error/dependency.js")
395449
end
396-
end
450+
end

0 commit comments

Comments
 (0)