sprockets-rails 2.3.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +43 -31
- data/lib/sprockets/rails/context.rb +48 -0
- data/lib/sprockets/rails/helper.rb +249 -128
- data/lib/sprockets/rails/route_wrapper.rb +23 -0
- data/lib/sprockets/rails/task.rb +10 -14
- data/lib/sprockets/rails/utils.rb +11 -0
- data/lib/sprockets/rails/version.rb +1 -1
- data/lib/sprockets/railtie.rb +125 -76
- metadata +15 -22
- data/LICENSE +0 -20
- data/lib/sprockets/rails/legacy_asset_tag_helper.rb +0 -32
- data/lib/sprockets/rails/legacy_asset_url_helper.rb +0 -133
@@ -1,128 +1,119 @@
|
|
1
1
|
require 'action_view'
|
2
2
|
require 'sprockets'
|
3
3
|
require 'active_support/core_ext/class/attribute'
|
4
|
+
require 'sprockets/rails/utils'
|
4
5
|
|
5
6
|
module Sprockets
|
6
7
|
module Rails
|
7
8
|
module Helper
|
8
|
-
class
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def precompile
|
13
|
-
Sprockets::Rails::Helper.precompile
|
14
|
-
end
|
15
|
-
|
16
|
-
def assets
|
17
|
-
Sprockets::Rails::Helper.assets
|
18
|
-
end
|
19
|
-
|
20
|
-
def raise_runtime_errors
|
21
|
-
Sprockets::Rails::Helper.raise_runtime_errors
|
22
|
-
end
|
23
|
-
|
24
|
-
class AssetFilteredError < StandardError
|
9
|
+
class AssetNotPrecompiled < StandardError
|
10
|
+
include Sprockets::Rails::Utils
|
25
11
|
def initialize(source)
|
26
|
-
msg =
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
12
|
+
msg =
|
13
|
+
if using_sprockets4?
|
14
|
+
"Asset `#{source}` was not declared to be precompiled in production.\n" +
|
15
|
+
"Declare links to your assets in `assets/config/manifest.js`.\n" +
|
16
|
+
"Examples:\n" +
|
17
|
+
"`//= link ../javascripts/application.js`\n" +
|
18
|
+
"`//= link_directory ../javascripts .js`\n" +
|
19
|
+
"`//= link_directory ../stylesheets .css`\n" +
|
20
|
+
"`//= link_tree ../javascripts .js`\n" +
|
21
|
+
"`//= link_tree ../images`\n" +
|
22
|
+
"and restart your server"
|
23
|
+
else
|
24
|
+
"Asset was not declared to be precompiled in production.\n" +
|
25
|
+
"Add `Rails.application.config.assets.precompile += " +
|
26
|
+
"%w( #{source} )` to `config/initializers/assets.rb` and " +
|
27
|
+
"restart your server"
|
28
|
+
end
|
37
29
|
super(msg)
|
38
30
|
end
|
39
31
|
end
|
40
32
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
else
|
45
|
-
require 'sprockets/rails/legacy_asset_tag_helper'
|
46
|
-
require 'sprockets/rails/legacy_asset_url_helper'
|
47
|
-
include LegacyAssetTagHelper
|
48
|
-
include LegacyAssetUrlHelper
|
49
|
-
end
|
33
|
+
include ActionView::Helpers::AssetUrlHelper
|
34
|
+
include ActionView::Helpers::AssetTagHelper
|
35
|
+
include Sprockets::Rails::Utils
|
50
36
|
|
51
|
-
VIEW_ACCESSORS = [
|
52
|
-
|
37
|
+
VIEW_ACCESSORS = [
|
38
|
+
:assets_environment, :assets_manifest,
|
39
|
+
:assets_precompile, :precompiled_asset_checker,
|
40
|
+
:assets_prefix, :digest_assets, :debug_assets,
|
41
|
+
:resolve_assets_with
|
42
|
+
]
|
53
43
|
|
54
44
|
def self.included(klass)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
45
|
+
klass.class_attribute(*VIEW_ACCESSORS)
|
46
|
+
|
47
|
+
klass.class_eval do
|
48
|
+
remove_method :assets_environment
|
49
|
+
def assets_environment
|
50
|
+
if instance_variable_defined?(:@assets_environment)
|
51
|
+
@assets_environment = @assets_environment.cached
|
52
|
+
elsif env = self.class.assets_environment
|
53
|
+
@assets_environment = env.cached
|
54
|
+
else
|
55
|
+
nil
|
56
|
+
end
|
60
57
|
end
|
61
|
-
else
|
62
|
-
klass.class_attribute(*VIEW_ACCESSORS)
|
63
58
|
end
|
64
59
|
end
|
65
60
|
|
66
61
|
def self.extended(obj)
|
67
62
|
obj.class_eval do
|
68
63
|
attr_accessor(*VIEW_ACCESSORS)
|
64
|
+
|
65
|
+
remove_method :assets_environment
|
66
|
+
def assets_environment
|
67
|
+
if env = @assets_environment
|
68
|
+
@assets_environment = env.cached
|
69
|
+
else
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
end
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
72
76
|
def compute_asset_path(path, options = {})
|
73
|
-
|
74
|
-
check_dependencies!(path) if defined?(depend_on)
|
77
|
+
debug = options[:debug]
|
75
78
|
|
76
|
-
if
|
77
|
-
|
78
|
-
path += "?body=1" if options[:debug]
|
79
|
-
File.join(assets_prefix || "/", path)
|
79
|
+
if asset_path = resolve_asset_path(path, debug)
|
80
|
+
File.join(assets_prefix || "/", legacy_debug_path(asset_path, debug))
|
80
81
|
else
|
81
82
|
super
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
|
-
#
|
86
|
-
#
|
87
|
-
def
|
88
|
-
|
89
|
-
|
86
|
+
# Resolve the asset path against the Sprockets manifest or environment.
|
87
|
+
# Returns nil if it's an asset we don't know about.
|
88
|
+
def resolve_asset_path(path, allow_non_precompiled = false) #:nodoc:
|
89
|
+
resolve_asset do |resolver|
|
90
|
+
resolver.asset_path path, digest_assets, allow_non_precompiled
|
90
91
|
end
|
91
|
-
super(source, options)
|
92
92
|
end
|
93
|
-
alias :path_to_asset :asset_path
|
94
93
|
|
95
|
-
#
|
94
|
+
# Expand asset path to digested form.
|
96
95
|
#
|
97
96
|
# path - String path
|
98
97
|
# options - Hash options
|
99
98
|
#
|
100
|
-
# Returns String
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
if digest_path = asset_digest_path(path, options)
|
105
|
-
digest_path[/-(.+)\./, 1]
|
99
|
+
# Returns String path or nil if no asset was found.
|
100
|
+
def asset_digest_path(path, options = {})
|
101
|
+
resolve_asset do |resolver|
|
102
|
+
resolver.digest_path path, options[:debug]
|
106
103
|
end
|
107
104
|
end
|
108
105
|
|
109
|
-
#
|
106
|
+
# Experimental: Get integrity for asset path.
|
110
107
|
#
|
111
108
|
# path - String path
|
112
109
|
# options - Hash options
|
113
110
|
#
|
114
|
-
# Returns String
|
115
|
-
def
|
116
|
-
|
117
|
-
if digest_path = manifest.assets[path]
|
118
|
-
return digest_path
|
119
|
-
end
|
120
|
-
end
|
111
|
+
# Returns String integrity attribute or nil if no asset was found.
|
112
|
+
def asset_integrity(path, options = {})
|
113
|
+
path = path_with_extname(path, options)
|
121
114
|
|
122
|
-
|
123
|
-
|
124
|
-
return asset.digest_path
|
125
|
-
end
|
115
|
+
resolve_asset do |resolver|
|
116
|
+
resolver.integrity path
|
126
117
|
end
|
127
118
|
end
|
128
119
|
|
@@ -131,21 +122,27 @@ module Sprockets
|
|
131
122
|
# Eventually will be deprecated and replaced by source maps.
|
132
123
|
def javascript_include_tag(*sources)
|
133
124
|
options = sources.extract_options!.stringify_keys
|
125
|
+
integrity = compute_integrity?(options)
|
134
126
|
|
135
127
|
if options["debug"] != false && request_debug_assets?
|
136
128
|
sources.map { |source|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
129
|
+
if asset = lookup_debug_asset(source, :type => :javascript)
|
130
|
+
if asset.respond_to?(:to_a)
|
131
|
+
asset.to_a.map do |a|
|
132
|
+
super(path_to_javascript(a.logical_path, :debug => true), options)
|
133
|
+
end
|
134
|
+
else
|
135
|
+
super(path_to_javascript(asset.logical_path, :debug => true), options)
|
141
136
|
end
|
142
137
|
else
|
143
138
|
super(source, options)
|
144
139
|
end
|
145
140
|
}.flatten.uniq.join("\n").html_safe
|
146
141
|
else
|
147
|
-
sources.
|
148
|
-
|
142
|
+
sources.map { |source|
|
143
|
+
options = options.merge('integrity' => asset_integrity(source, :type => :javascript)) if integrity
|
144
|
+
super source, options
|
145
|
+
}.join("\n").html_safe
|
149
146
|
end
|
150
147
|
end
|
151
148
|
|
@@ -154,81 +151,205 @@ module Sprockets
|
|
154
151
|
# Eventually will be deprecated and replaced by source maps.
|
155
152
|
def stylesheet_link_tag(*sources)
|
156
153
|
options = sources.extract_options!.stringify_keys
|
154
|
+
integrity = compute_integrity?(options)
|
155
|
+
|
157
156
|
if options["debug"] != false && request_debug_assets?
|
158
157
|
sources.map { |source|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
158
|
+
if asset = lookup_debug_asset(source, :type => :stylesheet)
|
159
|
+
if asset.respond_to?(:to_a)
|
160
|
+
asset.to_a.map do |a|
|
161
|
+
super(path_to_stylesheet(a.logical_path, :debug => true), options)
|
162
|
+
end
|
163
|
+
else
|
164
|
+
super(path_to_stylesheet(asset.logical_path, :debug => true), options)
|
163
165
|
end
|
164
166
|
else
|
165
167
|
super(source, options)
|
166
168
|
end
|
167
169
|
}.flatten.uniq.join("\n").html_safe
|
168
170
|
else
|
169
|
-
sources.
|
170
|
-
|
171
|
+
sources.map { |source|
|
172
|
+
options = options.merge('integrity' => asset_integrity(source, :type => :stylesheet)) if integrity
|
173
|
+
super source, options
|
174
|
+
}.join("\n").html_safe
|
171
175
|
end
|
172
176
|
end
|
173
177
|
|
174
178
|
protected
|
175
|
-
#
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
179
|
+
# This is awkward: `integrity` is a boolean option indicating whether
|
180
|
+
# we want to include or omit the subresource integrity hash, but the
|
181
|
+
# options hash is also passed through as literal tag attributes.
|
182
|
+
# That means we have to delete the shortcut boolean option so it
|
183
|
+
# doesn't bleed into the tag attributes, but also check its value if
|
184
|
+
# it's boolean-ish.
|
185
|
+
def compute_integrity?(options)
|
186
|
+
if secure_subresource_integrity_context?
|
187
|
+
case options['integrity']
|
188
|
+
when nil, false, true
|
189
|
+
options.delete('integrity') == true
|
190
|
+
end
|
191
|
+
else
|
192
|
+
options.delete 'integrity'
|
193
|
+
false
|
194
|
+
end
|
180
195
|
end
|
181
196
|
|
182
|
-
#
|
183
|
-
#
|
184
|
-
def
|
185
|
-
|
197
|
+
# Only serve integrity metadata for HTTPS requests:
|
198
|
+
# http://www.w3.org/TR/SRI/#non-secure-contexts-remain-non-secure
|
199
|
+
def secure_subresource_integrity_context?
|
200
|
+
respond_to?(:request) && self.request && self.request.ssl?
|
201
|
+
end
|
186
202
|
|
187
|
-
|
188
|
-
|
203
|
+
# Enable split asset debugging. Eventually will be deprecated
|
204
|
+
# and replaced by source maps in Sprockets 3.x.
|
205
|
+
def request_debug_assets?
|
206
|
+
debug_assets || (defined?(controller) && controller && params[:debug_assets])
|
207
|
+
rescue # FIXME: what exactly are we rescuing?
|
208
|
+
false
|
209
|
+
end
|
189
210
|
|
190
|
-
|
211
|
+
# Internal method to support multifile debugging. Will
|
212
|
+
# eventually be removed w/ Sprockets 3.x.
|
213
|
+
def lookup_debug_asset(path, options = {})
|
214
|
+
path = path_with_extname(path, options)
|
191
215
|
|
192
|
-
|
193
|
-
|
216
|
+
resolve_asset do |resolver|
|
217
|
+
resolver.find_debug_asset path
|
194
218
|
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# compute_asset_extname is in AV::Helpers::AssetUrlHelper
|
222
|
+
def path_with_extname(path, options)
|
223
|
+
path = path.to_s
|
224
|
+
"#{path}#{compute_asset_extname(path, options)}"
|
225
|
+
end
|
195
226
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
if
|
200
|
-
|
227
|
+
# Try each asset resolver and return the first non-nil result.
|
228
|
+
def resolve_asset
|
229
|
+
asset_resolver_strategies.detect do |resolver|
|
230
|
+
if result = yield(resolver)
|
231
|
+
break result
|
201
232
|
end
|
202
233
|
end
|
203
234
|
end
|
204
235
|
|
205
|
-
#
|
206
|
-
def
|
207
|
-
|
208
|
-
|
236
|
+
# List of resolvers in `config.assets.resolve_with` order.
|
237
|
+
def asset_resolver_strategies
|
238
|
+
@asset_resolver_strategies ||=
|
239
|
+
Array(resolve_assets_with).map do |name|
|
240
|
+
HelperAssetResolvers[name].new(self)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Append ?body=1 if debug is on and we're on old Sprockets.
|
245
|
+
def legacy_debug_path(path, debug)
|
246
|
+
if debug && !using_sprockets4?
|
247
|
+
"#{path}?body=1"
|
209
248
|
else
|
210
|
-
|
249
|
+
path
|
211
250
|
end
|
212
251
|
end
|
252
|
+
end
|
213
253
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
254
|
+
# Use a separate module since Helper is mixed in and we needn't pollute
|
255
|
+
# the class namespace with our internals.
|
256
|
+
module HelperAssetResolvers #:nodoc:
|
257
|
+
def self.[](name)
|
258
|
+
case name
|
259
|
+
when :manifest
|
260
|
+
Manifest
|
261
|
+
when :environment
|
262
|
+
Environment
|
263
|
+
else
|
264
|
+
raise ArgumentError, "Unrecognized asset resolver: #{name.inspect}. Expected :manifest or :environment"
|
220
265
|
end
|
266
|
+
end
|
221
267
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
268
|
+
class Manifest #:nodoc:
|
269
|
+
def initialize(view)
|
270
|
+
@manifest = view.assets_manifest
|
271
|
+
raise ArgumentError, 'config.assets.resolve_with includes :manifest, but app.assets_manifest is nil' unless @manifest
|
272
|
+
end
|
273
|
+
|
274
|
+
def asset_path(path, digest, allow_non_precompiled = false)
|
275
|
+
if digest
|
276
|
+
digest_path path, allow_non_precompiled
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def digest_path(path, allow_non_precompiled = false)
|
281
|
+
@manifest.assets[path]
|
282
|
+
end
|
283
|
+
|
284
|
+
def integrity(path)
|
285
|
+
if meta = metadata(path)
|
286
|
+
meta["integrity"]
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def find_debug_asset(path)
|
291
|
+
nil
|
292
|
+
end
|
293
|
+
|
294
|
+
private
|
295
|
+
def metadata(path)
|
296
|
+
if digest_path = digest_path(path)
|
297
|
+
@manifest.files[digest_path]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
class Environment #:nodoc:
|
303
|
+
def initialize(view)
|
304
|
+
raise ArgumentError, 'config.assets.resolve_with includes :environment, but app.assets is nil' unless view.assets_environment
|
305
|
+
@env = view.assets_environment
|
306
|
+
@precompiled_asset_checker = view.precompiled_asset_checker
|
307
|
+
end
|
308
|
+
|
309
|
+
def asset_path(path, digest, allow_non_precompiled = false)
|
310
|
+
# Digests enabled? Do the work to calculate the full asset path.
|
311
|
+
if digest
|
312
|
+
digest_path path, allow_non_precompiled
|
313
|
+
|
314
|
+
# Otherwise, ask the Sprockets environment whether the asset exists
|
315
|
+
# and check whether it's also precompiled for production deploys.
|
316
|
+
elsif find_asset(path)
|
317
|
+
raise_unless_precompiled_asset path unless allow_non_precompiled
|
318
|
+
path
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def digest_path(path, allow_non_precompiled = false)
|
323
|
+
if asset = find_asset(path)
|
324
|
+
raise_unless_precompiled_asset path unless allow_non_precompiled
|
325
|
+
asset.digest_path
|
229
326
|
end
|
230
|
-
env[path]
|
231
327
|
end
|
328
|
+
|
329
|
+
def integrity(path)
|
330
|
+
find_asset(path).try :integrity
|
331
|
+
end
|
332
|
+
|
333
|
+
def find_debug_asset(path)
|
334
|
+
if asset = find_asset(path, pipeline: :debug)
|
335
|
+
raise_unless_precompiled_asset asset.logical_path.sub('.debug', '')
|
336
|
+
asset
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
private
|
341
|
+
def find_asset(path, options = {})
|
342
|
+
@env[path, options]
|
343
|
+
end
|
344
|
+
|
345
|
+
def precompiled?(path)
|
346
|
+
@precompiled_asset_checker.call path
|
347
|
+
end
|
348
|
+
|
349
|
+
def raise_unless_precompiled_asset(path)
|
350
|
+
raise Helper::AssetNotPrecompiled.new(path) unless precompiled?(path)
|
351
|
+
end
|
352
|
+
end
|
232
353
|
end
|
233
354
|
end
|
234
355
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Sprockets
|
2
|
+
module Rails
|
3
|
+
module RouteWrapper
|
4
|
+
|
5
|
+
def internal_assets_path?
|
6
|
+
path =~ %r{\A#{self.class.assets_prefix}\z}
|
7
|
+
end
|
8
|
+
|
9
|
+
def internal?
|
10
|
+
super || internal_assets_path?
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(klass)
|
14
|
+
klass.class_eval do
|
15
|
+
def internal_with_sprockets?
|
16
|
+
internal_without_sprockets? || internal_assets_path?
|
17
|
+
end
|
18
|
+
alias_method_chain :internal?, :sprockets
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/sprockets/rails/task.rb
CHANGED
@@ -16,7 +16,9 @@ module Sprockets
|
|
16
16
|
|
17
17
|
def environment
|
18
18
|
if app
|
19
|
-
app.assets
|
19
|
+
# Use initialized app.assets or force build an environment if
|
20
|
+
# config.assets.compile is disabled
|
21
|
+
app.assets || Sprockets::Railtie.build_environment(app)
|
20
22
|
else
|
21
23
|
super
|
22
24
|
end
|
@@ -24,7 +26,8 @@ module Sprockets
|
|
24
26
|
|
25
27
|
def output
|
26
28
|
if app
|
27
|
-
|
29
|
+
config = app.config
|
30
|
+
File.join(config.paths['public'].first, config.assets.prefix)
|
28
31
|
else
|
29
32
|
super
|
30
33
|
end
|
@@ -46,17 +49,12 @@ module Sprockets
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
def cache_path
|
50
|
-
if app
|
51
|
-
"#{app.config.root}/tmp/cache/assets"
|
52
|
-
else
|
53
|
-
@cache_path
|
54
|
-
end
|
55
|
-
end
|
56
|
-
attr_writer :cache_path
|
57
|
-
|
58
52
|
def define
|
59
53
|
namespace :assets do
|
54
|
+
%w( environment precompile clean clobber ).each do |task|
|
55
|
+
Rake::Task[task].clear if Rake::Task.task_defined?(task)
|
56
|
+
end
|
57
|
+
|
60
58
|
# Override this task change the loaded dependencies
|
61
59
|
desc "Load asset compile environment"
|
62
60
|
task :environment do
|
@@ -73,9 +71,8 @@ module Sprockets
|
|
73
71
|
|
74
72
|
desc "Remove old compiled assets"
|
75
73
|
task :clean, [:keep] => :environment do |t, args|
|
76
|
-
keep = Integer(args.keep || 2)
|
77
74
|
with_logger do
|
78
|
-
manifest.clean(keep)
|
75
|
+
manifest.clean(Integer(args.keep || self.keep))
|
79
76
|
end
|
80
77
|
end
|
81
78
|
|
@@ -83,7 +80,6 @@ module Sprockets
|
|
83
80
|
task :clobber => :environment do
|
84
81
|
with_logger do
|
85
82
|
manifest.clobber
|
86
|
-
rm_rf cache_path if cache_path
|
87
83
|
end
|
88
84
|
end
|
89
85
|
end
|