sprockets 4.0.0.beta4 → 4.0.0.beta5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 52d1dd6743105d82450959d44e27538e02130e7e
4
- data.tar.gz: 02f58032703403898778cc33d6a56e0ca8bbee01
3
+ metadata.gz: 8fec40bbdd1b072ed9297eb8a8c4cace3ad4d406
4
+ data.tar.gz: 7e75410bb1fb7fce7577c5c7a270795735940d0b
5
5
  SHA512:
6
- metadata.gz: ac089336d45577a2647ba6b329c5a62862613674be5969f4312e0d7afbb0cf3a9a06cbc7d9db7dd55649fac74c234da54d4482f83d091c4d2357269502006d99
7
- data.tar.gz: 990363e0a8e9545ad6243279075cad733d7b403b45737b0c76b35d4647824e693c9f012c88b4220a431970d649dc7ad3582980311dc30c8e2b7b1871c1e5d611
6
+ metadata.gz: 41dc1ca9ad0acf4423861cc32353eb7e69f438fd01519ee2f0c5f6b543a4701b838132ebd1a55b3c2aedca5b2c2409b7221bc3199a7b094e9724c6165b9c7bbb
7
+ data.tar.gz: 2f9d9d7ca8cf7264eb99eb53b02f39d768f3f9472005d20a72655740c99eaf571977ddacd3ae07f8ada481e1390328e11cb2203bc415e29ecf496e93888d587a
@@ -4,6 +4,12 @@ Get upgrade notes from Sprockets 3.x to 4.x at https://github.com/rails/sprocket
4
4
 
5
5
  ## Master
6
6
 
