sprockets 2.2.3 → 2.12.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +135 -4
- data/bin/sprockets +8 -0
- data/lib/rake/sprocketstask.rb +24 -13
- data/lib/sprockets.rb +52 -8
- data/lib/sprockets/asset.rb +17 -8
- data/lib/sprockets/asset_attributes.rb +15 -4
- data/lib/sprockets/base.rb +155 -15
- data/lib/sprockets/bundled_asset.rb +5 -6
- data/lib/sprockets/caching.rb +39 -39
- data/lib/sprockets/closure_compressor.rb +22 -0
- data/lib/sprockets/compressing.rb +73 -0
- data/lib/sprockets/context.rb +57 -3
- data/lib/sprockets/directive_processor.rb +3 -1
- data/lib/sprockets/engines.rb +4 -4
- data/lib/sprockets/environment.rb +12 -15
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/index.rb +1 -0
- data/lib/sprockets/jst_processor.rb +2 -6
- data/lib/sprockets/manifest.rb +77 -19
- data/lib/sprockets/mime.rb +5 -4
- data/lib/sprockets/{trail.rb → paths.rb} +5 -37
- data/lib/sprockets/processed_asset.rb +1 -1
- data/lib/sprockets/processing.rb +3 -77
- data/lib/sprockets/processor.rb +1 -1
- data/lib/sprockets/sass_cache_store.rb +29 -0
- data/lib/sprockets/sass_compressor.rb +27 -0
- data/lib/sprockets/sass_functions.rb +70 -0
- data/lib/sprockets/sass_importer.rb +30 -0
- data/lib/sprockets/sass_template.rb +66 -0
- data/lib/sprockets/scss_template.rb +13 -0
- data/lib/sprockets/server.rb +1 -1
- data/lib/sprockets/static_asset.rb +4 -1
- data/lib/sprockets/uglifier_compressor.rb +29 -0
- data/lib/sprockets/version.rb +1 -1
- data/lib/sprockets/yui_compressor.rb +27 -0
- metadata +88 -7
@@ -19,7 +19,7 @@ module Sprockets
|
|
19
19
|
@dependency_digest = compute_dependency_digest(environment)
|
20
20
|
|
21
21
|
elapsed_time = ((Time.now.to_f - start_time) * 1000).to_i
|
22
|
-
environment.logger.
|
22
|
+
environment.logger.debug "Compiled #{logical_path} (#{elapsed_time}ms) (pid #{Process.pid})"
|
23
23
|
end
|
24
24
|
|
25
25
|
# Interal: Used to check equality
|
data/lib/sprockets/processing.rb
CHANGED
@@ -7,16 +7,6 @@ module Sprockets
|
|
7
7
|
# `Processing` is an internal mixin whose public methods are exposed on
|
8
8
|
# the `Environment` and `Index` classes.
|
9
9
|
module Processing
|
10
|
-
include Engines, Mime
|
11
|
-
|
12
|
-
# Register a new mime type.
|
13
|
-
def register_mime_type(mime_type, ext)
|
14
|
-
# Overrides the global behavior to expire the index
|
15
|
-
expire_index!
|
16
|
-
@trail.append_extension(ext)
|
17
|
-
super
|
18
|
-
end
|
19
|
-
|
20
10
|
# Returns an `Array` of format extension `String`s.
|
21
11
|
#
|
22
12
|
# format_extensions
|
@@ -26,14 +16,6 @@ module Sprockets
|
|
26
16
|
@trail.extensions - @engines.keys
|
27
17
|
end
|
28
18
|
|
29
|
-
# Registers a new Engine `klass` for `ext`.
|
30
|
-
def register_engine(ext, klass)
|
31
|
-
# Overrides the global behavior to expire the index
|
32
|
-
expire_index!
|
33
|
-
add_engine_to_trail(ext, klass)
|
34
|
-
super
|
35
|
-
end
|
36
|
-
|
37
19
|
# Deprecated alias for `preprocessors`.
|
38
20
|
def processors(*args)
|
39
21
|
preprocessors(*args)
|
@@ -83,13 +65,11 @@ module Sprockets
|
|
83
65
|
#
|
84
66
|
# A block can be passed for to create a shorthand processor.
|
85
67
|
#
|
86
|
-
# register_preprocessor :my_processor do |context, data|
|
68
|
+
# register_preprocessor 'text/css', :my_processor do |context, data|
|
87
69
|
# data.gsub(...)
|
88
70
|
# end
|
89
71
|
#
|
90
72
|
def register_preprocessor(mime_type, klass, &block)
|
91
|
-
expire_index!
|
92
|
-
|
93
73
|
if block_given?
|
94
74
|
name = klass.to_s
|
95
75
|
klass = Class.new(Processor) do
|
@@ -107,13 +87,11 @@ module Sprockets
|
|
107
87
|
#
|
108
88
|
# A block can be passed for to create a shorthand processor.
|
109
89
|
#
|
110
|
-
# register_postprocessor :my_processor do |context, data|
|
90
|
+
# register_postprocessor 'text/css', :my_processor do |context, data|
|
111
91
|
# data.gsub(...)
|
112
92
|
# end
|
113
93
|
#
|
114
94
|
def register_postprocessor(mime_type, klass, &block)
|
115
|
-
expire_index!
|
116
|
-
|
117
95
|
if block_given?
|
118
96
|
name = klass.to_s
|
119
97
|
klass = Class.new(Processor) do
|
@@ -135,8 +113,6 @@ module Sprockets
|
|
135
113
|
# unregister_preprocessor 'text/css', Sprockets::DirectiveProcessor
|
136
114
|
#
|
137
115
|
def unregister_preprocessor(mime_type, klass)
|
138
|
-
expire_index!
|
139
|
-
|
140
116
|
if klass.is_a?(String) || klass.is_a?(Symbol)
|
141
117
|
klass = @preprocessors[mime_type].detect { |cls|
|
142
118
|
cls.respond_to?(:name) &&
|
@@ -152,8 +128,6 @@ module Sprockets
|
|
152
128
|
# unregister_postprocessor 'text/css', Sprockets::DirectiveProcessor
|
153
129
|
#
|
154
130
|
def unregister_postprocessor(mime_type, klass)
|
155
|
-
expire_index!
|
156
|
-
|
157
131
|
if klass.is_a?(String) || klass.is_a?(Symbol)
|
158
132
|
klass = @postprocessors[mime_type].detect { |cls|
|
159
133
|
cls.respond_to?(:name) &&
|
@@ -187,13 +161,11 @@ module Sprockets
|
|
187
161
|
#
|
188
162
|
# A block can be passed for to create a shorthand processor.
|
189
163
|
#
|
190
|
-
# register_bundle_processor :my_processor do |context, data|
|
164
|
+
# register_bundle_processor 'text/css', :my_processor do |context, data|
|
191
165
|
# data.gsub(...)
|
192
166
|
# end
|
193
167
|
#
|
194
168
|
def register_bundle_processor(mime_type, klass, &block)
|
195
|
-
expire_index!
|
196
|
-
|
197
169
|
if block_given?
|
198
170
|
name = klass.to_s
|
199
171
|
klass = Class.new(Processor) do
|
@@ -210,8 +182,6 @@ module Sprockets
|
|
210
182
|
# unregister_bundle_processor 'text/css', Sprockets::CharsetNormalizer
|
211
183
|
#
|
212
184
|
def unregister_bundle_processor(mime_type, klass)
|
213
|
-
expire_index!
|
214
|
-
|
215
185
|
if klass.is_a?(String) || klass.is_a?(Symbol)
|
216
186
|
klass = @bundle_processors[mime_type].detect { |cls|
|
217
187
|
cls.respond_to?(:name) &&
|
@@ -222,50 +192,6 @@ module Sprockets
|
|
222
192
|
@bundle_processors[mime_type].delete(klass)
|
223
193
|
end
|
224
194
|
|
225
|
-
# Return CSS compressor or nil if none is set
|
226
|
-
def css_compressor
|
227
|
-
bundle_processors('text/css').detect { |klass|
|
228
|
-
klass.respond_to?(:name) &&
|
229
|
-
klass.name == 'Sprockets::Processor (css_compressor)'
|
230
|
-
}
|
231
|
-
end
|
232
|
-
|
233
|
-
# Assign a compressor to run on `text/css` assets.
|
234
|
-
#
|
235
|
-
# The compressor object must respond to `compress` or `compile`.
|
236
|
-
def css_compressor=(compressor)
|
237
|
-
expire_index!
|
238
|
-
|
239
|
-
unregister_bundle_processor 'text/css', :css_compressor
|
240
|
-
return unless compressor
|
241
|
-
|
242
|
-
register_bundle_processor 'text/css', :css_compressor do |context, data|
|
243
|
-
compressor.compress(data)
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
# Return JS compressor or nil if none is set
|
248
|
-
def js_compressor
|
249
|
-
bundle_processors('application/javascript').detect { |klass|
|
250
|
-
klass.respond_to?(:name) &&
|
251
|
-
klass.name == 'Sprockets::Processor (js_compressor)'
|
252
|
-
}
|
253
|
-
end
|
254
|
-
|
255
|
-
# Assign a compressor to run on `application/javascript` assets.
|
256
|
-
#
|
257
|
-
# The compressor object must respond to `compress` or `compile`.
|
258
|
-
def js_compressor=(compressor)
|
259
|
-
expire_index!
|
260
|
-
|
261
|
-
unregister_bundle_processor 'application/javascript', :js_compressor
|
262
|
-
return unless compressor
|
263
|
-
|
264
|
-
register_bundle_processor 'application/javascript', :js_compressor do |context, data|
|
265
|
-
compressor.compress(data)
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
195
|
private
|
270
196
|
def add_engine_to_trail(ext, klass)
|
271
197
|
@trail.append_extension(ext.to_s)
|
data/lib/sprockets/processor.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
class SassCacheStore < ::Sass::CacheStores::Base
|
5
|
+
attr_reader :environment
|
6
|
+
|
7
|
+
def initialize(environment)
|
8
|
+
@environment = environment
|
9
|
+
end
|
10
|
+
|
11
|
+
def _store(key, version, sha, contents)
|
12
|
+
environment.cache_set("sass/#{key}", {:version => version, :sha => sha, :contents => contents})
|
13
|
+
end
|
14
|
+
|
15
|
+
def _retrieve(key, version, sha)
|
16
|
+
if obj = environment.cache_get("sass/#{key}")
|
17
|
+
return unless obj[:version] == version
|
18
|
+
return unless obj[:sha] == sha
|
19
|
+
obj[:contents]
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def path_to(key)
|
26
|
+
key
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
class SassCompressor < Tilt::Template
|
5
|
+
self.default_mime_type = 'text/css'
|
6
|
+
|
7
|
+
def self.engine_initialized?
|
8
|
+
defined?(::Sass::Engine)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize_engine
|
12
|
+
require_template_library 'sass'
|
13
|
+
end
|
14
|
+
|
15
|
+
def prepare
|
16
|
+
end
|
17
|
+
|
18
|
+
def evaluate(context, locals, &block)
|
19
|
+
::Sass::Engine.new(data, {
|
20
|
+
:syntax => :scss,
|
21
|
+
:cache => false,
|
22
|
+
:read_cache => false,
|
23
|
+
:style => :compressed
|
24
|
+
}).render
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
module SassFunctions
|
5
|
+
def asset_path(path)
|
6
|
+
::Sass::Script::String.new(sprockets_context.asset_path(path.value), :string)
|
7
|
+
end
|
8
|
+
|
9
|
+
def asset_url(path)
|
10
|
+
::Sass::Script::String.new("url(" + sprockets_context.asset_path(path.value) + ")")
|
11
|
+
end
|
12
|
+
|
13
|
+
def image_path(path)
|
14
|
+
::Sass::Script::String.new(sprockets_context.image_path(path.value), :string)
|
15
|
+
end
|
16
|
+
|
17
|
+
def image_url(path)
|
18
|
+
::Sass::Script::String.new("url(" + sprockets_context.image_path(path.value) + ")")
|
19
|
+
end
|
20
|
+
|
21
|
+
def video_path(path)
|
22
|
+
::Sass::Script::String.new(sprockets_context.video_path(path.value), :string)
|
23
|
+
end
|
24
|
+
|
25
|
+
def video_url(path)
|
26
|
+
::Sass::Script::String.new("url(" + sprockets_context.video_path(path.value) + ")")
|
27
|
+
end
|
28
|
+
|
29
|
+
def audio_path(path)
|
30
|
+
::Sass::Script::String.new(sprockets_context.audio_path(path.value), :string)
|
31
|
+
end
|
32
|
+
|
33
|
+
def audio_url(path)
|
34
|
+
::Sass::Script::String.new("url(" + sprockets_context.audio_path(path.value) + ")")
|
35
|
+
end
|
36
|
+
|
37
|
+
def font_path(path)
|
38
|
+
::Sass::Script::String.new(sprockets_context.font_path(path.value), :string)
|
39
|
+
end
|
40
|
+
|
41
|
+
def font_url(path)
|
42
|
+
::Sass::Script::String.new("url(" + sprockets_context.font_path(path.value) + ")")
|
43
|
+
end
|
44
|
+
|
45
|
+
def javascript_path(path)
|
46
|
+
::Sass::Script::String.new(sprockets_context.javascript_path(path.value), :string)
|
47
|
+
end
|
48
|
+
|
49
|
+
def javascript_url(path)
|
50
|
+
::Sass::Script::String.new("url(" + sprockets_context.javascript_path(path.value) + ")")
|
51
|
+
end
|
52
|
+
|
53
|
+
def stylesheet_path(path)
|
54
|
+
::Sass::Script::String.new(sprockets_context.stylesheet_path(path.value), :string)
|
55
|
+
end
|
56
|
+
|
57
|
+
def stylesheet_url(path)
|
58
|
+
::Sass::Script::String.new("url(" + sprockets_context.stylesheet_path(path.value) + ")")
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
def sprockets_context
|
63
|
+
options[:sprockets][:context]
|
64
|
+
end
|
65
|
+
|
66
|
+
def sprockets_environment
|
67
|
+
options[:sprockets][:environment]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
# This custom importer that tracks all imported filenames during
|
5
|
+
# compile.
|
6
|
+
class SassImporter < ::Sass::Importers::Filesystem
|
7
|
+
attr_reader :imported_filenames
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
@imported_filenames = []
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_relative(*args)
|
15
|
+
engine = super
|
16
|
+
if engine && (filename = engine.options[:filename])
|
17
|
+
@imported_filenames << filename
|
18
|
+
end
|
19
|
+
engine
|
20
|
+
end
|
21
|
+
|
22
|
+
def find(*args)
|
23
|
+
engine = super
|
24
|
+
if engine && (filename = engine.options[:filename])
|
25
|
+
@imported_filenames << filename
|
26
|
+
end
|
27
|
+
engine
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
# This custom Tilt handler replaces the one built into Tilt. The
|
5
|
+
# main difference is that it uses a custom importer that plays nice
|
6
|
+
# with sprocket's caching system.
|
7
|
+
#
|
8
|
+
# See `SassImporter` for more infomation.
|
9
|
+
class SassTemplate < Tilt::Template
|
10
|
+
self.default_mime_type = 'text/css'
|
11
|
+
|
12
|
+
def self.engine_initialized?
|
13
|
+
defined?(::Sass::Engine) && defined?(::Sass::Script::Functions) &&
|
14
|
+
::Sass::Script::Functions < Sprockets::SassFunctions
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize_engine
|
18
|
+
# Double check constant to avoid tilt warning
|
19
|
+
unless defined? ::Sass
|
20
|
+
require_template_library 'sass'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Install custom functions. It'd be great if this didn't need to
|
24
|
+
# be installed globally, but could be passed into Engine as an
|
25
|
+
# option.
|
26
|
+
::Sass::Script::Functions.send :include, Sprockets::SassFunctions
|
27
|
+
end
|
28
|
+
|
29
|
+
def prepare
|
30
|
+
end
|
31
|
+
|
32
|
+
def syntax
|
33
|
+
:sass
|
34
|
+
end
|
35
|
+
|
36
|
+
def evaluate(context, locals, &block)
|
37
|
+
# Use custom importer that knows about Sprockets Caching
|
38
|
+
cache_store = SassCacheStore.new(context.environment)
|
39
|
+
|
40
|
+
options = {
|
41
|
+
:filename => eval_file,
|
42
|
+
:line => line,
|
43
|
+
:syntax => syntax,
|
44
|
+
:cache_store => cache_store,
|
45
|
+
:importer => SassImporter.new(context.pathname.to_s),
|
46
|
+
:load_paths => context.environment.paths.map { |path| SassImporter.new(path.to_s) },
|
47
|
+
:sprockets => {
|
48
|
+
:context => context,
|
49
|
+
:environment => context.environment
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
result = ::Sass::Engine.new(data, options).render
|
54
|
+
|
55
|
+
# Track all imported files
|
56
|
+
filenames = ([options[:importer].imported_filenames] + options[:load_paths].map(&:imported_filenames)).flatten.uniq
|
57
|
+
filenames.each { |filename| context.depend_on(filename) }
|
58
|
+
|
59
|
+
result
|
60
|
+
rescue ::Sass::SyntaxError => e
|
61
|
+
# Annotates exception message with parse line number
|
62
|
+
context.__LINE__ = e.sass_backtrace.first[:line]
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'sprockets/sass_template'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
# Scss handler to replace Tilt's builtin one. See `SassTemplate` and
|
5
|
+
# `SassImporter` for more infomation.
|
6
|
+
class ScssTemplate < SassTemplate
|
7
|
+
self.default_mime_type = 'text/css'
|
8
|
+
|
9
|
+
def syntax
|
10
|
+
:scss
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/sprockets/server.rb
CHANGED
@@ -90,7 +90,7 @@ module Sprockets
|
|
90
90
|
#
|
91
91
|
# http://example.org/assets/../../../etc/passwd
|
92
92
|
#
|
93
|
-
path.include?("..") || Pathname.new(path).absolute?
|
93
|
+
path.include?("..") || Pathname.new(path).absolute? || path.include?("://")
|
94
94
|
end
|
95
95
|
|
96
96
|
# Returns a 403 Forbidden response tuple
|
@@ -21,7 +21,9 @@ module Sprockets
|
|
21
21
|
# Save asset to disk.
|
22
22
|
def write_to(filename, options = {})
|
23
23
|
# Gzip contents if filename has '.gz'
|
24
|
-
options
|
24
|
+
unless options.key?(:compress)
|
25
|
+
options[:compress] = File.extname(filename) == '.gz' && File.extname(logical_path) != '.gz'
|
26
|
+
end
|
25
27
|
|
26
28
|
FileUtils.mkdir_p File.dirname(filename)
|
27
29
|
|
@@ -30,6 +32,7 @@ module Sprockets
|
|
30
32
|
pathname.open('rb') do |rd|
|
31
33
|
File.open("#{filename}+", 'wb') do |wr|
|
32
34
|
gz = Zlib::GzipWriter.new(wr, Zlib::BEST_COMPRESSION)
|
35
|
+
gz.mtime = mtime.to_i
|
33
36
|
buf = ""
|
34
37
|
while rd.read(16384, buf)
|
35
38
|
gz.write(buf)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
class UglifierCompressor < Tilt::Template
|
5
|
+
self.default_mime_type = 'application/javascript'
|
6
|
+
|
7
|
+
def self.engine_initialized?
|
8
|
+
defined?(::Uglifier)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize_engine
|
12
|
+
require_template_library 'uglifier'
|
13
|
+
end
|
14
|
+
|
15
|
+
def prepare
|
16
|
+
end
|
17
|
+
|
18
|
+
def evaluate(context, locals, &block)
|
19
|
+
# Feature detect Uglifier 2.0 option support
|
20
|
+
if Uglifier::DEFAULTS[:copyright]
|
21
|
+
# Uglifier < 2.x
|
22
|
+
Uglifier.new(:copyright => false).compile(data)
|
23
|
+
else
|
24
|
+
# Uglifier >= 2.x
|
25
|
+
Uglifier.new(:comments => :none).compile(data)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|