sprockets 4.0.0.beta6 → 4.0.0.beta7

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.
@@ -72,10 +72,14 @@ module Sprockets
72
72
  register_mime_type 'audio/aiff', extensions: ['.aiff']
73
73
  register_mime_type 'audio/mpeg', extensions: ['.mp3', '.mp2', '.m2a', '.m3a']
74
74
  register_mime_type 'application/ogg', extensions: ['.ogx']
75
+ register_mime_type 'audio/ogg', extensions: ['.ogg', '.oga']
75
76
  register_mime_type 'audio/midi', extensions: ['.midi', '.mid']
76
77
  register_mime_type 'video/avi', extensions: ['.avi']
77
78
  register_mime_type 'audio/wave', extensions: ['.wav', '.wave']
78
79
  register_mime_type 'video/mp4', extensions: ['.mp4', '.m4v']
80
+ register_mime_type 'audio/aac', extensions: ['.aac']
81
+ register_mime_type 'audio/mp4', extensions: ['.m4a']
82
+ register_mime_type 'audio/flac', extensions: ['.flac']
79
83
 
80
84
  # Common font types
81
85
  register_mime_type 'application/vnd.ms-fontobject', extensions: ['.eot']
@@ -102,9 +106,9 @@ module Sprockets
102
106
  env.default_processors_for(type, file_type)
103
107
  end
104
108
 
105
- require 'sprockets/source_map_comment_processor'
109
+ require 'sprockets/add_source_map_comment_to_asset_processor'
106
110
  register_pipeline :debug do
107
- [SourceMapCommentProcessor]
111
+ [AddSourceMapCommentToAssetProcessor]
108
112
  end
109
113
 
110
114
  require 'sprockets/directive_processor'
@@ -184,6 +188,7 @@ module Sprockets
184
188
  text/sass
185
189
  text/scss
186
190
  text/yaml
191
+ text/eco
187
192
  ), 'application/\2+ruby', '.erb', ERBProcessor)
188
193
 
189
194
  register_mime_type 'application/html+ruby', extensions: ['.html.erb', '.erb', '.rhtml'], charset: :html
@@ -3,8 +3,31 @@ require 'sprockets/uri_utils'
3
3
  require 'sprockets/path_utils'
4
4
 
5
5
  module Sprockets
6
- class SourceMapCommentProcessor
6
+ # This is a processor designed to add a source map "comment"
7
+ # to the bottom of a css or JS file that is serving a source
8
+ # map. An example of a comment might look like this
9
+ #
10
+ # //# application.js-80af0efcc960fc2ac93eda2f7b12e3db40ab360bf6ea269ceed3bea3678326f9.map
11
+ #
12
+ # As an asset is built it gets source map information added
13
+ # to the `asset.to_hash[:metadata][:map]` key. This contains all the
14
+ # information that is needed to build a source map file.
15
+ #
16
+ # To add this comment we must have an asset we can link to.
17
+ # To do this we ensure that the original aset is loaded, then
18
+ # we use a use a special mime type. For example `application/js-sourcemap+json`
19
+ # for a JS source map.
20
+ #
21
+ # This will trigger a new asset to be loaded and generated by the
22
+ # `SourceMapProcessor` processor.
23
+ #
24
+ # Finally once we have that file, we can generate a link to it
25
+ # with it's full fingerprint. This is done and then
26
+ # added to the original asset as a comment at the bottom.
27
+ #
28
+ class AddSourceMapCommentToAssetProcessor
7
29
  def self.call(input)
30
+
8
31
  case input[:content_type]
9
32
  when "application/javascript"
10
33
  comment = "\n//# sourceMappingURL=%s"
@@ -16,6 +16,18 @@ require 'sprockets/source_map_utils'
16
16
  require 'sprockets/uri_tar'
17
17
 
18
18
  module Sprockets
19
+
20
+ class DoubleLinkError < Sprockets::Error
21
+ def initialize(parent_filename:, logical_path:, last_filename:, filename:)
22
+ message = String.new
23
+ message << "Multiple files with the same output path cannot be linked (#{logical_path.inspect})\n"
24
+ message << "In #{parent_filename.inspect} these files were linked:\n"
25
+ message << " - #{last_filename}\n"
26
+ message << " - #{filename}\n"
27
+ super(message)
28
+ end
29
+ end
30
+
19
31
  # `Base` class for `Environment` and `CachedEnvironment`.
