sprockets 4.0.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -2
  3. data/MIT-LICENSE +21 -0
  4. data/README.md +103 -19
  5. data/lib/rake/sprocketstask.rb +6 -2
  6. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +1 -1
  7. data/lib/sprockets/asset.rb +23 -6
  8. data/lib/sprockets/base.rb +2 -2
  9. data/lib/sprockets/bower.rb +1 -1
  10. data/lib/sprockets/bundle.rb +1 -1
  11. data/lib/sprockets/cache/memory_store.rb +20 -11
  12. data/lib/sprockets/cache.rb +1 -1
  13. data/lib/sprockets/cached_environment.rb +11 -11
  14. data/lib/sprockets/coffee_script_processor.rb +2 -2
  15. data/lib/sprockets/configuration.rb +2 -2
  16. data/lib/sprockets/context.rb +2 -1
  17. data/lib/sprockets/dependencies.rb +1 -1
  18. data/lib/sprockets/digest_utils.rb +10 -13
  19. data/lib/sprockets/directive_processor.rb +19 -1
  20. data/lib/sprockets/eco_processor.rb +1 -1
  21. data/lib/sprockets/ejs_processor.rb +1 -1
  22. data/lib/sprockets/erb_processor.rb +8 -2
  23. data/lib/sprockets/exporters/base.rb +2 -3
  24. data/lib/sprockets/exporting.rb +2 -2
  25. data/lib/sprockets/loader.rb +5 -3
  26. data/lib/sprockets/manifest.rb +8 -7
  27. data/lib/sprockets/npm.rb +1 -1
  28. data/lib/sprockets/path_utils.rb +1 -1
  29. data/lib/sprockets/processing.rb +1 -1
  30. data/lib/sprockets/processor_utils.rb +4 -3
  31. data/lib/sprockets/sass_processor.rb +1 -1
  32. data/lib/sprockets/sassc_processor.rb +1 -1
  33. data/lib/sprockets/server.rb +30 -20
  34. data/lib/sprockets/source_map_processor.rb +1 -1
  35. data/lib/sprockets/source_map_utils.rb +4 -4
  36. data/lib/sprockets/uri_utils.rb +1 -1
  37. data/lib/sprockets/utils.rb +24 -16
  38. data/lib/sprockets/version.rb +1 -1
  39. data/lib/sprockets.rb +4 -1
  40. metadata +15 -14
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'digest/md5'
3
2
  require 'digest/sha1'
4
3
  require 'digest/sha2'
5
4
  require 'set'
@@ -19,7 +18,6 @@ module Sprockets
19
18
 
20
19
  # Internal: Maps digest bytesize to the digest class.
21
20
  DIGEST_SIZES = {
22
- 16 => Digest::MD5,
23
21
  20 => Digest::SHA1,
24
22
  32 => Digest::SHA256,
25
23
  48 => Digest::SHA384,
@@ -68,18 +66,8 @@ module Sprockets
68
66
  Encoding => ->(val, digest) {
69
67
  digest << 'Encoding'.freeze
70
68
  digest << val.name
71
- },
72
- }
73
- if 0.class != Integer # Ruby < 2.4
74
- ADD_VALUE_TO_DIGEST[Fixnum] = ->(val, digest) {
75
- digest << 'Integer'.freeze
76
- digest << val.to_s
77
- }
78
- ADD_VALUE_TO_DIGEST[Bignum] = ->(val, digest) {
79
- digest << 'Integer'.freeze
80
- digest << val.to_s
81
69
  }
82
- end
70
+ }
83
71
 
84
72
  ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
85
73
 
@@ -189,6 +177,15 @@ module Sprockets
189
177
  integrity_uri(unpack_hexdigest(hexdigest))
190
178
  end
191
179
 
180
+ # Internal: Checks an asset name for a valid digest
181
+ #
182
+ # name - The name of the asset
183
+ #
184
+ # Returns true if the name contains a digest like string and .digested before the extension
185
+ def already_digested?(name)
186
+ return name =~ /-([0-9a-zA-Z]{7,128})\.digested/
187
+ end
188
+
192
189
  private
