sprockets 3.7.3 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -265
- data/{LICENSE → MIT-LICENSE} +2 -2
- data/README.md +527 -320
- data/bin/sprockets +11 -7
- data/lib/rake/sprocketstask.rb +9 -4
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +39 -27
- 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 +49 -12
- data/lib/sprockets/bower.rb +6 -3
- data/lib/sprockets/bundle.rb +41 -5
- data/lib/sprockets/cache/file_store.rb +25 -3
- data/lib/sprockets/cache/memory_store.rb +28 -10
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +37 -2
- data/lib/sprockets/cached_environment.rb +15 -20
- data/lib/sprockets/closure_compressor.rb +1 -0
- data/lib/sprockets/coffee_script_processor.rb +19 -5
- data/lib/sprockets/compressing.rb +43 -3
- data/lib/sprockets/configuration.rb +5 -9
- data/lib/sprockets/context.rb +99 -25
- data/lib/sprockets/dependencies.rb +2 -1
- data/lib/sprockets/digest_utils.rb +35 -18
- data/lib/sprockets/directive_processor.rb +64 -38
- data/lib/sprockets/eco_processor.rb +2 -1
- data/lib/sprockets/ejs_processor.rb +2 -1
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +33 -32
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +71 -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 +88 -68
- data/lib/sprockets/manifest.rb +67 -64
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -62
- 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 +88 -8
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +32 -62
- data/lib/sprockets/processor_utils.rb +28 -38
- 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 +31 -10
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +52 -39
- 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 +12 -12
- data/lib/sprockets/utils/gzip.rb +46 -14
- data/lib/sprockets/utils.rb +64 -90
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +1 -0
- data/lib/sprockets.rb +102 -39
- metadata +135 -43
- 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
data/lib/sprockets/loader.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/asset'
|
2
3
|
require 'sprockets/digest_utils'
|
3
|
-
require 'sprockets/engines'
|
4
4
|
require 'sprockets/errors'
|
5
5
|
require 'sprockets/file_reader'
|
6
6
|
require 'sprockets/mime'
|
@@ -18,7 +18,7 @@ module Sprockets
|
|
18
18
|
# object.
|
19
19
|
module Loader
|
20
20
|
include DigestUtils, PathUtils, ProcessorUtils, URIUtils
|
21
|
-
include
|
21
|
+
include Mime, Processing, Resolve, Transformers
|
22
22
|
|
23
23
|
|
24
24
|
# Public: Load Asset by Asset URI.
|
@@ -27,7 +27,6 @@ module Sprockets
|
|
27
27
|
# and full path such as:
|
28
28
|
# "file:///Path/app/assets/js/app.js?type=application/javascript"
|
29
29
|
#
|
30
|
-
#
|
31
30
|
# Returns Asset.
|
32
31
|
def load(uri)
|
33
32
|
unloaded = UnloadedAsset.new(uri, self)
|
@@ -46,7 +45,7 @@ module Sprockets
|
|
46
45
|
# The presence of `paths` indicates dependencies were stored.
|
47
46
|
# We can check to see if the dependencies have not changed by "resolving" them and
|
48
47
|
# generating a digest key from the resolved entries. If this digest key has not
|
49
|
-
# changed the asset will be pulled from cache.
|
48
|
+
# changed, the asset will be pulled from cache.
|
50
49
|
#
|
51
50
|
# If this `paths` is present but the cache returns nothing then `fetch_asset_from_dependency_cache`
|
52
51
|
# will confusingly be called again with `paths` set to nil where the asset will be
|
@@ -61,10 +60,47 @@ module Sprockets
|
|
61
60
|
end
|
62
61
|
end
|
63
62
|
end
|
64
|
-
Asset.new(
|
63
|
+
Asset.new(asset)
|
65
64
|
end
|
66
65
|
|
67
66
|
private
|
67
|
+
def compress_key_from_hash(hash, key)
|
68
|
+
return unless hash.key?(key)
|
69
|
+
value = hash[key].dup
|
70
|
+
return if !value
|
71
|
+
|
72
|
+
if block_given?
|
73
|
+
value.map! do |x|
|
74
|
+
if yield x
|
75
|
+
compress_from_root(x)
|
76
|
+
else
|
77
|
+
x
|
78
|
+
end
|
79
|
+
end
|
80
|
+
else
|
81
|
+
value.map! { |x| compress_from_root(x) }
|
82
|
+
end
|
83
|
+
hash[key] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def expand_key_from_hash(hash, key)
|
88
|
+
return unless hash.key?(key)
|
89
|
+
value = hash[key].dup
|
90
|
+
return if !value
|
91
|
+
if block_given?
|
92
|
+
value.map! do |x|
|
93
|
+
if yield x
|
94
|
+
expand_from_root(x)
|
95
|
+
else
|
96
|
+
x
|
97
|
+
end
|
98
|
+
end
|
99
|
+
else
|
100
|
+
value.map! { |x| expand_from_root(x) }
|
101
|
+
end
|
102
|
+
hash[key] = value
|
103
|
+
end
|
68
104
|
|
69
105
|
# Internal: Load asset hash from cache
|
70
106
|
#
|
@@ -78,15 +114,17 @@ module Sprockets
|
|
78
114
|
asset[:uri] = expand_from_root(asset[:uri])
|
79
115
|
asset[:load_path] = expand_from_root(asset[:load_path])
|
80
116
|
asset[:filename] = expand_from_root(asset[:filename])
|
81
|
-
asset[:metadata]
|
82
|
-
asset[:metadata]
|
83
|
-
asset[:metadata]
|
84
|
-
asset[:metadata]
|
85
|
-
asset[:metadata]
|
117
|
+
expand_key_from_hash(asset[:metadata], :included)
|
118
|
+
expand_key_from_hash(asset[:metadata], :links)
|
119
|
+
expand_key_from_hash(asset[:metadata], :stubbed)
|
120
|
+
expand_key_from_hash(asset[:metadata], :required)
|
121
|
+
expand_key_from_hash(asset[:metadata], :to_load)
|
122
|
+
expand_key_from_hash(asset[:metadata], :to_link)
|
123
|
+
expand_key_from_hash(asset[:metadata], :dependencies) { |uri| uri.start_with?("file-digest://") }
|
86
124
|
|
87
125
|
asset[:metadata].each_key do |k|
|
88
|
-
next unless k
|
89
|
-
asset[:metadata]
|
126
|
+
next unless k.match?(/_dependencies\z/) # rubocop:disable Performance/EndWith
|
127
|
+
expand_key_from_hash(asset[:metadata], k)
|
90
128
|
end
|
91
129
|
end
|
92
130
|
asset
|
@@ -103,13 +141,23 @@ module Sprockets
|
|
103
141
|
raise FileNotFound, "could not find file: #{unloaded.filename}"
|
104
142
|
end
|
105
143
|
|
106
|
-
|
144
|
+
path_to_split =
|
145
|
+
if index_alias = unloaded.params[:index_alias]
|
146
|
+
expand_from_root index_alias
|
147
|
+
else
|
148
|
+
unloaded.filename
|
149
|
+
end
|
150
|
+
|
151
|
+
load_path, logical_path = paths_split(config[:paths], path_to_split)
|
107
152
|
|
108
153
|
unless load_path
|
109
|
-
|
154
|
+
target = path_to_split
|
155
|
+
target += " (index alias of #{unloaded.filename})" if unloaded.params[:index_alias]
|
156
|
+
raise FileOutsidePaths, "#{target} is no longer under a load path: #{self.paths.join(', ')}"
|
110
157
|
end
|
111
158
|
|
112
|
-
|
159
|
+
extname, file_type = match_path_extname(logical_path, mime_exts)
|
160
|
+
logical_path = logical_path.chomp(extname)
|
113
161
|
name = logical_path
|
114
162
|
|
115
163
|
if pipeline = unloaded.params[:pipeline]
|
@@ -124,9 +172,9 @@ module Sprockets
|
|
124
172
|
raise ConversionError, "could not convert #{file_type.inspect} to #{type.inspect}"
|
125
173
|
end
|
126
174
|
|
127
|
-
processors = processors_for(type, file_type,
|
175
|
+
processors = processors_for(type, file_type, pipeline)
|
128
176
|
|
129
|
-
processors_dep_uri = build_processors_uri(type, file_type,
|
177
|
+
processors_dep_uri = build_processors_uri(type, file_type, pipeline)
|
130
178
|
dependencies = config[:dependencies] + [processors_dep_uri]
|
131
179
|
|
132
180
|
# Read into memory and process if theres a processor pipeline
|
@@ -139,7 +187,9 @@ module Sprockets
|
|
139
187
|
load_path: load_path,
|
140
188
|
name: name,
|
141
189
|
content_type: type,
|
142
|
-
metadata: {
|
190
|
+
metadata: {
|
191
|
+
dependencies: dependencies
|
192
|
+
}
|
143
193
|
})
|
144
194
|
validate_processor_result!(result)
|
145
195
|
source = result.delete(:data)
|
@@ -147,12 +197,14 @@ module Sprockets
|
|
147
197
|
metadata[:charset] = source.encoding.name.downcase unless metadata.key?(:charset)
|
148
198
|
metadata[:digest] = digest(source)
|
149
199
|
metadata[:length] = source.bytesize
|
200
|
+
metadata[:environment_version] = version
|
150
201
|
else
|
151
202
|
dependencies << build_file_digest_uri(unloaded.filename)
|
152
203
|
metadata = {
|
153
204
|
digest: file_digest(unloaded.filename),
|
154
205
|
length: self.stat(unloaded.filename).size,
|
155
|
-
dependencies: dependencies
|
206
|
+
dependencies: dependencies,
|
207
|
+
environment_version: version,
|
156
208
|
}
|
157
209
|
end
|
158
210
|
|
@@ -168,20 +220,9 @@ module Sprockets
|
|
168
220
|
dependencies_digest: DigestUtils.digest(resolve_dependencies(metadata[:dependencies]))
|
169
221
|
}
|
170
222
|
|
171
|
-
asset[:id] =
|
223
|
+
asset[:id] = hexdigest(asset)
|
172
224
|
asset[:uri] = build_asset_uri(unloaded.filename, unloaded.params.merge(id: asset[:id]))
|
173
225
|
|
174
|
-
# Deprecated: Avoid tracking Asset mtime
|
175
|
-
asset[:mtime] = metadata[:dependencies].map { |u|
|
176
|
-
if u.start_with?("file-digest:")
|
177
|
-
s = self.stat(parse_file_digest_uri(u))
|
178
|
-
s ? s.mtime.to_i : nil
|
179
|
-
else
|
180
|
-
nil
|
181
|
-
end
|
182
|
-
}.compact.max
|
183
|
-
asset[:mtime] ||= self.stat(unloaded.filename).mtime.to_i
|
184
|
-
|
185
226
|
store_asset(asset, unloaded)
|
186
227
|
asset
|
187
228
|
end
|
@@ -203,38 +244,17 @@ module Sprockets
|
|
203
244
|
if cached_asset[:metadata]
|
204
245
|
# Deep dup to avoid modifying `asset`
|
205
246
|
cached_asset[:metadata] = cached_asset[:metadata].dup
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
cached_asset[:metadata][:links].map! { |uri| compress_from_root(uri) }
|
214
|
-
end
|
215
|
-
|
216
|
-
if cached_asset[:metadata][:stubbed] && !cached_asset[:metadata][:stubbed].empty?
|
217
|
-
cached_asset[:metadata][:stubbed] = cached_asset[:metadata][:stubbed].dup
|
218
|
-
cached_asset[:metadata][:stubbed].map! { |uri| compress_from_root(uri) }
|
219
|
-
end
|
220
|
-
|
221
|
-
if cached_asset[:metadata][:required] && !cached_asset[:metadata][:required].empty?
|
222
|
-
cached_asset[:metadata][:required] = cached_asset[:metadata][:required].dup
|
223
|
-
cached_asset[:metadata][:required].map! { |uri| compress_from_root(uri) }
|
224
|
-
end
|
225
|
-
|
226
|
-
if cached_asset[:metadata][:dependencies] && !cached_asset[:metadata][:dependencies].empty?
|
227
|
-
cached_asset[:metadata][:dependencies] = cached_asset[:metadata][:dependencies].dup
|
228
|
-
cached_asset[:metadata][:dependencies].map! do |uri|
|
229
|
-
uri.start_with?("file-digest://".freeze) ? compress_from_root(uri) : uri
|
230
|
-
end
|
231
|
-
end
|
247
|
+
compress_key_from_hash(cached_asset[:metadata], :included)
|
248
|
+
compress_key_from_hash(cached_asset[:metadata], :links)
|
249
|
+
compress_key_from_hash(cached_asset[:metadata], :stubbed)
|
250
|
+
compress_key_from_hash(cached_asset[:metadata], :required)
|
251
|
+
compress_key_from_hash(cached_asset[:metadata], :to_load)
|
252
|
+
compress_key_from_hash(cached_asset[:metadata], :to_link)
|
253
|
+
compress_key_from_hash(cached_asset[:metadata], :dependencies) { |uri| uri.start_with?("file-digest://") }
|
232
254
|
|
233
|
-
# compress all _dependencies in metadata like `sass_dependencies`
|
234
255
|
cached_asset[:metadata].each do |key, value|
|
235
|
-
next unless key
|
236
|
-
cached_asset[:metadata]
|
237
|
-
cached_asset[:metadata][key].map! {|uri| compress_from_root(uri) }
|
256
|
+
next unless key.match?(/_dependencies\z/) # rubocop:disable Performance/EndWith
|
257
|
+
compress_key_from_hash(cached_asset[:metadata], key)
|
238
258
|
end
|
239
259
|
end
|
240
260
|
|
@@ -255,11 +275,11 @@ module Sprockets
|
|
255
275
|
# "processors:type=text/css&file_type=text/css&pipeline=self",
|
256
276
|
# "file-digest:///Full/path/app/assets/stylesheets"]
|
257
277
|
#
|
258
|
-
# Returns back array of things that the given uri
|
278
|
+
# Returns back array of things that the given uri depends on
|
259
279
|
# For example the environment version, if you're using a different version of sprockets
|
260
280
|
# then the dependencies should be different, this is used only for generating cache key
|
261
281
|
# for example the "environment-version" may be resolved to "environment-1.0-3.2.0" for
|
262
|
-
#
|
282
|
+
# version "3.2.0" of sprockets.
|
263
283
|
#
|
264
284
|
# Any paths that are returned are converted to relative paths
|
265
285
|
#
|
@@ -271,14 +291,14 @@ module Sprockets
|
|
271
291
|
# Internal: Retrieves an asset based on its digest
|
272
292
|
#
|
273
293
|
# unloaded - An UnloadedAsset
|
274
|
-
# limit -
|
294
|
+
# limit - An Integer which sets the maximum number of versions of "histories"
|
275
295
|
# stored in the cache
|
276
296
|
#
|
277
297
|
# This method attempts to retrieve the last `limit` number of histories of an asset
|
278
298
|
# from the cache a "history" which is an array of unresolved "dependencies" that the asset needs
|
279
|
-
# to compile. In this case
|
280
|
-
# may rely on jquery.js (so jquery.js is a
|
281
|
-
# compilation, such as the VERSION of
|
299
|
+
# to compile. In this case a dependency can refer to either an asset e.g. index.js
|
300
|
+
# may rely on jquery.js (so jquery.js is a dependency), or other factors that may affect
|
301
|
+
# compilation, such as the VERSION of Sprockets (i.e. the environment) and what "processors"
|
282
302
|
# are used.
|
283
303
|
#
|
284
304
|
# For example a history array may look something like this
|
@@ -289,7 +309,7 @@ module Sprockets
|
|
289
309
|
# "file-digest:///Full/path/app/assets/stylesheets"]]
|
290
310
|
#
|
291
311
|
# Where the first entry is a Set of dependencies for last generated version of that asset.
|
292
|
-
# Multiple versions are stored since
|
312
|
+
# Multiple versions are stored since Sprockets keeps the last `limit` number of assets
|
293
313
|
# generated present in the system.
|
294
314
|
#
|
295
315
|
# If a "history" of dependencies is present in the cache, each version of "history" will be
|
data/lib/sprockets/manifest.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
require 'time'
|
3
4
|
|
4
5
|
require 'concurrent'
|
5
6
|
|
6
7
|
require 'sprockets/manifest_utils'
|
7
|
-
require 'sprockets/utils/gzip'
|
8
8
|
|
9
9
|
module Sprockets
|
10
10
|
# The Manifest logs the contents of assets compiled to a single directory. It
|
@@ -15,7 +15,7 @@ module Sprockets
|
|
15
15
|
# The JSON is part of the public API and should be considered stable. This
|
16
16
|
# should make it easy to read from other programming languages and processes
|
17
17
|
# that don't have sprockets loaded. See `#assets` and `#files` for more
|
18
|
-
#
|
18
|
+
# information about the structure.
|
19
19
|
class Manifest
|
20
20
|
include ManifestUtils
|
21
21
|
|
@@ -52,14 +52,8 @@ module Sprockets
|
|
52
52
|
@directory ||= File.dirname(@filename) if @filename
|
53
53
|
|
54
54
|
# If directory is given w/o filename, pick a random manifest location
|
55
|
-
@rename_filename = nil
|
56
55
|
if @directory && @filename.nil?
|
57
|
-
@filename = find_directory_manifest(@directory)
|
58
|
-
|
59
|
-
# If legacy manifest name autodetected, mark to rename on save
|
60
|
-
if File.basename(@filename).start_with?("manifest")
|
61
|
-
@rename_filename = File.join(@directory, generate_manifest_path)
|
62
|
-
end
|
56
|
+
@filename = find_directory_manifest(@directory, logger)
|
63
57
|
end
|
64
58
|
|
65
59
|
unless @directory && @filename
|
@@ -118,32 +112,22 @@ module Sprockets
|
|
118
112
|
# Public: Find all assets matching pattern set in environment.
|
119
113
|
#
|
120
114
|
# Returns Enumerator of Assets.
|
121
|
-
def find(*args)
|
115
|
+
def find(*args, &block)
|
122
116
|
unless environment
|
123
117
|
raise Error, "manifest requires environment for compilation"
|
124
118
|
end
|
125
119
|
|
126
120
|
return to_enum(__method__, *args) unless block_given?
|
127
121
|
|
128
|
-
paths, filters = args.flatten.partition { |arg| self.class.simple_logical_path?(arg) }
|
129
|
-
filters = filters.map { |arg| self.class.compile_match_filter(arg) }
|
130
|
-
|
131
122
|
environment = self.environment.cached
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
yield asset
|
123
|
+
promises = args.flatten.map do |path|
|
124
|
+
Concurrent::Promise.execute(executor: executor) do
|
125
|
+
environment.find_all_linked_assets(path).to_a
|
136
126
|
end
|
137
127
|
end
|
138
128
|
|
139
|
-
|
140
|
-
|
141
|
-
if filters.any? { |f| f.call(logical_path, filename) }
|
142
|
-
environment.find_all_linked_assets(filename) do |asset|
|
143
|
-
yield asset
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
129
|
+
promises.each do |promise|
|
130
|
+
promise.value!.each(&block)
|
147
131
|
end
|
148
132
|
|
149
133
|
nil
|
@@ -167,7 +151,7 @@ module Sprockets
|
|
167
151
|
end
|
168
152
|
end
|
169
153
|
|
170
|
-
# Compile
|
154
|
+
# Compile asset to directory. The asset is written to a
|
171
155
|
# fingerprinted filename like
|
172
156
|
# `application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js`. An entry is
|
173
157
|
# also inserted into the manifest file.
|
@@ -179,14 +163,19 @@ module Sprockets
|
|
179
163
|
raise Error, "manifest requires environment for compilation"
|
180
164
|
end
|
181
165
|
|
182
|
-
filenames
|
183
|
-
|
184
|
-
concurrent_writers = []
|
166
|
+
filenames = []
|
167
|
+
concurrent_exporters = []
|
185
168
|
|
169
|
+
assets_to_export = Concurrent::Array.new
|
186
170
|
find(*args) do |asset|
|
171
|
+
assets_to_export << asset
|
172
|
+
end
|
173
|
+
|
174
|
+
assets_to_export.each do |asset|
|
175
|
+
mtime = Time.now.iso8601
|
187
176
|
files[asset.digest_path] = {
|
188
177
|
'logical_path' => asset.logical_path,
|
189
|
-
'mtime' =>
|
178
|
+
'mtime' => mtime,
|
190
179
|
'size' => asset.bytesize,
|
191
180
|
'digest' => asset.hexdigest,
|
192
181
|
|
@@ -197,38 +186,23 @@ module Sprockets
|
|
197
186
|
}
|
198
187
|
assets[asset.logical_path] = asset.digest_path
|
199
188
|
|
200
|
-
if alias_logical_path = self.class.compute_alias_logical_path(asset.logical_path)
|
201
|
-
assets[alias_logical_path] = asset.digest_path
|
202
|
-
end
|
203
|
-
|
204
|
-
target = File.join(dir, asset.digest_path)
|
205
|
-
|
206
|
-
if File.exist?(target)
|
207
|
-
logger.debug "Skipping #{target}, already exists"
|
208
|
-
else
|
209
|
-
logger.info "Writing #{target}"
|
210
|
-
write_file = Concurrent::Future.execute { asset.write_to target }
|
211
|
-
concurrent_writers << write_file
|
212
|
-
end
|
213
189
|
filenames << asset.filename
|
214
190
|
|
215
|
-
|
216
|
-
|
217
|
-
|
191
|
+
promise = nil
|
192
|
+
exporters_for_asset(asset) do |exporter|
|
193
|
+
next if exporter.skip?(logger)
|
218
194
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
write_file.wait! if write_file
|
225
|
-
gzip.compress(target)
|
195
|
+
if promise.nil?
|
196
|
+
promise = Concurrent::Promise.new(executor: executor) { exporter.call }
|
197
|
+
concurrent_exporters << promise.execute
|
198
|
+
else
|
199
|
+
concurrent_exporters << promise.then { exporter.call }
|
226
200
|
end
|
227
201
|
end
|
228
|
-
|
229
202
|
end
|
230
|
-
|
231
|
-
|
203
|
+
|
204
|
+
# make sure all exporters have finished before returning the main thread
|
205
|
+
concurrent_exporters.each(&:wait!)
|
232
206
|
save
|
233
207
|
|
234
208
|
filenames
|
@@ -295,18 +269,13 @@ module Sprockets
|
|
295
269
|
def clobber
|
296
270
|
FileUtils.rm_r(directory) if File.exist?(directory)
|
297
271
|
logger.info "Removed #{directory}"
|
272
|
+
# if we have an environment clear the cache too
|
273
|
+
environment.cache.clear if environment
|
298
274
|
nil
|
299
275
|
end
|
300
276
|
|
301
|
-
# Persist
|
277
|
+
# Persist manifest back to FS
|
302
278
|
def save
|
303
|
-
if @rename_filename
|
304
|
-
logger.info "Renaming #{@filename} to #{@rename_filename}"
|
305
|
-
FileUtils.mv(@filename, @rename_filename)
|
306
|
-
@filename = @rename_filename
|
307
|
-
@rename_filename = nil
|
308
|
-
end
|
309
|
-
|
310
279
|
data = json_encode(@data)
|
311
280
|
FileUtils.mkdir_p File.dirname(@filename)
|
312
281
|
PathUtils.atomic_write(@filename) do |f|
|
@@ -315,6 +284,36 @@ module Sprockets
|
|
315
284
|
end
|
316
285
|
|
317
286
|
private
|
287
|
+
|
288
|
+
# Given an asset, finds all exporters that
|
289
|
+
# match its mime-type.
|
290
|
+
#
|
291
|
+
# Will yield each expoter to the passed in block.
|
292
|
+
#
|
293
|
+
# array = []
|
294
|
+
# puts asset.content_type # => "application/javascript"
|
295
|
+
# exporters_for_asset(asset) do |exporter|
|
296
|
+
# array << exporter
|
297
|
+
# end
|
298
|
+
# # puts array => [Exporters::FileExporter, Exporters::ZlibExporter]
|
299
|
+
def exporters_for_asset(asset)
|
300
|
+
exporters = [Exporters::FileExporter]
|
301
|
+
|
302
|
+
environment.exporters.each do |mime_type, exporter_list|
|
303
|
+
next unless asset.content_type
|
304
|
+
next unless environment.match_mime_type? asset.content_type, mime_type
|
305
|
+
exporter_list.each do |exporter|
|
306
|
+
exporters << exporter
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
exporters.uniq!
|
311
|
+
|
312
|
+
exporters.each do |exporter|
|
313
|
+
yield exporter.new(asset: asset, environment: environment, directory: dir)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
318
317
|
def json_decode(obj)
|
319
318
|
JSON.parse(obj, create_additions: false)
|
320
319
|
end
|
@@ -332,5 +331,9 @@ module Sprockets
|
|
332
331
|
logger
|
333
332
|
end
|
334
333
|
end
|
334
|
+
|
335
|
+
def executor
|
336
|
+
@executor ||= environment.export_concurrent ? :fast : :immediate
|
337
|
+
end
|
335
338
|
end
|
336
339
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'securerandom'
|
3
|
+
require 'logger'
|
2
4
|
|
3
5
|
module Sprockets
|
4
6
|
# Public: Manifest utilities.
|
@@ -6,7 +8,6 @@ module Sprockets
|
|
6
8
|
extend self
|
7
9
|
|
8
10
|
MANIFEST_RE = /^\.sprockets-manifest-[0-9a-f]{32}.json$/
|
9
|
-
LEGACY_MANIFEST_RE = /^manifest(-[0-9a-f]{32})?.json$/
|
10
11
|
|
11
12
|
# Public: Generate a new random manifest path.
|
12
13
|
#
|
@@ -33,12 +34,14 @@ module Sprockets
|
|
33
34
|
# # => "/app/public/assets/.sprockets-manifest-abc123.json"
|
34
35
|
#
|
35
36
|
# Returns String filename.
|
36
|
-
def find_directory_manifest(dirname)
|
37
|
+
def find_directory_manifest(dirname, logger = Logger.new($stderr))
|
37
38
|
entries = File.directory?(dirname) ? Dir.entries(dirname) : []
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
manifest_entries = entries.select { |e| e =~ MANIFEST_RE }
|
40
|
+
if manifest_entries.length > 1
|
41
|
+
manifest_entries.sort!
|
42
|
+
logger.warn("Found multiple manifests: #{manifest_entries}. Choosing the first alphabetically: #{manifest_entries.first}")
|
43
|
+
end
|
44
|
+
entry = manifest_entries.first || generate_manifest_path
|
42
45
|
File.join(dirname, entry)
|
43
46
|
end
|
44
47
|
end
|
data/lib/sprockets/mime.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/encoding_utils'
|
2
3
|
require 'sprockets/http_utils'
|
3
4
|
require 'sprockets/utils'
|
@@ -36,29 +37,18 @@ module Sprockets
|
|
36
37
|
|
37
38
|
# Public: Register a new mime type.
|
38
39
|
#
|
39
|
-
# mime_type
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# See EncodingUtils.
|
40
|
+
# mime_type - String MIME Type
|
41
|
+
# extensions - Array of String extnames
|
42
|
+
# charset - Proc/Method that detects the charset of a file.
|
43
|
+
# See EncodingUtils.
|
44
44
|
#
|
45
45
|
# Returns nothing.
|
46
|
-
def register_mime_type(mime_type,
|
47
|
-
|
48
|
-
if options.is_a?(String)
|
49
|
-
options = { extensions: [options] }
|
50
|
-
end
|
51
|
-
|
52
|
-
extnames = Array(options[:extensions]).map { |extname|
|
53
|
-
Sprockets::Utils.normalize_extension(extname)
|
54
|
-
}
|
46
|
+
def register_mime_type(mime_type, extensions: [], charset: nil)
|
47
|
+
extnames = Array(extensions)
|
55
48
|
|
56
|
-
charset = options[:charset]
|
57
49
|
charset ||= :default if mime_type.start_with?('text/')
|
58
50
|
charset = EncodingUtils::CHARSET_DETECT[charset] if charset.is_a?(Symbol)
|
59
51
|
|
60
|
-
self.computed_config = {}
|
61
|
-
|
62
52
|
self.config = hash_reassoc(config, :mime_exts) do |mime_exts|
|
63
53
|
extnames.each do |extname|
|
64
54
|
mime_exts[extname] = mime_type
|
@@ -97,54 +87,10 @@ module Sprockets
|
|
97
87
|
data = File.binread(filename)
|
98
88
|
|
99
89
|
if detect = mime_type_charset_detecter(content_type)
|
100
|
-
detect.call(data).encode(Encoding::UTF_8, :
|
90
|
+
detect.call(data).encode(Encoding::UTF_8, universal_newline: true)
|
101
91
|
else
|
102
92
|
data
|
103
93
|
end
|
104
94
|
end
|
105
|
-
|
106
|
-
private
|
107
|
-
def extname_map
|
108
|
-
self.computed_config[:_extnames] ||= compute_extname_map
|
109
|
-
end
|
110
|
-
|
111
|
-
def compute_extname_map
|
112
|
-
graph = {}
|
113
|
-
|
114
|
-
engine_extname_permutation = []
|
115
|
-
|
116
|
-
4.times do |n|
|
117
|
-
config[:engines].keys.permutation(n).each do |engine_extnames|
|
118
|
-
engine_extname_permutation << engine_extnames
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
mime_exts_grouped_by_mime_type = {}
|
123
|
-
config[:mime_exts].each do |format_extname,format_type|
|
124
|
-
mime_exts_grouped_by_mime_type[format_type] ||= []
|
125
|
-
mime_exts_grouped_by_mime_type[format_type] << format_extname
|
126
|
-
end
|
127
|
-
|
128
|
-
([nil] + pipelines.keys.map(&:to_s)).each do |pipeline|
|
129
|
-
pipeline_extname = pipeline ? ".#{pipeline}" : ''.freeze
|
130
|
-
engine_extname_permutation.each do |engine_extnames|
|
131
|
-
mime_exts_grouped_by_mime_type.each do |format_type, format_extnames|
|
132
|
-
type = format_type
|
133
|
-
value = [type, engine_extnames, pipeline]
|
134
|
-
format_extnames.each do |format_extname|
|
135
|
-
key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}"
|
136
|
-
graph[key] = value
|
137
|
-
end
|
138
|
-
if format_type == config[:engine_mime_types][engine_extnames.first]
|
139
|
-
key = "#{pipeline_extname}#{engine_extnames.join}"
|
140
|
-
graph[key] = value
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
graph[pipeline_extname] = [nil, [], pipeline]
|
145
|
-
end
|
146
|
-
|
147
|
-
graph
|
148
|
-
end
|
149
95
|
end
|
150
96
|
end
|