20
32
  class Base
21
33
  include PathUtils, PathDependencyUtils, PathDigestUtils, DigestUtils, SourceMapUtils
@@ -73,14 +85,26 @@ module Sprockets
73
85
  def find_all_linked_assets(*args)
74
86
  return to_enum(__method__, *args) unless block_given?
75
87
 
76
- asset = find_asset(*args)
88
+ parent_asset = asset = find_asset(*args)
77
89
  return unless asset
78
90
 
79
91
  yield asset
80
92
  stack = asset.links.to_a
93
+ linked_paths = {}
81
94
 
82
95
  while uri = stack.shift
83
96
  yield asset = load(uri)
97
+
98
+ last_filename = linked_paths[asset.logical_path]
99
+ if last_filename && last_filename != asset.filename
100
+ raise DoubleLinkError.new(
101
+ parent_filename: parent_asset.filename,
102
+ last_filename: last_filename,
103
+ logical_path: asset.logical_path,
104
+ filename: asset.filename
105
+ )
106
+ end
107
+ linked_paths[asset.logical_path] = asset.filename
84
108
  stack = asset.links.to_a + stack
85
109
  end
86
110
 
@@ -186,9 +186,10 @@ module Sprockets
186
186
  asset
187
187
  end
188
188
 
189
- # Returns a Base64-encoded `data:` URI with the contents of the
190
- # asset at the specified path, and marks that path as a dependency
191
- # of the current file.
189
+ # Returns a `data:` URI with the contents of the asset at the specified
190
+ # path, and marks that path as a dependency of the current file.
191
+ #
192
+ # Uses URI encoding for SVG files, base64 encoding for all the other files.
192
193
  #
193
194
  # Use `asset_data_uri` from ERB with CSS or JavaScript assets:
194
195
  #
@@ -198,8 +199,11 @@ module Sprockets
198
199
  #
199
200
  def asset_data_uri(path)
200
201
  asset = depend_on_asset(path)
201
- data = EncodingUtils.base64(asset.source)
202
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(data)}"
202
+ if asset.content_type == 'image/svg+xml'
203
+ svg_asset_data_uri(asset)
204
+ else
205
+ base64_asset_data_uri(asset)
206
+ end
203
207
  end
204
208
 
205
209
  # Expands logical path to full url to asset.
@@ -251,5 +255,50 @@ Extend your environment context with a custom method.
251
255
  def stylesheet_path(path)
252
256
  asset_path(path, type: :stylesheet)
253
257
  end
258
+
259
+ protected
260
+
261
+ # Returns a URI-encoded data URI (always "-quoted).
262
+ def svg_asset_data_uri(asset)
263
+ svg = asset.source.dup
264
+ optimize_svg_for_uri_escaping!(svg)
265
+ data = Rack::Utils.escape(svg)
266
+ optimize_quoted_uri_escapes!(data)
267
+ "\"data:#{asset.content_type};charset=utf-8,#{data}\""
268
+ end
269
+
270
+ # Returns a Base64-encoded data URI.
271
+ def base64_asset_data_uri(asset)
272
+ data = Rack::Utils.escape(EncodingUtils.base64(asset.source))
273
+ "data:#{asset.content_type};base64,#{data}"
274
+ end
275
+
276
+ # Optimizes an SVG for being URI-escaped.
277
+ #
278
+ # This method only performs these basic but crucial optimizations:
279
+ # * Replaces " with ', because ' does not need escaping.
280
+ # * Removes comments, meta, doctype, and newlines.
281
+ # * Collapses whitespace.
282
+ def optimize_svg_for_uri_escaping!(svg)
283
+ # Remove comments, xml meta, and doctype
284
+ svg.gsub!(/<!--.*?-->|<\?.*?\?>|<!.*?>/m, '')
285
+ # Replace consecutive whitespace and newlines with a space
286
+ svg.gsub!(/\s+/, ' ')
287
+ # Collapse inter-tag whitespace
288
+ svg.gsub!('> <', '><')
289
+ # Replace " with '
290
+ svg.gsub!(/([\w:])="(.*?)"/, "\\1='\\2'")
291
+ svg.strip!
292
+ end
293
+
294
+ # Un-escapes characters in the given URI-escaped string that do not need
295
+ # escaping in "-quoted data URIs.
296
+ def optimize_quoted_uri_escapes!(escaped)
297
+ escaped.gsub!('%3D', '=')
298
+ escaped.gsub!('%3A', ':')
299
+ escaped.gsub!('%2F', '/')
300
+ escaped.gsub!('%27', "'")
301
+ escaped.tr!('+', ' ')
302
+ end
254
303
  end