193
190
  def build_digest(obj)
194
191
  digest = digest_class.new
@@ -285,6 +285,24 @@ module Sprockets
285
285
  to_load(resolve(path))
286
286
  end
287
287
 
288
+ # Allows you to state a dependency on a relative directory
289
+ # without including it.
290
+ #
291
+ # This is used for caching purposes. Any changes made to
292
+ # the dependency directory will invalidate the cache of the
293
+ # source file.
294
+ #
295
+ # This is useful if you are using ERB and File.read to pull
296
+ # in contents from multiple files in a directory.
297
+ #
298
+ # //= depend_on_directory ./data
299
+ #
300
+ def process_depend_on_directory_directive(path = ".", accept = nil)
301
+ path = expand_relative_dirname(:depend_on_directory, path)
302
+ accept = expand_accept_shorthand(accept)
303
+ resolve_paths(*@environment.stat_directory_with_dependencies(path), accept: accept)
304
+ end
305
+
288
306
  # Allows dependency to be excluded from the asset bundle.
289
307
  #
290
308
  # The `path` must be a valid asset and may or may not already
@@ -374,7 +392,7 @@ module Sprockets
374
392
  next if subpath == @filename || stat.directory?
375
393
  uri, deps = @environment.resolve(subpath, **kargs)
376
394
  @dependencies.merge(deps)
377
- yield uri if uri
395
+ yield uri if uri && block_given?
378
396
  end
379
397
  end
380
398
 
@@ -4,7 +4,7 @@ require 'sprockets/autoload'
4
4
  module Sprockets
5
5
  # Processor engine class for the Eco compiler. Depends on the `eco` gem.
6
6
  #
7
- # For more infomation see:
7
+ # For more information see:
8
8
  #
9
9
  # https://github.com/sstephenson/ruby-eco
10
10
  # https://github.com/sstephenson/eco
@@ -4,7 +4,7 @@ require 'sprockets/autoload'
4
4
  module Sprockets
5
5
  # Processor engine class for the EJS compiler. Depends on the `ejs` gem.
6
6
  #
7
- # For more infomation see:
7
+ # For more information see:
8
8
  #
9
9
  # https://github.com/sstephenson/ruby-ejs
10
10
  #
@@ -18,8 +18,7 @@ class Sprockets::ERBProcessor
18
18
  end
19
19
 
20
20
  def call(input)
