sprockets 3.7.2 → 4.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/CHANGELOG.md +42 -270
- data/README.md +443 -320
- data/bin/sprockets +11 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +16 -21
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +1 -0
- data/lib/sprockets/autoload/coffee_script.rb +1 -0
- data/lib/sprockets/autoload/eco.rb +1 -0
- data/lib/sprockets/autoload/ejs.rb +1 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +1 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +1 -0
- data/lib/sprockets/autoload/yui.rb +1 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/autoload.rb +5 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +47 -10
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +40 -4
- data/lib/sprockets/cache/file_store.rb +25 -3
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +36 -1
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +1 -0
- data/lib/sprockets/coffee_script_processor.rb +18 -4
- data/lib/sprockets/compressing.rb +43 -3
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +97 -24
- data/lib/sprockets/dependencies.rb +1 -0
- data/lib/sprockets/digest_utils.rb +25 -5
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +1 -0
- data/lib/sprockets/ejs_processor.rb +1 -0
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +72 -0
- data/lib/sprockets/exporters/file_exporter.rb +24 -0
- data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
- data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
- data/lib/sprockets/exporting.rb +73 -0
- data/lib/sprockets/file_reader.rb +1 -0
- data/lib/sprockets/http_utils.rb +25 -7
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +85 -67
- data/lib/sprockets/manifest.rb +64 -62
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -42
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +3 -11
- data/lib/sprockets/path_digest_utils.rb +2 -1
- data/lib/sprockets/path_utils.rb +87 -7
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -61
- data/lib/sprockets/processor_utils.rb +24 -35
- data/lib/sprockets/resolve.rb +177 -93
- data/lib/sprockets/sass_cache_store.rb +2 -6
- data/lib/sprockets/sass_compressor.rb +13 -1
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +30 -9
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +26 -23
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +63 -35
- data/lib/sprockets/uglifier_compressor.rb +21 -11
- data/lib/sprockets/unloaded_asset.rb +13 -11
- data/lib/sprockets/uri_tar.rb +1 -0
- data/lib/sprockets/uri_utils.rb +11 -8
- data/lib/sprockets/utils/gzip.rb +46 -14
- data/lib/sprockets/utils.rb +41 -74
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +1 -0
- data/lib/sprockets.rb +99 -39
- metadata +127 -23
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -17
- data/lib/sprockets/deprecation.rb +0 -90
- data/lib/sprockets/eco_template.rb +0 -17
- data/lib/sprockets/ejs_template.rb +0 -17
- data/lib/sprockets/engines.rb +0 -92
- data/lib/sprockets/erb_template.rb +0 -11
- data/lib/sprockets/legacy.rb +0 -330
- data/lib/sprockets/legacy_proc_processor.rb +0 -35
- data/lib/sprockets/legacy_tilt_processor.rb +0 -29
- data/lib/sprockets/sass_template.rb +0 -19
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Sprockets
|
|
2
3
|
class Cache
|
|
3
4
|
# Public: A compatible cache store that doesn't store anything. Used by
|
|
@@ -41,6 +42,13 @@ module Sprockets
|
|
|
41
42
|
def inspect
|
|
42
43
|
"#<#{self.class}>"
|
|
43
44
|
end
|
|
45
|
+
|
|
46
|
+
# Public: Simulate clearing the cache
|
|
47
|
+
#
|
|
48
|
+
# Returns true
|
|
49
|
+
def clear(options=nil)
|
|
50
|
+
true
|
|
51
|
+
end
|
|
44
52
|
end
|
|
45
53
|
end
|
|
46
54
|
end
|
data/lib/sprockets/cache.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'logger'
|
|
2
3
|
require 'sprockets/digest_utils'
|
|
3
4
|
|
|
@@ -35,6 +36,12 @@ module Sprockets
|
|
|
35
36
|
#
|
|
36
37
|
# Returns argument value.
|
|
37
38
|
#
|
|
39
|
+
# clear(options)
|
|
40
|
+
#
|
|
41
|
+
# Clear the entire cache. Be careful with this method since it could
|
|
42
|
+
# affect other processes if shared cache is being used.
|
|
43
|
+
#
|
|
44
|
+
# The options hash is passed to the underlying cache implementation.
|
|
38
45
|
class Cache
|
|
39
46
|
# Builtin cache stores.
|
|
40
47
|
autoload :FileStore, 'sprockets/cache/file_store'
|
|
@@ -44,7 +51,7 @@ module Sprockets
|
|
|
44
51
|
# Internal: Cache key version for this class. Rarely should have to change
|
|
45
52
|
# unless the cache format radically changes. Will be bump on major version
|
|
46
53
|
# releases though.
|
|
47
|
-
VERSION = '
|
|
54
|
+
VERSION = '4.0.0'
|
|
48
55
|
|
|
49
56
|
def self.default_logger
|
|
50
57
|
logger = Logger.new($stderr)
|
|
@@ -143,6 +150,14 @@ module Sprockets
|
|
|
143
150
|
"#<#{self.class} local=#{@fetch_cache.inspect} store=#{@cache_wrapper.cache.inspect}>"
|
|
144
151
|
end
|
|
145
152
|
|
|
153
|
+
# Public: Clear cache
|
|
154
|
+
#
|
|
155
|
+
# Returns truthy on success, potentially raises exception on failure
|
|
156
|
+
def clear(options=nil)
|
|
157
|
+
@cache_wrapper.clear
|
|
158
|
+
@fetch_cache.clear
|
|
159
|
+
end
|
|
160
|
+
|
|
146
161
|
private
|
|
147
162
|
# Internal: Expand object cache key into a short String key.
|
|
148
163
|
#
|
|
@@ -211,6 +226,16 @@ module Sprockets
|
|
|
211
226
|
def set(key, value)
|
|
212
227
|
cache.set(key, value)
|
|
213
228
|
end
|
|
229
|
+
|
|
230
|
+
def clear(options=nil)
|
|
231
|
+
# dalli has a #flush method so try it
|
|
232
|
+
if cache.respond_to?(:flush)
|
|
233
|
+
cache.flush(options)
|
|
234
|
+
else
|
|
235
|
+
cache.clear(options)
|
|
236
|
+
end
|
|
237
|
+
true
|
|
238
|
+
end
|
|
214
239
|
end
|
|
215
240
|
|
|
216
241
|
class HashWrapper < Wrapper
|
|
@@ -221,6 +246,11 @@ module Sprockets
|
|
|
221
246
|
def set(key, value)
|
|
222
247
|
cache[key] = value
|
|
223
248
|
end
|
|
249
|
+
|
|
250
|
+
def clear(options=nil)
|
|
251
|
+
cache.clear
|
|
252
|
+
true
|
|
253
|
+
end
|
|
224
254
|
end
|
|
225
255
|
|
|
226
256
|
class ReadWriteWrapper < Wrapper
|
|
@@ -231,6 +261,11 @@ module Sprockets
|
|
|
231
261
|
def set(key, value)
|
|
232
262
|
cache.write(key, value)
|
|
233
263
|
end
|
|
264
|
+
|
|
265
|
+
def clear(options=nil)
|
|
266
|
+
cache.clear(options)
|
|
267
|
+
true
|
|
268
|
+
end
|
|
234
269
|
end
|
|
235
270
|
end
|
|
236
271
|
end
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'sprockets/base'
|
|
2
3
|
|
|
3
4
|
module Sprockets
|
|
4
|
-
# `
|
|
5
|
+
# `CachedEnvironment` is a special cached version of `Environment`.
|
|
5
6
|
#
|
|
6
7
|
# The expection is that all of its file system methods are cached
|
|
7
|
-
# for the instances lifetime. This makes `
|
|
8
|
+
# for the instances lifetime. This makes `CachedEnvironment` much faster. This
|
|
8
9
|
# behavior is ideal in production environments where the file system
|
|
9
10
|
# is immutable.
|
|
10
11
|
#
|
|
11
|
-
# `
|
|
12
|
+
# `CachedEnvironment` should not be initialized directly. Instead use
|
|
12
13
|
# `Environment#cached`.
|
|
13
14
|
class CachedEnvironment < Base
|
|
14
15
|
def initialize(environment)
|
|
15
16
|
initialize_configuration(environment)
|
|
16
17
|
|
|
17
18
|
@cache = environment.cache
|
|
18
|
-
@stats =
|
|
19
|
-
@entries =
|
|
20
|
-
@uris =
|
|
21
|
-
|
|
22
|
-
@
|
|
23
|
-
@resolved_dependencies = Hash.new { |h, k| h[k] = _resolve_dependency(k) }
|
|
19
|
+
@stats = {}
|
|
20
|
+
@entries = {}
|
|
21
|
+
@uris = {}
|
|
22
|
+
@processor_cache_keys = {}
|
|
23
|
+
@resolved_dependencies = {}
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# No-op return self as cached environment.
|
|
@@ -30,33 +30,28 @@ module Sprockets
|
|
|
30
30
|
alias_method :index, :cached
|
|
31
31
|
|
|
32
32
|
# Internal: Cache Environment#entries
|
|
33
|
-
alias_method :_entries, :entries
|
|
34
33
|
def entries(path)
|
|
35
|
-
@entries[path]
|
|
34
|
+
@entries[path] ||= super(path)
|
|
36
35
|
end
|
|
37
36
|
|
|
38
37
|
# Internal: Cache Environment#stat
|
|
39
|
-
alias_method :_stat, :stat
|
|
40
38
|
def stat(path)
|
|
41
|
-
@stats[path]
|
|
39
|
+
@stats[path] ||= super(path)
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
# Internal: Cache Environment#load
|
|
45
|
-
alias_method :_load, :load
|
|
46
43
|
def load(uri)
|
|
47
|
-
@uris[uri]
|
|
44
|
+
@uris[uri] ||= super(uri)
|
|
48
45
|
end
|
|
49
46
|
|
|
50
47
|
# Internal: Cache Environment#processor_cache_key
|
|
51
|
-
alias_method :_processor_cache_key, :processor_cache_key
|
|
52
48
|
def processor_cache_key(str)
|
|
53
|
-
@processor_cache_keys[str]
|
|
49
|
+
@processor_cache_keys[str] ||= super(str)
|
|
54
50
|
end
|
|
55
51
|
|
|
56
52
|
# Internal: Cache Environment#resolve_dependency
|
|
57
|
-
alias_method :_resolve_dependency, :resolve_dependency
|
|
58
53
|
def resolve_dependency(str)
|
|
59
|
-
@resolved_dependencies[str]
|
|
54
|
+
@resolved_dependencies[str] ||= super(str)
|
|
60
55
|
end
|
|
61
56
|
|
|
62
57
|
private
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'sprockets/autoload'
|
|
3
|
+
require 'sprockets/source_map_utils'
|
|
2
4
|
|
|
3
5
|
module Sprockets
|
|
4
6
|
# Processor engine class for the CoffeeScript compiler.
|
|
@@ -6,10 +8,10 @@ module Sprockets
|
|
|
6
8
|
#
|
|
7
9
|
# For more infomation see:
|
|
8
10
|
#
|
|
9
|
-
# https://github.com/
|
|
11
|
+
# https://github.com/rails/ruby-coffee-script
|
|
10
12
|
#
|
|
11
13
|
module CoffeeScriptProcessor
|
|
12
|
-
VERSION = '
|
|
14
|
+
VERSION = '2'
|
|
13
15
|
|
|
14
16
|
def self.cache_key
|
|
15
17
|
@cache_key ||= "#{name}:#{Autoload::CoffeeScript::Source.version}:#{VERSION}".freeze
|
|
@@ -17,9 +19,21 @@ module Sprockets
|
|
|
17
19
|
|
|
18
20
|
def self.call(input)
|
|
19
21
|
data = input[:data]
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
js, map = input[:cache].fetch([self.cache_key, data]) do
|
|
24
|
+
result = Autoload::CoffeeScript.compile(
|
|
25
|
+
data,
|
|
26
|
+
sourceMap: "v3",
|
|
27
|
+
sourceFiles: [File.basename(input[:filename])],
|
|
28
|
+
generatedFile: input[:filename]
|
|
29
|
+
)
|
|
30
|
+
[result['js'], JSON.parse(result['v3SourceMap'])]
|
|
22
31
|
end
|
|
32
|
+
|
|
33
|
+
map = SourceMapUtils.format_source_map(map, input)
|
|
34
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
|
35
|
+
|
|
36
|
+
{ data: js, map: map }
|
|
23
37
|
end
|
|
24
38
|
end
|
|
25
39
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'sprockets/utils'
|
|
2
3
|
|
|
3
4
|
module Sprockets
|
|
@@ -10,6 +11,24 @@ module Sprockets
|
|
|
10
11
|
config[:compressors]
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
# Public: Register a new compressor `klass` at `sym` for `mime_type`.
|
|
15
|
+
#
|
|
16
|
+
# Registering a processor allows it to be looked up by `sym` later when
|
|
17
|
+
# assigning a JavaScript or CSS compressor.
|
|
18
|
+
#
|
|
19
|
+
# Compressors only operate on JavaScript and CSS. If you want to compress a
|
|
20
|
+
# different type of asset, use a processor instead.
|
|
21
|
+
#
|
|
22
|
+
# Examples
|
|
23
|
+
#
|
|
24
|
+
# register_compressor 'text/css', :my_sass, MySassCompressor
|
|
25
|
+
# css_compressor = :my_sass
|
|
26
|
+
#
|
|
27
|
+
# mime_type - String MIME Type (one of: 'test/css' or 'application/javascript').
|
|
28
|
+
# sym - Symbol registration address.
|
|
29
|
+
# klass - The compressor class.
|
|
30
|
+
#
|
|
31
|
+
# Returns nothing.
|
|
13
32
|
def register_compressor(mime_type, sym, klass)
|
|
14
33
|
self.config = hash_reassoc(config, :compressors, mime_type) do |compressors|
|
|
15
34
|
compressors[sym] = klass
|
|
@@ -35,7 +54,7 @@ module Sprockets
|
|
|
35
54
|
if compressor.is_a?(Symbol)
|
|
36
55
|
@css_compressor = klass = config[:compressors]['text/css'][compressor] || raise(Error, "unknown compressor: #{compressor}")
|
|
37
56
|
elsif compressor.respond_to?(:compress)
|
|
38
|
-
klass =
|
|
57
|
+
klass = proc { |input| compressor.compress(input[:data]) }
|
|
39
58
|
@css_compressor = :css_compressor
|
|
40
59
|
else
|
|
41
60
|
@css_compressor = klass = compressor
|
|
@@ -62,7 +81,7 @@ module Sprockets
|
|
|
62
81
|
if compressor.is_a?(Symbol)
|
|
63
82
|
@js_compressor = klass = config[:compressors]['application/javascript'][compressor] || raise(Error, "unknown compressor: #{compressor}")
|
|
64
83
|
elsif compressor.respond_to?(:compress)
|
|
65
|
-
klass =
|
|
84
|
+
klass = proc { |input| compressor.compress(input[:data]) }
|
|
66
85
|
@js_compressor = :js_compressor
|
|
67
86
|
else
|
|
68
87
|
@js_compressor = klass = compressor
|
|
@@ -83,12 +102,33 @@ module Sprockets
|
|
|
83
102
|
|
|
84
103
|
# Public: Enable or disable the creation of Gzip files.
|
|
85
104
|
#
|
|
86
|
-
#
|
|
105
|
+
# To disable gzip generation set to a falsey value:
|
|
87
106
|
#
|
|
88
107
|
# environment.gzip = false
|
|
89
108
|
#
|
|
109
|
+
# To enable set to a truthy value. By default zlib wil
|
|
110
|
+
# be used to gzip assets. If you have the Zopfli gem
|
|
111
|
+
# installed you can specify the zopfli algorithm to be used
|
|
112
|
+
# instead:
|
|
113
|
+
#
|
|
114
|
+
# environment.gzip = :zopfli
|
|
115
|
+
#
|
|
90
116
|
def gzip=(gzip)
|
|
91
117
|
self.config = config.merge(gzip_enabled: gzip).freeze
|
|
118
|
+
|
|
119
|
+
case gzip
|
|
120
|
+
when false, nil
|
|
121
|
+
self.unregister_exporter Exporters::ZlibExporter
|
|
122
|
+
self.unregister_exporter Exporters::ZopfliExporter
|
|
123
|
+
when :zopfli
|
|
124
|
+
self.unregister_exporter Exporters::ZlibExporter
|
|
125
|
+
self.register_exporter '*/*', Exporters::ZopfliExporter
|
|
126
|
+
else
|
|
127
|
+
self.unregister_exporter Exporters::ZopfliExporter
|
|
128
|
+
self.register_exporter '*/*', Exporters::ZlibExporter
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
gzip
|
|
92
132
|
end
|
|
93
133
|
end
|
|
94
134
|
end
|
|
@@ -1,27 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'sprockets/compressing'
|
|
2
3
|
require 'sprockets/dependencies'
|
|
3
|
-
require 'sprockets/engines'
|
|
4
4
|
require 'sprockets/mime'
|
|
5
5
|
require 'sprockets/paths'
|
|
6
6
|
require 'sprockets/processing'
|
|
7
|
+
require 'sprockets/exporting'
|
|
7
8
|
require 'sprockets/transformers'
|
|
8
9
|
require 'sprockets/utils'
|
|
9
10
|
|
|
10
11
|
module Sprockets
|
|
11
12
|
module Configuration
|
|
12
|
-
include Paths, Mime,
|
|
13
|
+
include Paths, Mime, Transformers, Processing, Exporting, Compressing, Dependencies, Utils
|
|
13
14
|
|
|
14
15
|
def initialize_configuration(parent)
|
|
15
16
|
@config = parent.config
|
|
16
|
-
@computed_config = parent.computed_config
|
|
17
17
|
@logger = parent.logger
|
|
18
18
|
@context_class = Class.new(parent.context_class)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
attr_reader :config
|
|
22
22
|
|
|
23
|
-
attr_accessor :computed_config
|
|
24
|
-
|
|
25
23
|
def config=(config)
|
|
26
24
|
raise TypeError, "can't assign mutable config" unless config.frozen?
|
|
27
25
|
@config = config
|
|
@@ -69,8 +67,6 @@ module Sprockets
|
|
|
69
67
|
self.config = config.merge(digest_class: klass).freeze
|
|
70
68
|
end
|
|
71
69
|
|
|
72
|
-
# Deprecated: Get `Context` class.
|
|
73
|
-
#
|
|
74
70
|
# This class maybe mutated and mixed in with custom helpers.
|
|
75
71
|
#
|
|
76
72
|
# environment.context_class.instance_eval do
|
data/lib/sprockets/context.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
require 'rack/utils'
|
|
3
3
|
require 'set'
|
|
4
4
|
require 'sprockets/errors'
|
|
5
5
|
|
|
6
6
|
module Sprockets
|
|
7
|
-
# Deprecated: `Context` provides helper methods to all processors.
|
|
8
7
|
# They are typically accessed by ERB templates. You can mix in custom helpers
|
|
9
8
|
# by injecting them into `Environment#context_class`. Do not mix them into
|
|
10
9
|
# `Context` directly.
|
|
@@ -19,10 +18,25 @@ module Sprockets
|
|
|
19
18
|
# The `Context` also collects dependencies declared by
|
|
20
19
|
# assets. See `DirectiveProcessor` for an example of this.
|
|
21
20
|
class Context
|
|
22
|
-
|
|
21
|
+
# Internal: Proxy for ENV that keeps track of the environment variables used
|
|
22
|
+
class ENVProxy < SimpleDelegator
|
|
23
|
+
def initialize(context)
|
|
24
|
+
@context = context
|
|
25
|
+
super(ENV)
|
|
26
|
+
end
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
def [](key)
|
|
29
|
+
@context.depend_on_env(key)
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def fetch(key, *)
|
|
34
|
+
@context.depend_on_env(key)
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :environment, :filename
|
|
26
40
|
|
|
27
41
|
def initialize(input)
|
|
28
42
|
@environment = input[:environment]
|
|
@@ -31,7 +45,6 @@ module Sprockets
|
|
|
31
45
|
@logical_path = input[:name]
|
|
32
46
|
@filename = input[:filename]
|
|
33
47
|
@dirname = File.dirname(@filename)
|
|
34
|
-
@pathname = Pathname.new(@filename)
|
|
35
48
|
@content_type = input[:content_type]
|
|
36
49
|
|
|
37
50
|
@required = Set.new(@metadata[:required])
|
|
@@ -47,6 +60,10 @@ module Sprockets
|
|
|
47
60
|
dependencies: @dependencies }
|
|
48
61
|
end
|
|
49
62
|
|
|
63
|
+
def env_proxy
|
|
64
|
+
ENVProxy.new(self)
|
|
65
|
+
end
|
|
66
|
+
|
|
50
67
|
# Returns the environment path that contains the file.
|
|
51
68
|
#
|
|
52
69
|
# If `app/javascripts` and `app/stylesheets` are in your path, and
|
|
@@ -79,13 +96,13 @@ module Sprockets
|
|
|
79
96
|
# resolve("./bar.js")
|
|
80
97
|
# # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
|
|
81
98
|
#
|
|
82
|
-
# path
|
|
83
|
-
#
|
|
84
|
-
# accept - String content accept type
|
|
99
|
+
# path - String logical or absolute path
|
|
100
|
+
# accept - String content accept type
|
|
85
101
|
#
|
|
86
102
|
# Returns an Asset URI String.
|
|
87
|
-
def resolve(path,
|
|
88
|
-
|
|
103
|
+
def resolve(path, **kargs)
|
|
104
|
+
kargs[:base_path] = @dirname
|
|
105
|
+
uri, deps = environment.resolve!(path, **kargs)
|
|
89
106
|
@dependencies.merge(deps)
|
|
90
107
|
uri
|
|
91
108
|
end
|
|
@@ -105,15 +122,13 @@ module Sprockets
|
|
|
105
122
|
# including it.
|
|
106
123
|
#
|
|
107
124
|
# This is used for caching purposes. Any changes made to
|
|
108
|
-
# the dependency file
|
|
125
|
+
# the dependency file will invalidate the cache of the
|
|
109
126
|
# source file.
|
|
110
127
|
def depend_on(path)
|
|
111
|
-
path = path.to_s if path.is_a?(Pathname)
|
|
112
|
-
|
|
113
128
|
if environment.absolute_path?(path) && environment.stat(path)
|
|
114
129
|
@dependencies << environment.build_file_digest_uri(path)
|
|
115
130
|
else
|
|
116
|
-
resolve(path
|
|
131
|
+
resolve(path)
|
|
117
132
|
end
|
|
118
133
|
nil
|
|
119
134
|
end
|
|
@@ -123,10 +138,19 @@ module Sprockets
|
|
|
123
138
|
#
|
|
124
139
|
# This is used for caching purposes. Any changes that would
|
|
125
140
|
# invalidate the dependency asset will invalidate the source
|
|
126
|
-
# file. Unlike `depend_on`, this will
|
|
141
|
+
# file. Unlike `depend_on`, this will recursively include
|
|
127
142
|
# the target asset's dependencies.
|
|
128
143
|
def depend_on_asset(path)
|
|
129
|
-
load(resolve(path
|
|
144
|
+
load(resolve(path))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# `depend_on_env` allows you to state a dependency on an environment
|
|
148
|
+
# variable.
|
|
149
|
+
#
|
|
150
|
+
# This is used for caching purposes. Any changes in the value of the
|
|
151
|
+
# environment variable will invalidate the cache of the source file.
|
|
152
|
+
def depend_on_env(key)
|
|
153
|
+
@dependencies << "env:#{key}"
|
|
130
154
|
end
|
|
131
155
|
|
|
132
156
|
# `require_asset` declares `path` as a dependency of the file. The
|
|
@@ -139,7 +163,7 @@ module Sprockets
|
|
|
139
163
|
# <%= require_asset "#{framework}.js" %>
|
|
140
164
|
#
|
|
141
165
|
def require_asset(path)
|
|
142
|
-
@required << resolve(path, accept: @content_type, pipeline: :self
|
|
166
|
+
@required << resolve(path, accept: @content_type, pipeline: :self)
|
|
143
167
|
nil
|
|
144
168
|
end
|
|
145
169
|
|
|
@@ -147,7 +171,7 @@ module Sprockets
|
|
|
147
171
|
# `path` must be an asset which may or may not already be included
|
|
148
172
|
# in the bundle.
|
|
149
173
|
def stub_asset(path)
|
|
150
|
-
@stubbed << resolve(path, accept: @content_type, pipeline: :self
|
|
174
|
+
@stubbed << resolve(path, accept: @content_type, pipeline: :self)
|
|
151
175
|
nil
|
|
152
176
|
end
|
|
153
177
|
|
|
@@ -162,9 +186,10 @@ module Sprockets
|
|
|
162
186
|
asset
|
|
163
187
|
end
|
|
164
188
|
|
|
165
|
-
# Returns a
|
|
166
|
-
#
|
|
167
|
-
#
|
|
189
|
+
# Returns a `data:` URI with the contents of the asset at the specified
|
|
190
|
+
# path, and marks that path as a dependency of the current file.
|
|
191
|
+
#
|
|
192
|
+
# Uses URI encoding for SVG files, base64 encoding for all the other files.
|
|
168
193
|
#
|
|
169
194
|
# Use `asset_data_uri` from ERB with CSS or JavaScript assets:
|
|
170
195
|
#
|
|
@@ -174,8 +199,11 @@ module Sprockets
|
|
|
174
199
|
#
|
|
175
200
|
def asset_data_uri(path)
|
|
176
201
|
asset = depend_on_asset(path)
|
|
177
|
-
|
|
178
|
-
|
|
202
|
+
if asset.content_type == 'image/svg+xml'
|
|
203
|
+
svg_asset_data_uri(asset)
|
|
204
|
+
else
|
|
205
|
+
base64_asset_data_uri(asset)
|
|
206
|
+
end
|
|
179
207
|
end
|
|
180
208
|
|
|
181
209
|
# Expands logical path to full url to asset.
|
|
@@ -227,5 +255,50 @@ Extend your environment context with a custom method.
|
|
|
227
255
|
def stylesheet_path(path)
|
|
228
256
|
asset_path(path, type: :stylesheet)
|
|
229
257
|
end
|
|
258
|
+
|
|
259
|
+
protected
|
|
260
|
+
|
|
261
|
+
# Returns a URI-encoded data URI (always "-quoted).
|
|
262
|
+
def svg_asset_data_uri(asset)
|
|
263
|
+
svg = asset.source.dup
|
|
264
|
+
optimize_svg_for_uri_escaping!(svg)
|
|
265
|
+
data = Rack::Utils.escape(svg)
|
|
266
|
+
optimize_quoted_uri_escapes!(data)
|
|
267
|
+
"\"data:#{asset.content_type};charset=utf-8,#{data}\""
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Returns a Base64-encoded data URI.
|
|
271
|
+
def base64_asset_data_uri(asset)
|
|
272
|
+
data = Rack::Utils.escape(EncodingUtils.base64(asset.source))
|
|
273
|
+
"data:#{asset.content_type};base64,#{data}"
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Optimizes an SVG for being URI-escaped.
|
|
277
|
+
#
|
|
278
|
+
# This method only performs these basic but crucial optimizations:
|
|
279
|
+
# * Replaces " with ', because ' does not need escaping.
|
|
280
|
+
# * Removes comments, meta, doctype, and newlines.
|
|
281
|
+
# * Collapses whitespace.
|
|
282
|
+
def optimize_svg_for_uri_escaping!(svg)
|
|
283
|
+
# Remove comments, xml meta, and doctype
|
|
284
|
+
svg.gsub!(/<!--.*?-->|<\?.*?\?>|<!.*?>/m, '')
|
|
285
|
+
# Replace consecutive whitespace and newlines with a space
|
|
286
|
+
svg.gsub!(/\s+/, ' ')
|
|
287
|
+
# Collapse inter-tag whitespace
|
|
288
|
+
svg.gsub!('> <', '><')
|
|
289
|
+
# Replace " with '
|
|
290
|
+
svg.gsub!(/([\w:])="(.*?)"/, "\\1='\\2'")
|
|
291
|
+
svg.strip!
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Un-escapes characters in the given URI-escaped string that do not need
|
|
295
|
+
# escaping in "-quoted data URIs.
|
|
296
|
+
def optimize_quoted_uri_escapes!(escaped)
|
|
297
|
+
escaped.gsub!('%3D', '=')
|
|
298
|
+
escaped.gsub!('%3A', ':')
|
|
299
|
+
escaped.gsub!('%2F', '/')
|
|
300
|
+
escaped.gsub!('%27', "'")
|
|
301
|
+
escaped.tr!('+', ' ')
|
|
302
|
+
end
|
|
230
303
|
end
|
|
231
304
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'digest/md5'
|
|
2
3
|
require 'digest/sha1'
|
|
3
4
|
require 'digest/sha2'
|
|
@@ -62,7 +63,7 @@ module Sprockets
|
|
|
62
63
|
},
|
|
63
64
|
Set => ->(val, digest) {
|
|
64
65
|
digest << 'Set'.freeze
|
|
65
|
-
ADD_VALUE_TO_DIGEST[Array].call(val
|
|
66
|
+
ADD_VALUE_TO_DIGEST[Array].call(val, digest)
|
|
66
67
|
},
|
|
67
68
|
Encoding => ->(val, digest) {
|
|
68
69
|
digest << 'Encoding'.freeze
|
|
@@ -79,6 +80,9 @@ module Sprockets
|
|
|
79
80
|
digest << val.to_s
|
|
80
81
|
}
|
|
81
82
|
end
|
|
83
|
+
|
|
84
|
+
ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
|
|
85
|
+
|
|
82
86
|
ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
|
|
83
87
|
raise TypeError, "couldn't digest #{ val }"
|
|
84
88
|
}
|
|
@@ -93,10 +97,18 @@ module Sprockets
|
|
|
93
97
|
#
|
|
94
98
|
# Returns a String digest of the object.
|
|
95
99
|
def digest(obj)
|
|
96
|
-
digest
|
|
100
|
+
build_digest(obj).digest
|
|
101
|
+
end
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
|
104
|
+
#
|
|
105
|
+
# The same as `pack_hexdigest(digest(obj))`.
|
|
106
|
+
#
|
|
107
|
+
# obj - A JSON serializable object.
|
|
108
|
+
#
|
|
109
|
+
# Returns a String digest of the object.
|
|
110
|
+
def hexdigest(obj)
|
|
111
|
+
build_digest(obj).hexdigest!
|
|
100
112
|
end
|
|
101
113
|
|
|
102
114
|
# Internal: Pack a binary digest to a hex encoded string.
|
|
@@ -105,7 +117,7 @@ module Sprockets
|
|
|
105
117
|
#
|
|
106
118
|
# Returns hex String.
|
|
107
119
|
def pack_hexdigest(bin)
|
|
108
|
-
bin.unpack('H*').first
|
|
120
|
+
bin.unpack('H*'.freeze).first
|
|
109
121
|
end
|
|
110
122
|
|
|
111
123
|
# Internal: Unpack a hex encoded digest string into binary bytes.
|
|
@@ -176,5 +188,13 @@ module Sprockets
|
|
|
176
188
|
def hexdigest_integrity_uri(hexdigest)
|
|
177
189
|
integrity_uri(unpack_hexdigest(hexdigest))
|
|
178
190
|
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
def build_digest(obj)
|
|
194
|
+
digest = digest_class.new
|
|
195
|
+
|
|
196
|
+
ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
|
|
197
|
+
digest
|
|
198
|
+
end
|
|
179
199
|
end
|
|
180
200
|
end
|