255
304
  end
@@ -81,6 +81,8 @@ module Sprockets
81
81
  asset[:metadata][:links].map! { |uri| expand_from_root(uri) } if asset[:metadata][:links]
82
82
  asset[:metadata][:stubbed].map! { |uri| expand_from_root(uri) } if asset[:metadata][:stubbed]
83
83
  asset[:metadata][:required].map! { |uri| expand_from_root(uri) } if asset[:metadata][:required]
84
+ asset[:metadata][:to_load].map! { |uri| expand_from_root(uri) } if asset[:metadata][:to_load]
85
+ asset[:metadata][:to_link].map! { |uri| expand_from_root(uri) } if asset[:metadata][:to_link]
84
86
  asset[:metadata][:dependencies].map! { |uri| uri.start_with?("file-digest://") ? expand_from_root(uri) : uri } if asset[:metadata][:dependencies]
85
87
 
86
88
  asset[:metadata].each_key do |k|
@@ -140,7 +142,6 @@ module Sprockets
140
142
 
141
143
  # Read into memory and process if theres a processor pipeline
142
144
  if processors.any?
143
-
144
145
  result = call_processors(processors, {
145
146
  environment: self,
146
147
  cache: self.cache,
@@ -224,6 +225,16 @@ module Sprockets
224
225
  cached_asset[:metadata][:required].map! { |uri| compress_from_root(uri) }
225
226
  end
226
227
 
228
+ if cached_asset[:metadata][:to_load] && !cached_asset[:metadata][:to_load].empty?
229
+ cached_asset[:metadata][:to_load] = cached_asset[:metadata][:to_load].dup
230
+ cached_asset[:metadata][:to_load].map! { |uri| compress_from_root(uri) }
231
+ end
232
+
233
+ if cached_asset[:metadata][:to_link] && !cached_asset[:metadata][:to_link].empty?
234
+ cached_asset[:metadata][:to_link] = cached_asset[:metadata][:to_link].dup
235
+ cached_asset[:metadata][:to_link].map! { |uri| compress_from_root(uri) }
236
+ end
237
+
227
238
  if cached_asset[:metadata][:dependencies] && !cached_asset[:metadata][:dependencies].empty?
228
239
  cached_asset[:metadata][:dependencies] = cached_asset[:metadata][:dependencies].dup
229
240
  cached_asset[:metadata][:dependencies].map! do |uri|
@@ -165,7 +165,12 @@ module Sprockets
165
165
  filenames = []
166
166
  concurrent_exporters = []
167
167
 
168
+ assets_to_export = Concurrent::Array.new
168
169
  find(*args) do |asset|
170
+ assets_to_export << asset
171
+ end
172
+
173
+ assets_to_export.each do |asset|
169
174
  mtime = Time.now.iso8601
170
175
  files[asset.digest_path] = {
171
176
  'logical_path' => asset.logical_path,
@@ -54,11 +54,11 @@ module Sprockets
54
54
  if fingerprint
55
55
  if_match = fingerprint
56
56
  elsif env['HTTP_IF_MATCH']
57
- if_match = env['HTTP_IF_MATCH'][/^"(\w+)"$/, 1]
57
+ if_match = env['HTTP_IF_MATCH'][/"(\w+)"$/, 1]
58
58
  end
59
59
 
60
60
  if env['HTTP_IF_NONE_MATCH']
61
- if_none_match = env['HTTP_IF_NONE_MATCH'][/^"(\w+)"$/, 1]
61
+ if_none_match = env['HTTP_IF_NONE_MATCH'][/"(\w+)"$/, 1]
62
62
  end
63
63
 
64
64
  # Look up the asset.
@@ -2,24 +2,32 @@
2
2
  require 'set'
3
3
 
4
4
  module Sprockets
5
- class SourceMapProcessor
6
- def self.original_content_type(source_map_content_type, error_when_not_found: true)
7
- case source_map_content_type
8
- when "application/js-sourcemap+json"
9
- "application/javascript"
10
- when "application/css-sourcemap+json"
11
- "text/css"
12
- else
13
- fail(source_map_content_type) if error_when_not_found
14
- source_map_content_type
15
- end
16
- end
17
5
 
6
+ # The purpose of this class is to generate a source map file
7
+ # that can be read and understood by browsers.
8
+ #
9
+ # When a file is passed in it will have a `application/js-sourcemap+json`
10
+ # or `application/css-sourcemap+json` mime type. The filename will be
11
+ # match the original asset. The original asset is loaded. As it
12
+ # gets processed by Sprockets it will aquire all information
13
+ # needed to build a source map file in the `asset.to_hash[:metadata][:map]`
14
+ # key.
15
+ #
16
+ # The output is an asset with a properly formatted source map file:
17
+ #
18
+ # {
19
+ # "version": 3,
20
+ # "sources": ["foo.js"],
21
+ # "names": [ ],
22
+ # "mappings": "AAAA,GAAIA"
23
+ # }
24
+ #
25
+ class SourceMapProcessor
18
26
  def self.call(input)
19
27
  links = Set.new(input[:metadata][:links])
20
28
  env = input[:environment]
21
29
 
22
- uri, _ = env.resolve!(input[:filename], accept: original_content_type(input[:content_type]))
30
+ uri, _ = env.resolve!(input[:filename], accept: self.original_content_type(input[:content_type]))
23
31
  asset = env.load(uri)
24
32
  map = asset.metadata[:map]
25
33
 
@@ -42,5 +50,17 @@ module Sprockets
42
50
 
43
51
  { data: json, links: links, dependencies: dependencies }
44
52
  end
53
+
54
+ def self.original_content_type(source_map_content_type, error_when_not_found: true)
55
+ case source_map_content_type
56
+ when "application/js-sourcemap+json"
57
+ "application/javascript"
58
+ when "application/css-sourcemap+json"
59
+ "text/css"
60
+ else
61
+ fail(source_map_content_type) if error_when_not_found
62
+ source_map_content_type
63
+ end
64
+ end
45
65
  end
46
66
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sprockets
3
- VERSION = "4.0.0.beta6"
3
+ VERSION = "4.0.0.beta7"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta6
4
+ version: 4.0.0.beta7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-11-15 00:00:00.000000000 Z
12
+ date: 2018-03-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -45,6 +45,20 @@ dependencies:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: m
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
48
62
  - !ruby/object:Gem::Dependency
49
63
  name: babel-transpiler
50
64
  requirement: !ruby/object:Gem::Requirement
@@ -304,6 +318,7 @@ files:
304
318
  - bin/sprockets
305
319
  - lib/rake/sprocketstask.rb
306
320
  - lib/sprockets.rb
321
+ - lib/sprockets/add_source_map_comment_to_asset_processor.rb
307
322
  - lib/sprockets/asset.rb
308
323
  - lib/sprockets/autoload.rb
309
324
  - lib/sprockets/autoload/babel.rb
@@ -370,7 +385,6 @@ files:
370
385
  - lib/sprockets/sassc_compressor.rb
371
386
  - lib/sprockets/sassc_processor.rb
372
387
  - lib/sprockets/server.rb
373
- - lib/sprockets/source_map_comment_processor.rb
374
388
  - lib/sprockets/source_map_processor.rb
375
389
  - lib/sprockets/source_map_utils.rb
376
390
  - lib/sprockets/transformers.rb
@@ -402,7 +416,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
402
416
  version: 1.3.1
403
417
  requirements: []
404
418
  rubyforge_project: sprockets
405
- rubygems_version: 2.6.14
419
+ rubygems_version: 2.7.6
406
420
  signing_key:
407
421
  specification_version: 4
408
422
  summary: Rack-based asset packaging system