21
- match = ERB.version.match(/\Aerb\.rb \[(?<version>[^ ]+) /)
22
- if match && match[:version] >= "2.2.0" # Ruby 2.6+
21
+ if keyword_constructor? # Ruby 2.6+
23
22
  engine = ::ERB.new(input[:data], trim_mode: '<>')
24
23
  else
25
24
  engine = ::ERB.new(input[:data], nil, '<>')
@@ -34,4 +33,11 @@ class Sprockets::ERBProcessor
34
33
  data = engine.result(context.instance_eval('binding'))
35
34
  context.metadata.merge(data: data)
36
35
  end
36
+
37
+ private
38
+
39
+ def keyword_constructor?
40
+ return @keyword_constructor if defined? @keyword_constructor
41
+ @keyword_constructor = ::ERB.instance_method(:initialize).parameters.include?([:key, :trim_mode])
42
+ end
37
43
  end
@@ -1,6 +1,6 @@
1
1
  module Sprockets
2
2
  module Exporters
3
- # Convienence class for all exporters to inherit from
3
+ # Convenience class for all exporters to inherit from
4
4
  #
5
5
  # An exporter is responsible for exporting a Sprockets::Asset
6
6
  # to a file system. For example the Exporters::File class
@@ -29,7 +29,7 @@ module Sprockets
29
29
  setup
30
30
  end
31
31
 
32
- # Public: Callback that is executed after intialization
32
+ # Public: Callback that is executed after initialization
33
33
  #
34
34
  # Any setup that needs to be done can be performed in the +setup+
35
35
  # method. It will be called immediately after initialization.
@@ -69,4 +69,3 @@ module Sprockets
69
69
  end
70
70
  end
71
71
  end
72
-
@@ -28,11 +28,11 @@ module Sprockets
28
28
 
29
29
  # Public: Remove Exporting processor `klass` for `mime_type`.
30
30
  #
31
- # environment.unregister_exporter '*/*', Sprockets::Exporters::Zlib
31
+ # environment.unregister_exporter '*/*', Sprockets::Exporters::ZlibExporter
32
32
  #
33
33
  # Can be called without a mime type
34
34
  #
35
- # environment.unregister_exporter Sprockets::Exporters::Zlib
35
+ # environment.unregister_exporter Sprockets::Exporters::ZlibExporter
36
36
  #
37
37
  # Does not remove any exporters that depend on `klass`.
38
38
  def unregister_exporter(mime_types, exporter = nil)
@@ -195,14 +195,16 @@ module Sprockets
195
195
  source = result.delete(:data)
196
196
  metadata = result
197
197
  metadata[:charset] = source.encoding.name.downcase unless metadata.key?(:charset)
198
- metadata[:digest] = digest(self.version + source)
198
+ metadata[:digest] = digest(source)
199
199
  metadata[:length] = source.bytesize
200
+ metadata[:environment_version] = version
200
201
  else
201
202
  dependencies << build_file_digest_uri(unloaded.filename)
202
203
  metadata = {
203
204
  digest: file_digest(unloaded.filename),
204
205
  length: self.stat(unloaded.filename).size,
205
- dependencies: dependencies
206
+ dependencies: dependencies,
207
+ environment_version: version,
206
208
  }
207
209
  end
208
210
 
@@ -289,7 +291,7 @@ module Sprockets
289
291
  # Internal: Retrieves an asset based on its digest
290
292
  #
291
293
  # unloaded - An UnloadedAsset
292
- # limit - A Fixnum which sets the maximum number of versions of "histories"
294
+ # limit - An Integer which sets the maximum number of versions of "histories"
293
295
  # stored in the cache
294
296
  #
295
297
  # This method attempts to retrieve the last `limit` number of histories of an asset
@@ -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
- # infomation about the structure.
18
+ # information about the structure.
19
19
  class Manifest
20
20
  include ManifestUtils
21
21
 
@@ -112,7 +112,7 @@ module Sprockets
112
112
  # Public: Find all assets matching pattern set in environment.
113
113
  #
114
114
  # Returns Enumerator of Assets.
115
- def find(*args)
115
+ def find(*args, &block)
116
116
  unless environment
117
117
  raise Error, "manifest requires environment for compilation"
118
118
  end
@@ -122,12 +122,13 @@ module Sprockets
122
122
  environment = self.environment.cached
123
123
  promises = args.flatten.map do |path|
124
124
  Concurrent::Promise.execute(executor: executor) do
125
- environment.find_all_linked_assets(path) do |asset|
126
- yield asset
127
- end
125
+ environment.find_all_linked_assets(path).to_a
128
126
  end
129
127
  end
130
- promises.each(&:wait!)
128
+
129
+ promises.each do |promise|
130
+ promise.value!.each(&block)
131
+ end
131
132
 
132
133
  nil
133
134
  end
@@ -273,7 +274,7 @@ module Sprockets
273
274
  nil
274
275
  end
275
276
 
276
- # Persist manfiest back to FS
277
+ # Persist manifest back to FS
277
278
  def save
278
279
  data = json_encode(@data)
279
280
  FileUtils.mkdir_p File.dirname(@filename)
data/lib/sprockets/npm.rb CHANGED
@@ -8,7 +8,7 @@ module Sprockets
8
8
  # load_path - String environment path
9
9
  # logical_path - String path relative to base
10
10
  #
11
- # Returns candiate filenames.
11
+ # Returns candidate filenames.
12
12
  def resolve_alternates(load_path, logical_path)
13
13
  candidates, deps = super
14
14
 
@@ -162,7 +162,7 @@ module Sprockets
162
162
  def split_subpath(path, subpath)
163
163
  return "" if path == subpath
164
164
  path = File.join(path, ''.freeze)
165
- if subpath.start_with?(path)
165
+ if subpath&.start_with?(path)
166
166
  subpath[path.length..-1]
167
167
  else
168
168
  nil
@@ -130,7 +130,7 @@ module Sprockets
130
130
  #
131
131
  # mime_type - String MIME Type. Use '*/*' applies to all types.
132
132
  # key - Symbol metadata key
133
- # initial - Initial memo to pass to the reduce funciton (default: nil)
133
+ # initial - Initial memo to pass to the reduce function (default: nil)
134
134
  # block - Proc accepting the memo accumulator and current value
135
135
  #
136
136
  # Returns nothing.
@@ -6,7 +6,7 @@ module Sprockets
6
6
  #
7
7
  # A Processor is a general function that may modify or transform an asset as
8
8
  # part of the pipeline. CoffeeScript to JavaScript conversion, Minification
9
- # or Concatenation are all implemented as seperate Processor steps.
9
+ # or Concatenation are all implemented as separate Processor steps.
10
10
  #
11
11
  # Processors maybe any object that responds to call. So procs or a class that
12
12
  # defines a self.call method.
@@ -118,8 +118,9 @@ module Sprockets
118
118
  Symbol,
119
119
  TrueClass,
120
120
  FalseClass,
121
- NilClass
122
- ] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
121
+ NilClass,
122
+ Integer
123
+ ]).freeze
123
124
 
