sprockets 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +68 -0
- data/README.md +397 -408
- data/bin/sprockets +12 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +19 -23
- 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 +59 -11
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +44 -4
- data/lib/sprockets/cache/file_store.rb +32 -7
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cache.rb +42 -5
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +6 -11
- data/lib/sprockets/coffee_script_processor.rb +19 -5
- data/lib/sprockets/compressing.rb +62 -2
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +98 -23
- data/lib/sprockets/dependencies.rb +9 -8
- data/lib/sprockets/digest_utils.rb +104 -60
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +3 -2
- data/lib/sprockets/ejs_processor.rb +3 -2
- data/lib/sprockets/encoding_utils.rb +8 -4
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -1
- data/lib/sprockets/exporters/base.rb +72 -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 +26 -6
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +236 -69
- data/lib/sprockets/manifest.rb +97 -44
- 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 +106 -21
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -51
- data/lib/sprockets/processor_utils.rb +81 -15
- data/lib/sprockets/resolve.rb +182 -95
- data/lib/sprockets/sass_cache_store.rb +1 -0
- data/lib/sprockets/sass_compressor.rb +21 -17
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +45 -17
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +57 -34
- 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 +23 -20
- data/lib/sprockets/unloaded_asset.rb +139 -0
- data/lib/sprockets/uri_tar.rb +99 -0
- data/lib/sprockets/uri_utils.rb +15 -14
- data/lib/sprockets/utils/gzip.rb +99 -0
- data/lib/sprockets/utils.rb +43 -59
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +5 -14
- data/lib/sprockets.rb +103 -33
- metadata +151 -22
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -6
- data/lib/sprockets/eco_template.rb +0 -6
- data/lib/sprockets/ejs_template.rb +0 -6
- data/lib/sprockets/engines.rb +0 -81
- data/lib/sprockets/erb_template.rb +0 -6
- data/lib/sprockets/legacy.rb +0 -314
- 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 -7
data/bin/sprockets
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
$VERBOSE = nil
|
2
3
|
|
3
4
|
require 'sprockets'
|
4
5
|
require 'optparse'
|
@@ -11,7 +12,7 @@ unless ARGV.delete("--noenv")
|
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
+
paths = []
|
15
16
|
environment = Sprockets::Environment.new(Dir.pwd)
|
16
17
|
manifest = nil
|
17
18
|
|
@@ -51,6 +52,10 @@ OptionParser.new do |opts|
|
|
51
52
|
opts.on("--noenv", "Disables .sprocketsrc file") do
|
52
53
|
end
|
53
54
|
|
55
|
+
opts.on("--cache=DIRECTORY", "Enables the FileStore cache using the specified directory") do |directory|
|
56
|
+
environment.cache = Sprockets::Cache::FileStore.new(directory)
|
57
|
+
end
|
58
|
+
|
54
59
|
opts.on_tail("-h", "--help", "Shows this help message") do
|
55
60
|
opts.show_usage
|
56
61
|
end
|
@@ -63,8 +68,8 @@ OptionParser.new do |opts|
|
|
63
68
|
opts.show_usage if ARGV.empty?
|
64
69
|
|
65
70
|
begin
|
66
|
-
opts.order(ARGV) do |
|
67
|
-
|
71
|
+
opts.order(ARGV) do |path|
|
72
|
+
paths << path
|
68
73
|
end
|
69
74
|
rescue OptionParser::ParseError => e
|
70
75
|
opts.warn e.message
|
@@ -74,14 +79,14 @@ end
|
|
74
79
|
|
75
80
|
if environment.paths.empty?
|
76
81
|
warn "No load paths given"
|
77
|
-
warn "Usage: sprockets -Ijavascripts/
|
82
|
+
warn "Usage: sprockets -Ijavascripts/ path"
|
78
83
|
exit 1
|
79
84
|
end
|
80
85
|
|
81
86
|
if manifest
|
82
|
-
manifest.compile(
|
83
|
-
elsif
|
84
|
-
puts environment.find_asset(
|
87
|
+
manifest.compile(paths)
|
88
|
+
elsif paths.length == 1
|
89
|
+
puts environment.find_asset(paths.first).to_s
|
85
90
|
else
|
86
91
|
warn "Only one file can be compiled to stdout at a time"
|
87
92
|
exit 1
|
data/lib/rake/sprocketstask.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'rake'
|
2
3
|
require 'rake/tasklib'
|
3
4
|
|
@@ -124,7 +125,7 @@ module Rake
|
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
127
|
-
task :
|
128
|
+
task clobber: ["clobber_#{name}"]
|
128
129
|
|
129
130
|
desc name == :assets ? "Clean old assets" : "Clean old #{name} assets"
|
130
131
|
task "clean_#{name}" do
|
@@ -133,7 +134,7 @@ module Rake
|
|
133
134
|
end
|
134
135
|
end
|
135
136
|
|
136
|
-
task :
|
137
|
+
task clean: ["clean_#{name}"]
|
137
138
|
end
|
138
139
|
|
139
140
|
private
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'sprockets/uri_utils'
|
3
|
+
require 'sprockets/path_utils'
|
4
|
+
|
5
|
+
module Sprockets
|
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
|
29
|
+
def self.call(input)
|
30
|
+
|
31
|
+
case input[:content_type]
|
32
|
+
when "application/javascript"
|
33
|
+
comment = "\n//# sourceMappingURL=%s"
|
34
|
+
map_type = "application/js-sourcemap+json"
|
35
|
+
when "text/css"
|
36
|
+
comment = "\n/*# sourceMappingURL=%s */"
|
37
|
+
map_type = "application/css-sourcemap+json"
|
38
|
+
else
|
39
|
+
fail input[:content_type]
|
40
|
+
end
|
41
|
+
|
42
|
+
env = input[:environment]
|
43
|
+
|
44
|
+
uri, _ = env.resolve!(input[:filename], accept: input[:content_type])
|
45
|
+
asset = env.load(uri)
|
46
|
+
|
47
|
+
uri, _ = env.resolve!(input[:filename], accept: map_type)
|
48
|
+
map = env.load(uri)
|
49
|
+
|
50
|
+
uri, params = URIUtils.parse_asset_uri(input[:uri])
|
51
|
+
uri = env.expand_from_root(params[:index_alias]) if params[:index_alias]
|
52
|
+
path = PathUtils.relative_path_from(PathUtils.split_subpath(input[:load_path], uri), map.digest_path)
|
53
|
+
|
54
|
+
asset.metadata.merge(
|
55
|
+
data: asset.source + (comment % path) + "\n",
|
56
|
+
links: asset.links + [asset.uri, map.uri]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/sprockets/asset.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'fileutils'
|
2
3
|
require 'sprockets/digest_utils'
|
3
4
|
|
@@ -13,17 +14,14 @@ module Sprockets
|
|
13
14
|
# attributes - Hash of ivars
|
14
15
|
#
|
15
16
|
# Returns Asset.
|
16
|
-
def initialize(
|
17
|
-
@environment = environment
|
17
|
+
def initialize(attributes = {})
|
18
18
|
@attributes = attributes
|
19
19
|
@content_type = attributes[:content_type]
|
20
20
|
@filename = attributes[:filename]
|
21
21
|
@id = attributes[:id]
|
22
|
-
@integrity = attributes[:integrity]
|
23
22
|
@load_path = attributes[:load_path]
|
24
23
|
@logical_path = attributes[:logical_path]
|
25
24
|
@metadata = attributes[:metadata]
|
26
|
-
@mtime = attributes[:mtime]
|
27
25
|
@name = attributes[:name]
|
28
26
|
@source = attributes[:source]
|
29
27
|
@uri = attributes[:uri]
|
@@ -69,6 +67,13 @@ module Sprockets
|
|
69
67
|
logical_path.sub(/\.(\w+)$/) { |ext| "-#{etag}#{ext}" }
|
70
68
|
end
|
71
69
|
|
70
|
+
# Public: Return load path + logical path with digest spliced in.
|
71
|
+
#
|
72
|
+
# Returns String.
|
73
|
+
def full_digest_path
|
74
|
+
File.join(@load_path, digest_path)
|
75
|
+
end
|
76
|
+
|
72
77
|
# Public: Returns String MIME type of asset. Returns nil if type is unknown.
|
73
78
|
attr_reader :content_type
|
74
79
|
|
@@ -81,14 +86,6 @@ module Sprockets
|
|
81
86
|
metadata[:links] || Set.new
|
82
87
|
end
|
83
88
|
|
84
|
-
# Public: Get all internally required assets that were concated into this
|
85
|
-
# asset.
|
86
|
-
#
|
87
|
-
# Returns Array of String asset URIs.
|
88
|
-
def included
|
89
|
-
metadata[:included]
|
90
|
-
end
|
91
|
-
|
92
89
|
# Public: Return `String` of concatenated source.
|
93
90
|
#
|
94
91
|
# Returns String.
|
@@ -121,26 +118,28 @@ module Sprockets
|
|
121
118
|
end
|
122
119
|
alias_method :bytesize, :length
|
123
120
|
|
121
|
+
# Public: Returns String byte digest of source.
|
122
|
+
def digest
|
123
|
+
metadata[:digest]
|
124
|
+
end
|
125
|
+
|
124
126
|
# Public: Returns String hexdigest of source.
|
125
127
|
def hexdigest
|
126
|
-
DigestUtils.pack_hexdigest(
|
128
|
+
DigestUtils.pack_hexdigest(digest)
|
127
129
|
end
|
128
130
|
|
129
|
-
# Deprecated: Returns String hexdigest of source.
|
130
|
-
#
|
131
|
-
# In 4.x this will be changed to return a raw Digest byte String.
|
132
|
-
alias_method :digest, :hexdigest
|
133
|
-
|
134
131
|
# Pubic: ETag String of Asset.
|
135
132
|
alias_method :etag, :hexdigest
|
136
133
|
|
137
134
|
# Public: Returns String base64 digest of source.
|
138
135
|
def base64digest
|
139
|
-
DigestUtils.pack_base64digest(
|
136
|
+
DigestUtils.pack_base64digest(digest)
|
140
137
|
end
|
141
138
|
|
142
139
|
# Public: A "named information" URL for subresource integrity.
|
143
|
-
|
140
|
+
def integrity
|
141
|
+
DigestUtils.integrity_uri(metadata[:digest])
|
142
|
+
end
|
144
143
|
|
145
144
|
# Public: Add enumerator to allow `Asset` instances to be used as Rack
|
146
145
|
# compatible body objects.
|
@@ -165,9 +164,6 @@ module Sprockets
|
|
165
164
|
f.write source
|
166
165
|
end
|
167
166
|
|
168
|
-
# Set mtime correctly
|
169
|
-
File.utime(mtime, mtime, filename)
|
170
|
-
|
171
167
|
nil
|
172
168
|
end
|
173
169
|
|
data/lib/sprockets/autoload.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Sprockets
|
2
3
|
module Autoload
|
4
|
+
autoload :Babel, 'sprockets/autoload/babel'
|
3
5
|
autoload :Closure, 'sprockets/autoload/closure'
|
4
6
|
autoload :CoffeeScript, 'sprockets/autoload/coffee_script'
|
5
7
|
autoload :Eco, 'sprockets/autoload/eco'
|
6
8
|
autoload :EJS, 'sprockets/autoload/ejs'
|
9
|
+
autoload :JSMinC, 'sprockets/autoload/jsminc'
|
7
10
|
autoload :Sass, 'sprockets/autoload/sass'
|
11
|
+
autoload :SassC, 'sprockets/autoload/sassc'
|
8
12
|
autoload :Uglifier, 'sprockets/autoload/uglifier'
|
9
13
|
autoload :YUI, 'sprockets/autoload/yui'
|
14
|
+
autoload :Zopfli, 'sprockets/autoload/zopfli'
|
10
15
|
end
|
11
16
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'sprockets/autoload'
|
3
|
+
require 'sprockets/path_utils'
|
4
|
+
require 'sprockets/source_map_utils'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Sprockets
|
8
|
+
class BabelProcessor
|
9
|
+
VERSION = '1'
|
10
|
+
|
11
|
+
def self.instance
|
12
|
+
@instance ||= new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.call(input)
|
16
|
+
instance.call(input)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.cache_key
|
20
|
+
instance.cache_key
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :cache_key
|
24
|
+
|
25
|
+
def initialize(options = {})
|
26
|
+
@options = options.merge({
|
27
|
+
'blacklist' => (options['blacklist'] || []) + ['useStrict'],
|
28
|
+
'sourceMap' => true
|
29
|
+
}).freeze
|
30
|
+
|
31
|
+
@cache_key = [
|
32
|
+
self.class.name,
|
33
|
+
Autoload::Babel::Transpiler::VERSION,
|
34
|
+
Autoload::Babel::Source::VERSION,
|
35
|
+
VERSION,
|
36
|
+
@options
|
37
|
+
].freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def call(input)
|
41
|
+
data = input[:data]
|
42
|
+
|
43
|
+
result = input[:cache].fetch(@cache_key + [input[:filename]] + [data]) do
|
44
|
+
opts = {
|
45
|
+
'moduleRoot' => nil,
|
46
|
+
'filename' => input[:filename],
|
47
|
+
'filenameRelative' => PathUtils.split_subpath(input[:load_path], input[:filename]),
|
48
|
+
'sourceFileName' => File.basename(input[:filename]),
|
49
|
+
'sourceMapTarget' => input[:filename]
|
50
|
+
}.merge(@options)
|
51
|
+
|
52
|
+
if opts['moduleIds'] && opts['moduleRoot']
|
53
|
+
opts['moduleId'] ||= File.join(opts['moduleRoot'], input[:name])
|
54
|
+
elsif opts['moduleIds']
|
55
|
+
opts['moduleId'] ||= input[:name]
|
56
|
+
end
|
57
|
+
Autoload::Babel::Transpiler.transform(data, opts)
|
58
|
+
end
|
59
|
+
|
60
|
+
map = SourceMapUtils.format_source_map(result["map"], input)
|
61
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
62
|
+
|
63
|
+
{ data: result['code'], map: map }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/sprockets/base.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/asset'
|
2
3
|
require 'sprockets/bower'
|
3
4
|
require 'sprockets/cache'
|
@@ -5,20 +6,36 @@ require 'sprockets/configuration'
|
|
5
6
|
require 'sprockets/digest_utils'
|
6
7
|
require 'sprockets/errors'
|
7
8
|
require 'sprockets/loader'
|
8
|
-
require 'sprockets/
|
9
|
+
require 'sprockets/npm'
|
9
10
|
require 'sprockets/path_dependency_utils'
|
11
|
+
require 'sprockets/path_digest_utils'
|
10
12
|
require 'sprockets/path_utils'
|
11
13
|
require 'sprockets/resolve'
|
12
14
|
require 'sprockets/server'
|
15
|
+
require 'sprockets/source_map_utils'
|
16
|
+
require 'sprockets/uri_tar'
|
13
17
|
|
14
18
|
module Sprockets
|
15
|
-
|
19
|
+
|
20
|
+
class DoubleLinkError < Sprockets::Error
|
21
|
+
def initialize(parent_filename:, logical_path:, last_filename:, filename:)
|
22
|
+
super <<~MSG
|
23
|
+
Multiple files with the same output path cannot be linked (#{logical_path.inspect})
|
24
|
+
In #{parent_filename.inspect} these files were linked:
|
25
|
+
- #{last_filename}
|
26
|
+
- #{filename}
|
27
|
+
MSG
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# `Base` class for `Environment` and `CachedEnvironment`.
|
16
32
|
class Base
|
17
|
-
include PathUtils, PathDependencyUtils, PathDigestUtils, DigestUtils
|
33
|
+
include PathUtils, PathDependencyUtils, PathDigestUtils, DigestUtils, SourceMapUtils
|
18
34
|
include Configuration
|
19
35
|
include Server
|
20
36
|
include Resolve, Loader
|
21
37
|
include Bower
|
38
|
+
include Npm
|
22
39
|
|
23
40
|
# Get persistent cache store
|
24
41
|
attr_reader :cache
|
@@ -32,7 +49,7 @@ module Sprockets
|
|
32
49
|
@cache = Cache.new(cache, logger)
|
33
50
|
end
|
34
51
|
|
35
|
-
# Return an `
|
52
|
+
# Return an `CachedEnvironment`. Must be implemented by the subclass.
|
36
53
|
def cached
|
37
54
|
raise NotImplementedError
|
38
55
|
end
|
@@ -48,33 +65,46 @@ module Sprockets
|
|
48
65
|
# Caveat: Digests are cached by the path's current mtime. Its possible
|
49
66
|
# for a files contents to have changed and its mtime to have been
|
50
67
|
# negligently reset thus appearing as if the file hasn't changed on
|
51
|
-
# disk. Also, the mtime is only read to the nearest second.
|
68
|
+
# disk. Also, the mtime is only read to the nearest second. It's
|
52
69
|
# also possible the file was updated more than once in a given second.
|
53
|
-
|
70
|
+
key = UnloadedAsset.new(path, self).file_digest_key(stat.mtime.to_i)
|
71
|
+
cache.fetch(key) do
|
54
72
|
self.stat_digest(path, stat)
|
55
73
|
end
|
56
74
|
end
|
57
75
|
end
|
58
76
|
|
59
77
|
# Find asset by logical path or expanded path.
|
60
|
-
def find_asset(
|
61
|
-
uri, _ = resolve(
|
78
|
+
def find_asset(*args, **options)
|
79
|
+
uri, _ = resolve(*args, **options)
|
62
80
|
if uri
|
63
81
|
load(uri)
|
64
82
|
end
|
65
83
|
end
|
66
84
|
|
67
|
-
def find_all_linked_assets(
|
68
|
-
return to_enum(__method__,
|
85
|
+
def find_all_linked_assets(*args)
|
86
|
+
return to_enum(__method__, *args) unless block_given?
|
69
87
|
|
70
|
-
asset = find_asset(
|
88
|
+
parent_asset = asset = find_asset(*args)
|
71
89
|
return unless asset
|
72
90
|
|
73
91
|
yield asset
|
74
92
|
stack = asset.links.to_a
|
93
|
+
linked_paths = {}
|
75
94
|
|
76
95
|
while uri = stack.shift
|
77
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
|
78
108
|
stack = asset.links.to_a + stack
|
79
109
|
end
|
80
110
|
|
@@ -89,11 +119,29 @@ module Sprockets
|
|
89
119
|
find_asset(*args)
|
90
120
|
end
|
91
121
|
|
122
|
+
# Find asset by logical path or expanded path.
|
123
|
+
#
|
124
|
+
# If the asset is not found an error will be raised.
|
125
|
+
def find_asset!(*args)
|
126
|
+
uri, _ = resolve!(*args)
|
127
|
+
if uri
|
128
|
+
load(uri)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
92
132
|
# Pretty inspect
|
93
133
|
def inspect
|
94
134
|
"#<#{self.class}:0x#{object_id.to_s(16)} " +
|
95
135
|
"root=#{root.to_s.inspect}, " +
|
96
136
|
"paths=#{paths.inspect}>"
|
97
137
|
end
|
138
|
+
|
139
|
+
def compress_from_root(uri)
|
140
|
+
URITar.new(uri, self).compress
|
141
|
+
end
|
142
|
+
|
143
|
+
def expand_from_root(uri)
|
144
|
+
URITar.new(uri, self).expand
|
145
|
+
end
|
98
146
|
end
|
99
147
|
end
|
data/lib/sprockets/bower.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
|
3
4
|
module Sprockets
|
@@ -17,7 +18,7 @@ module Sprockets
|
|
17
18
|
candidates, deps = super
|
18
19
|
|
19
20
|
# bower.json can only be nested one level deep
|
20
|
-
if !logical_path.index('/')
|
21
|
+
if !logical_path.index('/'.freeze)
|
21
22
|
dirname = File.join(load_path, logical_path)
|
22
23
|
|
23
24
|
if directory?(dirname)
|
@@ -27,7 +28,9 @@ module Sprockets
|
|
27
28
|
if filename
|
28
29
|
deps << build_file_digest_uri(filename)
|
29
30
|
read_bower_main(dirname, filename) do |path|
|
30
|
-
|
31
|
+
if file?(path)
|
32
|
+
candidates << path
|
33
|
+
end
|
31
34
|
end
|
32
35
|
end
|
33
36
|
end
|
data/lib/sprockets/bundle.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'set'
|
2
3
|
require 'sprockets/utils'
|
4
|
+
require 'sprockets/uri_utils'
|
3
5
|
|
4
6
|
module Sprockets
|
5
7
|
# Internal: Bundle processor takes a single file asset and prepends all the
|
@@ -15,15 +17,32 @@ module Sprockets
|
|
15
17
|
def self.call(input)
|
16
18
|
env = input[:environment]
|
17
19
|
type = input[:content_type]
|
20
|
+
input[:links] ||= Set.new
|
18
21
|
dependencies = Set.new(input[:metadata][:dependencies])
|
19
22
|
|
20
|
-
processed_uri, deps = env.resolve(input[:filename], accept: type, pipeline: :self
|
23
|
+
processed_uri, deps = env.resolve(input[:filename], accept: type, pipeline: :self)
|
21
24
|
dependencies.merge(deps)
|
22
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
|
+
|
23
41
|
find_required = proc { |uri| env.load(uri).metadata[:required] }
|
24
42
|
required = Utils.dfs(processed_uri, &find_required)
|
25
43
|
stubbed = Utils.dfs(env.load(processed_uri).metadata[:stubbed], &find_required)
|
26
44
|
required.subtract(stubbed)
|
45
|
+
dedup(required)
|
27
46
|
assets = required.map { |uri| env.load(uri) }
|
28
47
|
|
29
48
|
(required + stubbed).each do |uri|
|
@@ -31,20 +50,41 @@ module Sprockets
|
|
31
50
|
end
|
32
51
|
|
33
52
|
reducers = Hash[env.match_mime_type_keys(env.config[:bundle_reducers], type).flat_map(&:to_a)]
|
34
|
-
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)
|
35
70
|
end
|
36
71
|
|
37
72
|
# Internal: Run bundle reducers on set of Assets producing a reduced
|
38
73
|
# metadata Hash.
|
39
74
|
#
|
75
|
+
# filename - String bundle filename
|
40
76
|
# assets - Array of Assets
|
41
77
|
# reducers - Array of [initial, reducer_proc] pairs
|
42
78
|
#
|
43
79
|
# Returns reduced asset metadata Hash.
|
44
|
-
def self.process_bundle_reducers(assets, reducers)
|
80
|
+
def self.process_bundle_reducers(input, assets, reducers)
|
45
81
|
initial = {}
|
46
82
|
reducers.each do |k, (v, _)|
|
47
|
-
|
83
|
+
if v.respond_to?(:call)
|
84
|
+
initial[k] = v.call(input)
|
85
|
+
elsif !v.nil?
|
86
|
+
initial[k] = v
|
87
|
+
end
|
48
88
|
end
|
49
89
|
|
50
90
|
assets.reduce(initial) do |h, asset|
|