sprockets 4.0.0.beta4 → 4.0.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +5 -6
- data/lib/sprockets.rb +2 -8
- data/lib/sprockets/babel_processor.rb +4 -4
- data/lib/sprockets/base.rb +2 -0
- data/lib/sprockets/bundle.rb +38 -3
- data/lib/sprockets/cache.rb +34 -0
- data/lib/sprockets/cache/file_store.rb +17 -1
- data/lib/sprockets/cache/memory_store.rb +8 -0
- data/lib/sprockets/cache/null_store.rb +7 -0
- data/lib/sprockets/cached_environment.rb +10 -16
- data/lib/sprockets/coffee_script_processor.rb +9 -2
- data/lib/sprockets/digest_utils.rb +3 -0
- data/lib/sprockets/directive_processor.rb +21 -13
- data/lib/sprockets/loader.rb +1 -7
- data/lib/sprockets/manifest.rb +13 -9
- data/lib/sprockets/manifest_utils.rb +0 -1
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_utils.rb +25 -1
- data/lib/sprockets/preprocessors/default_source_map.rb +27 -7
- data/lib/sprockets/sass_compressor.rb +3 -5
- data/lib/sprockets/sass_processor.rb +2 -18
- data/lib/sprockets/sassc_compressor.rb +11 -10
- data/lib/sprockets/sassc_processor.rb +10 -17
- data/lib/sprockets/server.rb +1 -1
- data/lib/sprockets/source_map_comment_processor.rb +6 -1
- data/lib/sprockets/source_map_processor.rb +16 -18
- data/lib/sprockets/source_map_utils.rb +197 -70
- data/lib/sprockets/uglifier_compressor.rb +14 -8
- data/lib/sprockets/version.rb +1 -1
- metadata +7 -6
data/lib/sprockets/loader.rb
CHANGED
@@ -140,10 +140,6 @@ module Sprockets
|
|
140
140
|
|
141
141
|
# Read into memory and process if theres a processor pipeline
|
142
142
|
if processors.any?
|
143
|
-
source_uri, _ = resolve!(unloaded.filename, pipeline: :source)
|
144
|
-
source_asset = load(source_uri)
|
145
|
-
|
146
|
-
source_path = source_asset.digest_path
|
147
143
|
|
148
144
|
result = call_processors(processors, {
|
149
145
|
environment: self,
|
@@ -151,12 +147,10 @@ module Sprockets
|
|
151
147
|
uri: unloaded.uri,
|
152
148
|
filename: unloaded.filename,
|
153
149
|
load_path: load_path,
|
154
|
-
source_path: source_path,
|
155
150
|
name: name,
|
156
151
|
content_type: type,
|
157
152
|
metadata: {
|
158
|
-
dependencies: dependencies
|
159
|
-
map: []
|
153
|
+
dependencies: dependencies
|
160
154
|
}
|
161
155
|
})
|
162
156
|
validate_processor_result!(result)
|
data/lib/sprockets/manifest.rb
CHANGED
@@ -120,11 +120,14 @@ module Sprockets
|
|
120
120
|
return to_enum(__method__, *args) unless block_given?
|
121
121
|
|
122
122
|
environment = self.environment.cached
|
123
|
-
args.flatten.
|
124
|
-
|
125
|
-
|
123
|
+
promises = args.flatten.map do |path|
|
124
|
+
Concurrent::Promise.execute(executor: executor) do
|
125
|
+
environment.find_all_linked_assets(path) do |asset|
|
126
|
+
yield asset
|
127
|
+
end
|
126
128
|
end
|
127
129
|
end
|
130
|
+
promises.each(&:wait!)
|
128
131
|
|
129
132
|
nil
|
130
133
|
end
|
@@ -160,7 +163,6 @@ module Sprockets
|
|
160
163
|
|
161
164
|
filenames = []
|
162
165
|
concurrent_exporters = []
|
163
|
-
executor = Concurrent::FixedThreadPool.new(Concurrent.processor_count)
|
164
166
|
|
165
167
|
find(*args) do |asset|
|
166
168
|
mtime = Time.now.iso8601
|
@@ -183,11 +185,6 @@ module Sprockets
|
|
183
185
|
exporters_for_asset(asset) do |exporter|
|
184
186
|
next if exporter.skip?(logger)
|
185
187
|
|
186
|
-
if !environment.export_concurrent
|
187
|
-
exporter.call
|
188
|
-
next
|
189
|
-
end
|
190
|
-
|
191
188
|
if promise.nil?
|
192
189
|
promise = Concurrent::Promise.new(executor: executor) { exporter.call }
|
193
190
|
concurrent_exporters << promise.execute
|
@@ -265,6 +262,8 @@ module Sprockets
|
|
265
262
|
def clobber
|
266
263
|
FileUtils.rm_r(directory) if File.exist?(directory)
|
267
264
|
logger.info "Removed #{directory}"
|
265
|
+
# if we have an environment clear the cache too
|
266
|
+
environment.cache.clear if environment
|
268
267
|
nil
|
269
268
|
end
|
270
269
|
|
@@ -294,6 +293,7 @@ module Sprockets
|
|
294
293
|
exporters = [Exporters::FileExporter]
|
295
294
|
|
296
295
|
environment.exporters.each do |mime_type, exporter_list|
|
296
|
+
next unless asset.content_type
|
297
297
|
next unless environment.match_mime_type? asset.content_type, mime_type
|
298
298
|
exporter_list.each do |exporter|
|
299
299
|
exporters << exporter
|
@@ -324,5 +324,9 @@ module Sprockets
|
|
324
324
|
logger
|
325
325
|
end
|
326
326
|
end
|
327
|
+
|
328
|
+
def executor
|
329
|
+
@executor ||= environment.export_concurrent ? :fast : :immediate
|
330
|
+
end
|
327
331
|
end
|
328
332
|
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 candiate 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
|
data/lib/sprockets/path_utils.rb
CHANGED
@@ -81,7 +81,7 @@ module Sprockets
|
|
81
81
|
end
|
82
82
|
else
|
83
83
|
def absolute_path?(path)
|
84
|
-
path
|
84
|
+
path.start_with?(File::SEPARATOR)
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
@@ -128,6 +128,30 @@ module Sprockets
|
|
128
128
|
(Pathname.new(base) + path).to_s
|
129
129
|
end
|
130
130
|
|
131
|
+
# Public: Sets pipeline for path
|
132
|
+
#
|
133
|
+
# path - String path
|
134
|
+
# extensions - List of file extensions
|
135
|
+
# pipeline - Pipeline
|
136
|
+
#
|
137
|
+
# Examples
|
138
|
+
#
|
139
|
+
# set_pipeline('path/file.js.erb', config[:mime_exts], config[:pipeline_exts], :source)
|
140
|
+
# # => 'path/file.source.js.erb'
|
141
|
+
#
|
142
|
+
# set_pipeline('path/some.file.source.js.erb', config[:mime_exts], config[:pipeline_exts], :debug)
|
143
|
+
# # => 'path/some.file.debug.js.erb'
|
144
|
+
#
|
145
|
+
# Returns string path with pipeline parsed in
|
146
|
+
def set_pipeline(path, mime_exts, pipeline_exts, pipeline)
|
147
|
+
extension, _ = match_path_extname(path, mime_exts)
|
148
|
+
path.chomp!(extension)
|
149
|
+
pipeline_old, _ = match_path_extname(path, pipeline_exts)
|
150
|
+
path.chomp!(pipeline_old)
|
151
|
+
|
152
|
+
"#{path}.#{pipeline}#{extension}"
|
153
|
+
end
|
154
|
+
|
131
155
|
# Internal: Get relative path for root path and subpath.
|
132
156
|
#
|
133
157
|
# path - String path
|
@@ -9,17 +9,37 @@ module Sprockets
|
|
9
9
|
# available.
|
10
10
|
class DefaultSourceMap
|
11
11
|
def call(input)
|
12
|
-
result
|
13
|
-
map
|
12
|
+
result = { data: input[:data] }
|
13
|
+
map = input[:metadata][:map]
|
14
|
+
filename = input[:filename]
|
15
|
+
load_path = input[:load_path]
|
16
|
+
lines = input[:data].lines.count
|
17
|
+
basename = File.basename(filename)
|
18
|
+
mime_exts = input[:environment].config[:mime_exts]
|
19
|
+
pipeline_exts = input[:environment].config[:pipeline_exts]
|
14
20
|
if map.nil? || map.empty?
|
15
|
-
result[:map]
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
result[:map] = {
|
22
|
+
"version" => 3,
|
23
|
+
"file" => PathUtils.split_subpath(load_path, filename),
|
24
|
+
"mappings" => default_mappings(lines),
|
25
|
+
"sources" => [PathUtils.set_pipeline(basename, mime_exts, pipeline_exts, :source)],
|
26
|
+
"names" => []
|
27
|
+
}
|
20
28
|
end
|
21
29
|
return result
|
22
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def default_mappings(lines)
|
35
|
+
if (lines == 0)
|
36
|
+
""
|
37
|
+
elsif (lines == 1)
|
38
|
+
"AAAA"
|
39
|
+
else
|
40
|
+
"AAAA;" + "AACA;"*(lines - 2) + "AACA"
|
41
|
+
end
|
42
|
+
end
|
23
43
|
end
|
24
44
|
end
|
25
45
|
end
|
@@ -49,15 +49,13 @@ module Sprockets
|
|
49
49
|
def call(input)
|
50
50
|
css, map = Autoload::Sass::Engine.new(
|
51
51
|
input[:data],
|
52
|
-
@options.merge(filename:
|
52
|
+
@options.merge(filename: input[:filename])
|
53
53
|
).render_with_sourcemap('')
|
54
54
|
|
55
55
|
css = css.sub("/*# sourceMappingURL= */\n", '')
|
56
56
|
|
57
|
-
map = SourceMapUtils.
|
58
|
-
|
59
|
-
SourceMapUtils.decode_json_source_map(map.to_json(css_uri: 'uri'))["mappings"]
|
60
|
-
)
|
57
|
+
map = SourceMapUtils.format_source_map(JSON.parse(map.to_json(css_uri: '')), input)
|
58
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
61
59
|
|
62
60
|
{ data: css, map: map }
|
63
61
|
end
|
@@ -80,13 +80,8 @@ module Sprockets
|
|
80
80
|
|
81
81
|
css = css.sub("\n/*# sourceMappingURL= */\n", '')
|
82
82
|
|
83
|
-
map = SourceMapUtils.
|
84
|
-
|
85
|
-
expand_map_sources(
|
86
|
-
SourceMapUtils.decode_json_source_map(map.to_json(css_uri: '', type: :inline))["mappings"],
|
87
|
-
input[:environment]
|
88
|
-
)
|
89
|
-
)
|
83
|
+
map = SourceMapUtils.format_source_map(JSON.parse(map.to_json(css_uri: '')), input)
|
84
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
90
85
|
|
91
86
|
# Track all imported files
|
92
87
|
sass_dependencies = Set.new([input[:filename]])
|
@@ -100,17 +95,6 @@ module Sprockets
|
|
100
95
|
|
101
96
|
private
|
102
97
|
|
103
|
-
def expand_source(source, env)
|
104
|
-
uri, _ = env.resolve!(source, pipeline: :source)
|
105
|
-
env.load(uri).digest_path
|
106
|
-
end
|
107
|
-
|
108
|
-
def expand_map_sources(mapping, env)
|
109
|
-
mapping.each do |map|
|
110
|
-
map[:source] = expand_source(map[:source], env)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
98
|
# Public: Build the cache store to be used by the Sass engine.
|
115
99
|
#
|
116
100
|
# input - the input hash.
|
@@ -9,23 +9,24 @@ module Sprockets
|
|
9
9
|
@options = {
|
10
10
|
syntax: :scss,
|
11
11
|
style: :compressed,
|
12
|
-
|
13
|
-
|
12
|
+
source_map_contents: false,
|
13
|
+
omit_source_map_url: true,
|
14
14
|
}.merge(options).freeze
|
15
15
|
end
|
16
16
|
|
17
17
|
def call(input)
|
18
18
|
# SassC requires the template to be modifiable
|
19
19
|
input_data = input[:data].frozen? ? input[:data].dup : input[:data]
|
20
|
-
|
20
|
+
engine = Autoload::SassC::Engine.new(input_data, @options.merge(filename: input[:filename], source_map_file: "#{input[:filename]}.map"))
|
21
|
+
|
22
|
+
css = engine.render.sub(/^\n^\/\*# sourceMappingURL=.*\*\/$/m, '')
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
input[:metadata][:map]
|
27
|
-
|
28
|
-
)
|
24
|
+
begin
|
25
|
+
map = SourceMapUtils.format_source_map(JSON.parse(engine.source_map), input)
|
26
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
27
|
+
rescue SassC::NotRenderedError
|
28
|
+
map = input[:metadata][:map]
|
29
|
+
end
|
29
30
|
|
30
31
|
{ data: css, map: map }
|
31
32
|
end
|
@@ -27,25 +27,18 @@ module Sprockets
|
|
27
27
|
engine.render.sub(/^\n^\/\*# sourceMappingURL=.*\*\/$/m, '')
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
map = map["mappings"].each do |m|
|
36
|
-
m[:source] = PathUtils.join(File.dirname(input[:filename]), m[:source])
|
37
|
-
end
|
38
|
-
|
39
|
-
map = SourceMapUtils.combine_source_maps(
|
40
|
-
input[:metadata][:map],
|
41
|
-
expand_map_sources(map, input[:environment])
|
42
|
-
)
|
30
|
+
begin
|
31
|
+
map = SourceMapUtils.format_source_map(JSON.parse(engine.source_map), input)
|
32
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
43
33
|
|
44
|
-
|
45
|
-
|
34
|
+
engine.dependencies.each do |dependency|
|
35
|
+
context.metadata[:dependencies] << URIUtils.build_file_digest_uri(dependency.filename)
|
36
|
+
end
|
37
|
+
rescue SassC::NotRenderedError
|
38
|
+
map = input[:metadata][:map]
|
46
39
|
end
|
47
40
|
|
48
|
-
context.metadata.merge(data: css, map: map
|
41
|
+
context.metadata.merge(data: css, map: map)
|
49
42
|
end
|
50
43
|
|
51
44
|
private
|
@@ -56,7 +49,7 @@ module Sprockets
|
|
56
49
|
syntax: self.class.syntax,
|
57
50
|
load_paths: input[:environment].paths,
|
58
51
|
importer: @importer_class,
|
59
|
-
source_map_contents:
|
52
|
+
source_map_contents: false,
|
60
53
|
source_map_file: "#{input[:filename]}.map",
|
61
54
|
omit_source_map_url: true,
|
62
55
|
sprockets: {
|
data/lib/sprockets/server.rb
CHANGED
@@ -241,7 +241,7 @@ module Sprockets
|
|
241
241
|
# If the request url contains a fingerprint, set a long
|
242
242
|
# expires on the response
|
243
243
|
if path_fingerprint(env["PATH_INFO"])
|
244
|
-
headers["Cache-Control"] << ", max-age=31536000"
|
244
|
+
headers["Cache-Control"] << ", max-age=31536000, immutable"
|
245
245
|
|
246
246
|
# Otherwise set `must-revalidate` since the asset could be modified.
|
247
247
|
else
|
@@ -1,4 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'sprockets/uri_utils'
|
3
|
+
require 'sprockets/path_utils'
|
4
|
+
|
2
5
|
module Sprockets
|
3
6
|
class SourceMapCommentProcessor
|
4
7
|
def self.call(input)
|
@@ -21,7 +24,9 @@ module Sprockets
|
|
21
24
|
uri, _ = env.resolve!(input[:filename], accept: map_type)
|
22
25
|
map = env.load(uri)
|
23
26
|
|
24
|
-
|
27
|
+
uri, params = URIUtils.parse_asset_uri(input[:uri])
|
28
|
+
uri = env.expand_from_root(params[:index_alias]) if params[:index_alias]
|
29
|
+
path = PathUtils.relative_path_from(PathUtils.split_subpath(input[:load_path], uri), map.digest_path)
|
25
30
|
|
26
31
|
asset.metadata.merge(
|
27
32
|
data: asset.source + (comment % path),
|
@@ -3,24 +3,25 @@ require 'set'
|
|
3
3
|
|
4
4
|
module Sprockets
|
5
5
|
class SourceMapProcessor
|
6
|
-
def self.
|
7
|
-
case
|
6
|
+
def self.original_content_type(source_map_content_type, error_when_not_found: true)
|
7
|
+
case source_map_content_type
|
8
8
|
when "application/js-sourcemap+json"
|
9
9
|
accept = "application/javascript"
|
10
10
|
when "application/css-sourcemap+json"
|
11
11
|
accept = "text/css"
|
12
12
|
else
|
13
|
-
fail
|
13
|
+
fail(source_map_content_type) if error_when_not_found
|
14
|
+
source_map_content_type
|
14
15
|
end
|
16
|
+
end
|
15
17
|
|
18
|
+
def self.call(input)
|
16
19
|
links = Set.new(input[:metadata][:links])
|
17
|
-
|
18
20
|
env = input[:environment]
|
19
21
|
|
20
|
-
uri, _
|
21
|
-
asset
|
22
|
-
map
|
23
|
-
sources = asset.metadata[:sources]
|
22
|
+
uri, _ = env.resolve!(input[:filename], accept: original_content_type(input[:content_type]))
|
23
|
+
asset = env.load(uri)
|
24
|
+
map = asset.metadata[:map]
|
24
25
|
|
25
26
|
# TODO: Because of the default piplene hack we have to apply dependencies
|
26
27
|
# from compiled asset to the source map, otherwise the source map cache
|
@@ -28,19 +29,16 @@ module Sprockets
|
|
28
29
|
dependencies = Set.new(input[:metadata][:dependencies])
|
29
30
|
dependencies.merge(asset.metadata[:dependencies])
|
30
31
|
|
31
|
-
map
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
path = source
|
38
|
-
end
|
39
|
-
uri, _ = env.resolve!(path)
|
32
|
+
map["file"] = PathUtils.split_subpath(input[:load_path], input[:filename])
|
33
|
+
sources = map["sections"] ? map["sections"].map { |s| s["map"]["sources"] }.flatten : map["sources"]
|
34
|
+
|
35
|
+
sources.each do |source|
|
36
|
+
source = PathUtils.join(File.dirname(map["file"]), source)
|
37
|
+
uri, _ = env.resolve!(source)
|
40
38
|
links << uri
|
41
39
|
end
|
42
40
|
|
43
|
-
json =
|
41
|
+
json = JSON.generate(map)
|
44
42
|
|
45
43
|
{ data: json, links: links, dependencies: dependencies }
|
46
44
|
end
|