sprockets 3.7.2 → 4.1.1
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 +62 -262
- 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 +9 -0
- 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 -36
- 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 +34 -21
- 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 -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 +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 +38 -25
- 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 +45 -75
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +1 -0
- data/lib/sprockets.rb +102 -39
- metadata +128 -23
- 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,34 +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
|
-
([nil] + pipelines.keys.map(&:to_s)).each do |pipeline|
|
115
|
-
pipeline_extname = ".#{pipeline}" if pipeline
|
116
|
-
([[nil, nil]] + config[:mime_exts].to_a).each do |format_extname, format_type|
|
117
|
-
4.times do |n|
|
118
|
-
config[:engines].keys.permutation(n).each do |engine_extnames|
|
119
|
-
key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}"
|
120
|
-
type = format_type || config[:engine_mime_types][engine_extnames.first]
|
121
|
-
graph[key] = {type: type, engines: engine_extnames, pipeline: pipeline}
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
graph
|
128
|
-
end
|
129
95
|
end
|
130
96
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Sprockets
|
5
|
+
module Npm
|
6
|
+
# Internal: Override resolve_alternates to install package.json behavior.
|
7
|
+
#
|
8
|
+
# load_path - String environment path
|
9
|
+
# logical_path - String path relative to base
|
10
|
+
#
|
11
|
+
# Returns candidate filenames.
|
12
|
+
def resolve_alternates(load_path, logical_path)
|
13
|
+
candidates, deps = super
|
14
|
+
|
15
|
+
dirname = File.join(load_path, logical_path)
|
16
|
+
|
17
|
+
if directory?(dirname)
|
18
|
+
filename = File.join(dirname, 'package.json')
|
19
|
+
|
20
|
+
if self.file?(filename)
|
21
|
+
deps << build_file_digest_uri(filename)
|
22
|
+
read_package_directives(dirname, filename) do |path|
|
23
|
+
if file?(path)
|
24
|
+
candidates << path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
return candidates, deps
|
31
|
+
end
|
32
|
+
|
33
|
+
# Internal: Read package.json's main and style directives.
|
34
|
+
#
|
35
|
+
# dirname - String path to component directory.
|
36
|
+
# filename - String path to package.json.
|
37
|
+
#
|
38
|
+
# Returns nothing.
|
39
|
+
def read_package_directives(dirname, filename)
|
40
|
+
package = JSON.parse(File.read(filename), create_additions: false)
|
41
|
+
|
42
|
+
case package['main']
|
43
|
+
when String
|
44
|
+
yield File.expand_path(package['main'], dirname)
|
45
|
+
when nil
|
46
|
+
yield File.expand_path('index.js', dirname)
|
47
|
+
end
|
48
|
+
|
49
|
+
yield File.expand_path(package['style'], dirname) if package['style']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|