7
+ ## 4.0.0.beta5
8
+
9
+ - Reduce string allocations
10
+ - Source map metadata uses compressed form specified by the [source map v3 spec](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k). [#402] **[BREAKING]**
11
+ - Generate [index maps](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt) when decoding source maps isn't necessary. [#402]
12
+ - Remove fingerprints from source map files. [#402]
7
13
 
8
14
  ## 4.0.0.beta4
9
15
 
data/README.md CHANGED
@@ -63,8 +63,8 @@ For example, if you have an `application.js` and want all the files in the `foo/
63
63
  Then create a file `foo/index.js` that requires all the files in that folder in any order you want:
64
64
 
65
65
  ```
66
- //= require foo.min.js
67
- //= require foo-ui.js
66
+ //= require ./foo.min.js
67
+ //= require ./foo-ui.js
68
68
  ```
69
69
 
70
70
  Now, your `application.js` will correctly load the `foo.min.js` before `foo-ui.js`. If you used `require_tree` it would not work correctly.
@@ -359,8 +359,8 @@ reference files relative to the location of the current file.
359
359
  #### The `require` Directive
360
360
 
361
361
  `require` *path* inserts the contents of the asset source file
362
- specified by *path*. If the file is required multiple times, it will
363
- appear in the bundle only once.
362
+ specified by *path*. If the same file is required multiple times
363
+ with different path expressions, it will appear in the bundle only once.
364
364
 
365
365
  #### The `require_directory` Directive
366
366
 
@@ -440,7 +440,7 @@ Similar to Rack, a processor is any "callable" (an object that responds to `call
440
440
 
441
441
  Also see [`Sprockets::ProcessorUtils`](https://github.com/rails/sprockets/blob/master/lib/sprockets/processor_utils.rb) for public helper methods.
442
442
 
443
- ### input Hash
443
+ ### Input Hash
444
444
 
445
445
  The `input` Hash defines the following public fields.
446
446
 
@@ -448,7 +448,6 @@ The `input` Hash defines the following public fields.
448
448
  * `:environment` - Current `Sprockets::Environment` instance.
449
449
  * `:cache` - A `Sprockets::Cache` instance. See [`Sprockets::Cache#fetch`](https://github.com/rails/sprockets/blob/master/lib/sprockets/cache.rb).
450
450
  * `:uri` - String Asset URI.
451
- * `:source_path` - String full path to original file.
452
451
  * `:load_path` - String current load path for filename.
453
452
  * `:name` - String logical path for filename.
454
453
  * `:content_type` - String content type of the output asset.
@@ -99,13 +99,7 @@ module Sprockets
99
99
  end
100
100
 
101
101
  register_pipeline :default do |env, type, file_type|
102
- # TODO: Hack for to inject source map transformer
103
- if (type == "application/js-sourcemap+json" && file_type != "application/js-sourcemap+json") ||
104
- (type == "application/css-sourcemap+json" && file_type != "application/css-sourcemap+json")
105
- [SourceMapProcessor]
106
- else
107
- env.default_processors_for(type, file_type)
108
- end
102
+ env.default_processors_for(type, file_type)
109
103
  end
110
104
 
111
105
  require 'sprockets/source_map_comment_processor'
@@ -129,7 +123,7 @@ module Sprockets
129
123
  register_bundle_metadata_reducer 'application/javascript', :data, proc { String.new("") }, Utils.method(:concat_javascript_sources)
130
124
  register_bundle_metadata_reducer '*/*', :links, :+
131
125
  register_bundle_metadata_reducer '*/*', :sources, proc { [] }, :+
132
- register_bundle_metadata_reducer '*/*', :map, SourceMapUtils.method(:concat_source_maps)
126
+ register_bundle_metadata_reducer '*/*', :map, proc { |input| { "version" => 3, "file" => PathUtils.split_subpath(input[:load_path], input[:filename]), "sections" => [] } }, SourceMapUtils.method(:concat_source_maps)
133
127
 
134
128
  require 'sprockets/closure_compressor'
135
129
  require 'sprockets/sass_compressor'
@@ -42,11 +42,11 @@ module Sprockets
42
42
 
43
43
  result = input[:cache].fetch(@cache_key + [input[:filename]] + [data]) do
44
44
  opts = {
45
- 'sourceRoot' => input[:load_path],
46
45
  'moduleRoot' => nil,
47
46
  'filename' => input[:filename],
48
47
  'filenameRelative' => PathUtils.split_subpath(input[:load_path], input[:filename]),
49
- 'sourceFileName' => input[:source_path]
48
+ 'sourceFileName' => File.basename(input[:filename]),
49
+ 'sourceMapTarget' => input[:filename]
50
50
  }.merge(@options)
51
51
 
52
52
  if opts['moduleIds'] && opts['moduleRoot']
@@ -57,8 +57,8 @@ module Sprockets
57
57
  Autoload::Babel::Transpiler.transform(data, opts)
58
58
  end
59
59
 
60
- map = SourceMapUtils.decode_json_source_map(JSON.generate(result['map']))
61
- map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map["mappings"])
60
+ map = SourceMapUtils.format_source_map(result["map"], input)
61
+ map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
62
62
 
63
63
  { data: result['code'], map: map }
64
64
  end
@@ -6,6 +6,7 @@ require 'sprockets/configuration'
6
6
  require 'sprockets/digest_utils'
7
7
  require 'sprockets/errors'
8
8
  require 'sprockets/loader'
9
+ require 'sprockets/npm'
9
10
  require 'sprockets/path_dependency_utils'
10
11
  require 'sprockets/path_digest_utils'
11
12
  require 'sprockets/path_utils'
@@ -22,6 +23,7 @@ module Sprockets
22
23
  include Server
23
24
  include Resolve, Loader
24
25
  include Bower
26
+ include Npm
25
27
 
26
28
  # Get persistent cache store
27
29
  attr_reader :cache
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'set'
3
3
  require 'sprockets/utils'
4
+ require 'sprockets/uri_utils'
4
5
 
5
6
  module Sprockets
6
7
  # Internal: Bundle processor takes a single file asset and prepends all the
@@ -16,15 +17,32 @@ module Sprockets
16
17
  def self.call(input)
17
18
  env = input[:environment]
18
19
  type = input[:content_type]
20
+ input[:links] ||= Set.new
19
21
  dependencies = Set.new(input[:metadata][:dependencies])
20
22
 
21
23
  processed_uri, deps = env.resolve(input[:filename], accept: type, pipeline: :self)
22
24
  dependencies.merge(deps)
23
25
 
26
+ # DirectiveProcessor (and any other transformers called here with pipeline=self)
27
+ primary_asset = env.load(processed_uri)
28
+ to_load = primary_asset.metadata.delete(:to_load) || Set.new
29
+ to_link = primary_asset.metadata.delete(:to_link) || Set.new
30
+
31
+ to_load.each do |uri|
32
+ loaded_asset = env.load(uri)
33
+ dependencies.merge(loaded_asset.metadata[:dependencies])
34
+ if to_link.include?(uri)
35
+ primary_metadata = primary_asset.metadata
36
+ input[:links] << loaded_asset.uri
37
+ primary_metadata[:links] << loaded_asset.uri
38
+ end
39
+ end
40
+
24
41
  find_required = proc { |uri| env.load(uri).metadata[:required] }
25
42
  required = Utils.dfs(processed_uri, &find_required)
26
43
  stubbed = Utils.dfs(env.load(processed_uri).metadata[:stubbed], &find_required)
27
44
  required.subtract(stubbed)
45
+ dedup(required)
28
46
  assets = required.map { |uri| env.load(uri) }
29
47
 
30
48
  (required + stubbed).each do |uri|
@@ -32,21 +50,38 @@ module Sprockets
32
50
  end
33
51
 
34
52
  reducers = Hash[env.match_mime_type_keys(env.config[:bundle_reducers], type).flat_map(&:to_a)]
35
- process_bundle_reducers(assets, reducers).merge(dependencies: dependencies, included: assets.map(&:uri))
53
+ process_bundle_reducers(input, assets, reducers).merge(dependencies: dependencies, included: assets.map(&:uri))
54
+ end
55
+
56
+ # Internal: Removes uri from required if it's already included as an alias.
57
+ #
58
+ # required - Set of required uris
59
+ #
60
+ # Returns deduped set of uris
61
+ def self.dedup(required)
62
+ dupes = required.reduce([]) do |r, uri|
63
+ path, params = URIUtils.parse_asset_uri(uri)
64
+ if (params.delete(:index_alias))
65
+ r << URIUtils.build_asset_uri(path, params)
66
+ end
67
+ r
68
+ end
69
+ required.subtract(dupes)
36
70
  end
37
71
 
38
72
  # Internal: Run bundle reducers on set of Assets producing a reduced
39
73
  # metadata Hash.
40
74
  #
75
+ # filename - String bundle filename
41
76
  # assets - Array of Assets
42
77
  # reducers - Array of [initial, reducer_proc] pairs
43
78
  #
44
79
  # Returns reduced asset metadata Hash.
45
- def self.process_bundle_reducers(assets, reducers)
80
+ def self.process_bundle_reducers(input, assets, reducers)
46
81
  initial = {}
47
82
  reducers.each do |k, (v, _)|
48
83
  if v.respond_to?(:call)
49
- initial[k] = v.call
84
+ initial[k] = v.call(input)
50
85
  elsif !v.nil?
51
86
  initial[k] = v
52
87
  end
@@ -36,6 +36,12 @@ module Sprockets
36
36
  #
37
37
  # Returns argument value.
38
38
  #
39
+ # clear(options)
40
+ #
41
+ # Clear the entire cache. Be careful with this method since it could
42
+ # affect other processes if shared cache is being used.
43
+ #
44
+ # The options hash is passed to the underlying cache implementation.
39
45
  class Cache
40
46
  # Builtin cache stores.
41
47
  autoload :FileStore, 'sprockets/cache/file_store'
@@ -144,6 +150,14 @@ module Sprockets
144
150
  "#<#{self.class} local=#{@fetch_cache.inspect} store=#{@cache_wrapper.cache.inspect}>"
145
151
  end
146
152
 
153
+ # Public: Clear cache
154
+ #
155
+ # Returns truthy on success, potentially raises exception on failure
156
+ def clear(options=nil)
157
+ @cache_wrapper.clear
158
+ @fetch_cache.clear
159
+ end
160
+
147
161
  private
148
162
  # Internal: Expand object cache key into a short String key.
149
163
  #
@@ -212,6 +226,16 @@ module Sprockets
212
226
  def set(key, value)
213
227
  cache.set(key, value)
214
228
  end
229
+
230
+ def clear(options=nil)
231
+ # dalli has a #flush method so try it
232
+ if cache.respond_to?(:flush)
233
+ cache.flush(options)
234
+ else
235
+ cache.clear(options)
236
+ end
237
+ true
238
+ end
215
239
  end
216
240
 
217
241
  class HashWrapper < Wrapper
@@ -222,6 +246,11 @@ module Sprockets
222
246
  def set(key, value)
223
247
  cache[key] = value
224
248
  end
249
+
250
+ def clear(options=nil)
251
+ cache.clear
252
+ true
253
+ end
225
254
  end
226
255
 
227
256
  class ReadWriteWrapper < Wrapper
@@ -232,6 +261,11 @@ module Sprockets
232
261
  def set(key, value)
233
262
  cache.write(key, value)
234
263
  end
264
+
265
+ def clear(options=nil)
266
+ cache.clear(options)
267
+ true
268
+ end
235
269
  end
236
270
  end
237
271
  end
@@ -20,7 +20,8 @@ module Sprockets
20
20
  class FileStore
21
21
  # Internal: Default key limit for store.
22
22
  DEFAULT_MAX_SIZE = 25 * 1024 * 1024
23
-
23
+ EXCLUDED_DIRS = ['.', '..'].freeze
24
+ GITKEEP_FILES = ['.gitkeep', '.keep'].freeze
24
25
  # Internal: Default standard error fatal logger.
25
26
  #
26
27
  # Returns a Logger.
@@ -123,6 +124,21 @@ module Sprockets
123
124
  "#<#{self.class} size=#{size}/#{@max_size}>"
124
125
  end
125
126
 
127
+ # Public: Clear the cache
128
+ #
129
+ # adapted from ActiveSupport::Cache::FileStore#clear
130
+ #
131
+ # Deletes all items from the cache. In this case it deletes all the entries in the specified
132
+ # file store directory except for .keep or .gitkeep. Be careful which directory is specified
133
+ # as @root because everything in that directory will be deleted.
134
+ #
135
+ # Returns true
136
+ def clear(options=nil)
137
+ root_dirs = Dir.entries(@root).reject { |f| (EXCLUDED_DIRS + GITKEEP_FILES).include?(f) }
138
+ FileUtils.rm_r(root_dirs.collect{ |f| File.join(@root, f) })
139
+ true
140
+ end
141
+
126
142
  private
127
143
  # Internal: Get all cache files along with stats.
128
144
  #
@@ -62,6 +62,14 @@ module Sprockets
62
62
  def inspect
63
63
  "#<#{self.class} size=#{@cache.size}/#{@max_size}>"
64
64
  end
65
+
66
+ # Public: Clear the cache
67
+ #
68
+ # Returns true
69
+ def clear(options=nil)
70
+ @cache.clear
71
+ true
72
+ end
65
73
  end
66
74
  end
67
75
  end
@@ -42,6 +42,13 @@ module Sprockets
42
42
  def inspect
43
43
  "#<#{self.class}>"
44
44
  end
45
+
46
+ # Public: Simulate clearing the cache
47
+ #
48
+ # Returns true
49
+ def clear(options=nil)
50
+ true
51
+ end
45
52
  end
46
53
  end
47
54
  end
@@ -16,12 +16,11 @@ module Sprockets
16
16
  initialize_configuration(environment)
17
17
 
18
18
  @cache = environment.cache
19
- @stats = Hash.new { |h, k| h[k] = _stat(k) }
20
- @entries = Hash.new { |h, k| h[k] = _entries(k) }
21
- @uris = Hash.new { |h, k| h[k] = _load(k) }
22
-
23
- @processor_cache_keys = Hash.new { |h, k| h[k] = _processor_cache_key(k) }
24
- @resolved_dependencies = Hash.new { |h, k| h[k] = _resolve_dependency(k) }
19
+ @stats = {}
20
+ @entries = {}
21
+ @uris = {}
22
+ @processor_cache_keys = {}
23
+ @resolved_dependencies = {}
25
24
  end
26
25
 
27
26
  # No-op return self as cached environment.
@@ -31,33 +30,28 @@ module Sprockets
31
30
  alias_method :index, :cached
32
31
 
33
32
  # Internal: Cache Environment#entries
34
- alias_method :_entries, :entries
35
33
  def entries(path)
36
- @entries[path]
34
+ @entries[path] ||= super(path)
37
35
  end
38
36
 
39
37
  # Internal: Cache Environment#stat
40
- alias_method :_stat, :stat
41
38
  def stat(path)
42
- @stats[path]
39
+ @stats[path] ||= super(path)
43
40
  end
44
41
 
45
42
  # Internal: Cache Environment#load
46
- alias_method :_load, :load
47
43
  def load(uri)
48
- @uris[uri]
44
+ @uris[uri] ||= super(uri)
49
45
  end
50
46
 
51
47
  # Internal: Cache Environment#processor_cache_key
52
- alias_method :_processor_cache_key, :processor_cache_key
53
48
  def processor_cache_key(str)
54
- @processor_cache_keys[str]
49
+ @processor_cache_keys[str] ||= super(str)
55
50
  end
56
51
 
57
52
  # Internal: Cache Environment#resolve_dependency
58
- alias_method :_resolve_dependency, :resolve_dependency
59
53
  def resolve_dependency(str)
60
- @resolved_dependencies[str]
54
+ @resolved_dependencies[str] ||= super(str)
61
55
  end
62
56
 
63
57
  private
@@ -21,11 +21,18 @@ module Sprockets
21
21
  data = input[:data]
22
22
 
23
23
  js, map = input[:cache].fetch([self.cache_key, data]) do
24
- result = Autoload::CoffeeScript.compile(data, sourceMap: true, sourceFiles: [input[:source_path]])
25
- [result['js'], SourceMapUtils.decode_json_source_map(result['v3SourceMap'])['mappings']]
24
+ result = Autoload::CoffeeScript.compile(
25
+ data,
26
+ sourceMap: "v3",
27
+ sourceFiles: [File.basename(input[:filename])],
28
+ generatedFile: input[:filename]
29
+ )
30
+ [result['js'], JSON.parse(result['v3SourceMap'])]
26
31
  end
27
32
 
33
+ map = SourceMapUtils.format_source_map(map, input)
28
34
  map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
35
+
29
36
  { data: js, map: map }
30
37
  end
31
38
  end
@@ -80,6 +80,9 @@ module Sprockets
80
80
  digest << val.to_s
81
81
  }
82
82
  end
83
+
84
+ ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
85
+
83
86
  ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
84
87
  raise TypeError, "couldn't digest #{ val }"
85
88
  }
@@ -70,20 +70,28 @@ module Sprockets
70
70
  @uri = input[:uri]
71
71
  @filename = input[:filename]
72
72
  @dirname = File.dirname(@filename)
73
- @content_type = input[:content_type]
73
+ # If loading a source map file like `application.js.map` resolve
74
+ # dependencies using `.js` instead of `.js.map`
75
+ @content_type = SourceMapProcessor.original_content_type(input[:content_type], error_when_not_found: false)
74
76
  @required = Set.new(input[:metadata][:required])
75
77
  @stubbed = Set.new(input[:metadata][:stubbed])
76
78
  @links = Set.new(input[:metadata][:links])
77
79
  @dependencies = Set.new(input[:metadata][:dependencies])
80
+ @to_link = Set.new
81
+ @to_load = Set.new
78
82
 
79
83
  data, directives = process_source(input[:data])
80
84
  process_directives(directives)
81
85
 
82
- { data: data,
83
- required: @required,
84
- stubbed: @stubbed,
85
- links: @links,
86
- dependencies: @dependencies }
86
+ {
87
+ data: data,
88
+ required: @required,
89
+ stubbed: @stubbed,
90
+ links: @links,
91
+ to_load: @to_load,
92
+ to_link: @to_link,
93
+ dependencies: @dependencies
94
+ }
87
95
  end
88
96
 
89
97
  protected
@@ -274,7 +282,7 @@ module Sprockets
274
282
  # //= depend_on_asset "bar.js"
275
283
  #
276
284
  def process_depend_on_asset_directive(path)
277
- load(resolve(path))
285
+ to_load(resolve(path))
278
286
  end
279
287
 
280
288
  # Allows dependency to be excluded from the asset bundle.
@@ -298,7 +306,8 @@ module Sprockets
298
306
  # /*= link "logo.png" */
299
307
  #
300
308
  def process_link_directive(path)
301
- @links << load(resolve(path)).uri
309
+ uri = to_load(resolve(path))
310
+ @to_link << uri
302
311
  end
303
312
 
304
313
  # `link_directory` links all the files inside a single
@@ -355,7 +364,7 @@ module Sprockets
355
364
 
356
365
  def link_paths(paths, deps, accept)
357
366
  resolve_paths(paths, deps, accept: accept) do |uri|
358
- @links << load(uri).uri
367
+ @to_link << to_load(uri)
359
368
  end
360
369
  end
361
370
 
@@ -385,10 +394,9 @@ module Sprockets
385
394
  end
386
395
  end
387
396
 
388
- def load(uri)
389
- asset = @environment.load(uri)
390
- @dependencies.merge(asset.metadata[:dependencies])
391
- asset
397
+ def to_load(uri)
398
+ @to_load << uri
399
+ uri
392
400
  end
393
401
 
394
402
  def resolve(path, **kargs)