124
125
  # Internal: Set of all nested compound metadata types that can nest values.
125
126
  VALID_METADATA_COMPOUND_TYPES = Set.new([
@@ -7,7 +7,7 @@ require 'uri'
7
7
  module Sprockets
8
8
  # Processor engine class for the SASS/SCSS compiler. Depends on the `sass` gem.
9
9
  #
10
- # For more infomation see:
10
+ # For more information see:
11
11
  #
12
12
  # https://github.com/sass/sass
13
13
  # https://github.com/rails/sass-rails
@@ -7,7 +7,7 @@ require 'uri'
7
7
  module Sprockets
8
8
  # Processor engine class for the SASS/SCSS compiler. Depends on the `sassc` gem.
9
9
  #
10
- # For more infomation see:
10
+ # For more information see:
11
11
  #
12
12
  # https://github.com/sass/sassc-ruby
13
13
  # https://github.com/sass/sassc-rails
@@ -35,7 +35,8 @@ module Sprockets
35
35
  msg = "Served asset #{env['PATH_INFO']} -"
36
36
 
37
37
  # Extract the path from everything after the leading slash
38
- path = Rack::Utils.unescape(env['PATH_INFO'].to_s.sub(/^\//, ''))
38
+ full_path = Rack::Utils.unescape(env['PATH_INFO'].to_s.sub(/^\//, ''))
39
+ path = full_path
39
40
 
40
41
  unless path.valid_encoding?
41
42
  return bad_request_response(env)
@@ -64,6 +65,15 @@ module Sprockets
64
65
  # Look up the asset.
65
66
  asset = find_asset(path)
66
67
 
68
+ # Fallback to looking up the asset with the full path.
69
+ # This will make assets that are hashed with webpack or
70
+ # other js bundlers work consistently between production
71
+ # and development pipelines.
72
+ if asset.nil? && (asset = find_asset(full_path))
73
+ if_match = asset.etag if fingerprint
74
+ fingerprint = asset.etag
75
+ end
76
+
67
77
  if asset.nil?
68
78
  status = :not_found
69
79
  elsif fingerprint && asset.etag != fingerprint
@@ -138,39 +148,39 @@ module Sprockets
138
148
  # Returns a 400 Forbidden response tuple
139
149
  def bad_request_response(env)
140
150
  if head_request?(env)
141
- [ 400, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ]
151
+ [ 400, { "content-type" => "text/plain", "content-length" => "0" }, [] ]
142
152
  else
143
- [ 400, { "Content-Type" => "text/plain", "Content-Length" => "11" }, [ "Bad Request" ] ]
153
+ [ 400, { "content-type" => "text/plain", "content-length" => "11" }, [ "Bad Request" ] ]
144
154
  end
145
155
  end
146
156
 
147
157
  # Returns a 403 Forbidden response tuple
148
158
  def forbidden_response(env)
149
159
  if head_request?(env)
150
- [ 403, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ]
160
+ [ 403, { "content-type" => "text/plain", "content-length" => "0" }, [] ]
151
161
  else
152
- [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
162
+ [ 403, { "content-type" => "text/plain", "content-length" => "9" }, [ "Forbidden" ] ]
153
163
  end
154
164
  end
155
165
 
156
166
  # Returns a 404 Not Found response tuple
157
167
  def not_found_response(env)
158
168
  if head_request?(env)
159
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
169
+ [ 404, { "content-type" => "text/plain", "content-length" => "0", "x-cascade" => "pass" }, [] ]
160
170
  else
161
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
171
+ [ 404, { "content-type" => "text/plain", "content-length" => "9", "x-cascade" => "pass" }, [ "Not found" ] ]
162
172
  end
163
173
  end
164
174
 
165
175
  def method_not_allowed_response
166
- [ 405, { "Content-Type" => "text/plain", "Content-Length" => "18" }, [ "Method Not Allowed" ] ]
176
+ [ 405, { "content-type" => "text/plain", "content-length" => "18" }, [ "Method Not Allowed" ] ]
167
177
  end
168
178
 
169
179
  def precondition_failed_response(env)
170
180
  if head_request?(env)
171
- [ 412, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
181
+ [ 412, { "content-type" => "text/plain", "content-length" => "0", "x-cascade" => "pass" }, [] ]
172
182
  else
173
- [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ]
183
+ [ 412, { "content-type" => "text/plain", "content-length" => "19", "x-cascade" => "pass" }, [ "Precondition Failed" ] ]
174
184
  end
175
185
  end
176
186
 
@@ -179,7 +189,7 @@ module Sprockets
179
189
  def javascript_exception_response(exception)
180
190
  err = "#{exception.class.name}: #{exception.message}\n (in #{exception.backtrace[0]})"
181
191
  body = "throw Error(#{err.inspect})"
182
- [ 200, { "Content-Type" => "application/javascript", "Content-Length" => body.bytesize.to_s }, [ body ] ]
192
+ [ 200, { "content-type" => "application/javascript", "content-length" => body.bytesize.to_s }, [ body ] ]
183
193
  end
184
194
 
185
195
  # Returns a CSS response that hides all elements on the page and
@@ -232,7 +242,7 @@ module Sprockets
232
242
  }
233
243
  CSS
234
244
 
235
- [ 200, { "Content-Type" => "text/css; charset=utf-8", "Content-Length" => body.bytesize.to_s }, [ body ] ]
245
+ [ 200, { "content-type" => "text/css; charset=utf-8", "content-length" => body.bytesize.to_s }, [ body ] ]
236
246
  end
237
247
 
238
248
  # Escape special characters for use inside a CSS content("...") string
@@ -248,18 +258,18 @@ module Sprockets
248
258
  headers = {}
249
259
 
250
260
  # Set caching headers
251
- headers["Cache-Control"] = +"public"
252
- headers["ETag"] = %("#{etag}")
261
+ headers["cache-control"] = +"public"
262
+ headers["etag"] = %("#{etag}")
253
263
 
254
264
  # If the request url contains a fingerprint, set a long
255
265
  # expires on the response
256
266
  if path_fingerprint(env["PATH_INFO"])
257
- headers["Cache-Control"] << ", max-age=31536000, immutable"
267
+ headers["cache-control"] << ", max-age=31536000, immutable"
258
268
 
259
269
  # Otherwise set `must-revalidate` since the asset could be modified.
260
270
  else
261
- headers["Cache-Control"] << ", must-revalidate"
262
- headers["Vary"] = "Accept-Encoding"
271
+ headers["cache-control"] << ", must-revalidate"
272
+ headers["vary"] = "Accept-Encoding"
263
273
  end
264
274
 
265
275
  headers
@@ -269,7 +279,7 @@ module Sprockets
269
279
  headers = {}
270
280
 
271
281
  # Set content length header
272
- headers["Content-Length"] = length.to_s
282
+ headers["content-length"] = length.to_s
273
283
 
274
284
  # Set content type header
275
285
  if type = asset.content_type
@@ -277,7 +287,7 @@ module Sprockets
277
287
  if type.start_with?("text/") && asset.charset
278
288
  type += "; charset=#{asset.charset}"
279
289
  end
280
- headers["Content-Type"] = type
290
+ headers["content-type"] = type
281
291
  end
282
292
 
283
293
  headers.merge(cache_headers(env, asset.etag))
@@ -289,7 +299,7 @@ module Sprockets
289
299
  # # => "0aa2105d29558f3eb790d411d7d8fb66"
290
300
  #
291
301
  def path_fingerprint(path)
292
- path[/-([0-9a-f]{7,128})\.[^.]+\z/, 1]
302
+ path[/-([0-9a-zA-Z]{7,128})\.[^.]+\z/, 1]
293
303
  end
294
304
  end
295
305
  end
@@ -9,7 +9,7 @@ module Sprockets
9
9
  # When a file is passed in it will have a `application/js-sourcemap+json`
10
10
  # or `application/css-sourcemap+json` mime type. The filename will be
11
11
  # match the original asset. The original asset is loaded. As it
12
- # gets processed by Sprockets it will aquire all information
12
+ # gets processed by Sprockets it will acquire all information
13
13
  # needed to build a source map file in the `asset.to_hash[:metadata][:map]`
14
14
  # key.
15
15
  #
@@ -78,7 +78,7 @@ module Sprockets
78
78
  offset = 0
79
79
  if a["sections"].count != 0 && !a["sections"].last["map"]["mappings"].empty?
80
80
  last_line_count = a["sections"].last["map"].delete("x_sprockets_linecount")
81
- offset += last_line_count
81
+ offset += last_line_count || 1
82
82
 
83
83
  last_offset = a["sections"].last["offset"]["line"]
84
84
  offset += last_offset
@@ -140,7 +140,7 @@ module Sprockets
140
140
  }
141
141
  end
142
142
 
143
- # Public: Combine two seperate source map transformations into a single
143
+ # Public: Combine two separate source map transformations into a single
144
144
  # mapping.
145
145
  #
146
146
  # Source transformations may happen in discrete steps producing separate
@@ -436,7 +436,7 @@ module Sprockets
436
436
  digit = BASE64_VALUES[str[i]]
437
437
  raise ArgumentError unless digit
438
438
  continuation = (digit & VLQ_CONTINUATION_BIT) != 0
439
- digit &= VLQ_CONTINUATION_BIT - 1
439
+ digit &= VLQ_BASE_MASK
440
440
  value += digit << shift
441
441
  if continuation
442
442
  shift += VLQ_BASE_SHIFT
@@ -453,7 +453,7 @@ module Sprockets
453
453
  #
454
454
  # ary - Two dimensional Array of Integers.
455
455
  #
456
- # Returns a VLQ encoded String seperated by , and ;.
456
+ # Returns a VLQ encoded String separated by , and ;.
457
457
  def vlq_encode_mappings(ary)
458
458
  ary.map { |group|
459
459
  group.map { |segment|
@@ -53,7 +53,7 @@ module Sprockets
53
53
  path = path[1..-1]
54
54
  end
55
55
 
56
- [scheme, host, path, query]
56
+ [scheme, host || '', path, query]
57
57
  end
58
58
 
59
59
  # Internal: Join file: URI component parts into String.
@@ -25,7 +25,7 @@ module Sprockets
25
25
 
26
26
  # Internal: Duplicate and store key/value on new frozen hash.
27
27
  #
28
- # Seperated for recursive calls, always use hash_reassoc(hash, *keys).
28
+ # Separated for recursive calls, always use hash_reassoc(hash, *keys).
29
29
  #
30
30
  # hash - Hash
31
31
  # key - Object key
@@ -118,30 +118,38 @@ module Sprockets
118
118
  buf
119
119
  end
120
120
 
121
+ MODULE_INCLUDE_MUTEX = Mutex.new
122
+ private_constant :MODULE_INCLUDE_MUTEX
123
+
121
124
  # Internal: Inject into target module for the duration of the block.
122
125
  #
123
126
  # mod - Module
124
127
  #
125
128
  # Returns result of block.
126
129
  def module_include(base, mod)
127
- old_methods = {}
130
+ MODULE_INCLUDE_MUTEX.synchronize do
131
+ old_methods = {}
128
132
 
129
- mod.instance_methods.each do |sym|
130
- old_methods[sym] = base.instance_method(sym) if base.method_defined?(sym)
131
- end
133
+ mod.instance_methods.each do |sym|
134
+ old_methods[sym] = base.instance_method(sym) if base.method_defined?(sym)
135
+ end
132
136
 
133
- mod.instance_methods.each do |sym|
134
- method = mod.instance_method(sym)
135
- base.send(:define_method, sym, method)
136
- end
137
+ mod.instance_methods.each do |sym|
138
+ method = mod.instance_method(sym)
139
+ if base.method_defined?(sym)
140
+ base.send(:alias_method, sym, sym)
141
+ end
142
+ base.send(:define_method, sym, method)
143
+ end
137
144
 
138
- yield
139
- ensure
140
- mod.instance_methods.each do |sym|
141
- base.send(:undef_method, sym) if base.method_defined?(sym)
142
- end
143
- old_methods.each do |sym, method|
144
- base.send(:define_method, sym, method)
145
+ yield
146
+ ensure
147
+ mod.instance_methods.each do |sym|
148
+ base.send(:undef_method, sym) if base.method_defined?(sym)
149
+ end
150
+ old_methods.each do |sym, method|
151
+ base.send(:define_method, sym, method)
152
+ end
145
153
  end
146
154
  end
147
155
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sprockets
3
- VERSION = "4.0.0"
3
+ VERSION = "4.2.0"
4
4
  end
data/lib/sprockets.rb CHANGED
@@ -51,6 +51,7 @@ module Sprockets
51
51
  register_mime_type 'application/json', extensions: ['.json'], charset: :unicode
52
52
  register_mime_type 'application/ruby', extensions: ['.rb']
53
53
  register_mime_type 'application/xml', extensions: ['.xml']
54
+ register_mime_type 'application/manifest+json', extensions: ['.webmanifest']
54
55
  register_mime_type 'text/css', extensions: ['.css'], charset: :css
55
56
  register_mime_type 'text/html', extensions: ['.html', '.htm'], charset: :html
56
57
  register_mime_type 'text/plain', extensions: ['.txt', '.text']
@@ -89,7 +90,7 @@ module Sprockets
89
90
  register_mime_type 'application/font-woff2', extensions: ['.woff2']
90
91
 
91
92
  require 'sprockets/source_map_processor'
92
- register_mime_type 'application/js-sourcemap+json', extensions: ['.js.map']
93
+ register_mime_type 'application/js-sourcemap+json', extensions: ['.js.map'], charset: :unicode
93
94
  register_mime_type 'application/css-sourcemap+json', extensions: ['.css.map']
94
95
  register_transformer 'application/javascript', 'application/js-sourcemap+json', SourceMapProcessor
95
96
  register_transformer 'text/css', 'application/css-sourcemap+json', SourceMapProcessor
@@ -180,6 +181,7 @@ module Sprockets
180
181
  application/ecmascript-6
181
182
  application/javascript
182
183
  application/json
184
+ application/manifest+json
183
185
  application/xml
184
186
  text/coffeescript
185
187
  text/css
@@ -189,6 +191,7 @@ module Sprockets
189
191
  text/scss
190
192
  text/yaml
191
193
  text/eco
194
+ text/ejs
192
195
  ), 'application/\2+ruby', '.erb', ERBProcessor)
193
196
 
194
197
  register_mime_type 'application/html+ruby', extensions: ['.html.erb', '.erb', '.rhtml'], charset: :html