sprockets 3.7.3 → 4.2.2
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 +77 -259
- 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 +2 -2
- 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 +91 -69
- 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 +63 -40
- 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 +19 -16
- 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 +148 -45
- 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]
|
@@ -117,16 +165,18 @@ module Sprockets
|
|
117
165
|
end
|
118
166
|
|
119
167
|
if type = unloaded.params[:type]
|
120
|
-
|
168
|
+
extensions = config[:mime_types][type][:extensions]
|
169
|
+
extension = extensions.include?(extname) ? extname : extensions.first
|
170
|
+
logical_path += extension
|
121
171
|
end
|
122
172
|
|
123
173
|
if type != file_type && !config[:transformers][file_type][type]
|
124
174
|
raise ConversionError, "could not convert #{file_type.inspect} to #{type.inspect}"
|
125
175
|
end
|
126
176
|
|
127
|
-
processors = processors_for(type, file_type,
|
177
|
+
processors = processors_for(type, file_type, pipeline)
|
128
178
|
|
129
|
-
processors_dep_uri = build_processors_uri(type, file_type,
|
179
|
+
processors_dep_uri = build_processors_uri(type, file_type, pipeline)
|
130
180
|
dependencies = config[:dependencies] + [processors_dep_uri]
|
131
181
|
|
132
182
|
# Read into memory and process if theres a processor pipeline
|
@@ -139,7 +189,9 @@ module Sprockets
|
|
139
189
|
load_path: load_path,
|
140
190
|
name: name,
|
141
191
|
content_type: type,
|
142
|
-
metadata: {
|
192
|
+
metadata: {
|
193
|
+
dependencies: dependencies
|
194
|
+
}
|
143
195
|
})
|
144
196
|
validate_processor_result!(result)
|
145
197
|
source = result.delete(:data)
|
@@ -147,12 +199,14 @@ module Sprockets
|
|
147
199
|
metadata[:charset] = source.encoding.name.downcase unless metadata.key?(:charset)
|
148
200
|
metadata[:digest] = digest(source)
|
149
201
|
metadata[:length] = source.bytesize
|
202
|
+
metadata[:environment_version] = version
|
150
203
|
else
|
151
204
|
dependencies << build_file_digest_uri(unloaded.filename)
|
152
205
|
metadata = {
|
153
206
|
digest: file_digest(unloaded.filename),
|
154
207
|
length: self.stat(unloaded.filename).size,
|
155
|
-
dependencies: dependencies
|
208
|
+
dependencies: dependencies,
|
209
|
+
environment_version: version,
|
156
210
|
}
|
157
211
|
end
|
158
212
|
|
@@ -168,20 +222,9 @@ module Sprockets
|
|
168
222
|
dependencies_digest: DigestUtils.digest(resolve_dependencies(metadata[:dependencies]))
|
169
223
|
}
|
170
224
|
|
171
|
-
asset[:id] =
|
225
|
+
asset[:id] = hexdigest(asset)
|
172
226
|
asset[:uri] = build_asset_uri(unloaded.filename, unloaded.params.merge(id: asset[:id]))
|
173
227
|
|
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
228
|
store_asset(asset, unloaded)
|
186
229
|
asset
|
187
230
|
end
|
@@ -203,38 +246,17 @@ module Sprockets
|
|
203
246
|
if cached_asset[:metadata]
|
204
247
|
# Deep dup to avoid modifying `asset`
|
205
248
|
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
|
249
|
+
compress_key_from_hash(cached_asset[:metadata], :included)
|
250
|
+
compress_key_from_hash(cached_asset[:metadata], :links)
|
251
|
+
compress_key_from_hash(cached_asset[:metadata], :stubbed)
|
252
|
+
compress_key_from_hash(cached_asset[:metadata], :required)
|
253
|
+
compress_key_from_hash(cached_asset[:metadata], :to_load)
|
254
|
+
compress_key_from_hash(cached_asset[:metadata], :to_link)
|
255
|
+
compress_key_from_hash(cached_asset[:metadata], :dependencies) { |uri| uri.start_with?("file-digest://") }
|
232
256
|
|
233
|
-
# compress all _dependencies in metadata like `sass_dependencies`
|
234
257
|
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) }
|
258
|
+
next unless key.match?(/_dependencies\z/) # rubocop:disable Performance/EndWith
|
259
|
+
compress_key_from_hash(cached_asset[:metadata], key)
|
238
260
|
end
|
239
261
|
end
|
240
262
|
|
@@ -255,11 +277,11 @@ module Sprockets
|
|
255
277
|
# "processors:type=text/css&file_type=text/css&pipeline=self",
|
256
278
|
# "file-digest:///Full/path/app/assets/stylesheets"]
|
257
279
|
#
|
258
|
-
# Returns back array of things that the given uri
|
280
|
+
# Returns back array of things that the given uri depends on
|
259
281
|
# For example the environment version, if you're using a different version of sprockets
|
260
282
|
# then the dependencies should be different, this is used only for generating cache key
|
261
283
|
# for example the "environment-version" may be resolved to "environment-1.0-3.2.0" for
|
262
|
-
#
|
284
|
+
# version "3.2.0" of sprockets.
|
263
285
|
#
|
264
286
|
# Any paths that are returned are converted to relative paths
|
265
287
|
#
|
@@ -271,14 +293,14 @@ module Sprockets
|
|
271
293
|
# Internal: Retrieves an asset based on its digest
|
272
294
|
#
|
273
295
|
# unloaded - An UnloadedAsset
|
274
|
-
# limit -
|
296
|
+
# limit - An Integer which sets the maximum number of versions of "histories"
|
275
297
|
# stored in the cache
|
276
298
|
#
|
277
299
|
# This method attempts to retrieve the last `limit` number of histories of an asset
|
278
300
|
# 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
|
301
|
+
# to compile. In this case a dependency can refer to either an asset e.g. index.js
|
302
|
+
# may rely on jquery.js (so jquery.js is a dependency), or other factors that may affect
|
303
|
+
# compilation, such as the VERSION of Sprockets (i.e. the environment) and what "processors"
|
282
304
|
# are used.
|
283
305
|
#
|
284
306
|
# For example a history array may look something like this
|
@@ -289,7 +311,7 @@ module Sprockets
|
|
289
311
|
# "file-digest:///Full/path/app/assets/stylesheets"]]
|
290
312
|
#
|
291
313
|
# Where the first entry is a Set of dependencies for last generated version of that asset.
|
292
|
-
# Multiple versions are stored since
|
314
|
+
# Multiple versions are stored since Sprockets keeps the last `limit` number of assets
|
293
315
|
# generated present in the system.
|
294
316
|
#
|
295
317
|
# 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
|