sprockets 2.3.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sprockets might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/LICENSE +2 -2
- data/README.md +332 -115
- data/bin/sprockets +8 -0
- data/lib/rake/sprocketstask.rb +25 -13
- data/lib/sprockets/asset.rb +143 -205
- data/lib/sprockets/autoload/closure.rb +7 -0
- data/lib/sprockets/autoload/coffee_script.rb +7 -0
- data/lib/sprockets/autoload/eco.rb +7 -0
- data/lib/sprockets/autoload/ejs.rb +7 -0
- data/lib/sprockets/autoload/sass.rb +7 -0
- data/lib/sprockets/autoload/uglifier.rb +7 -0
- data/lib/sprockets/autoload/yui.rb +7 -0
- data/lib/sprockets/autoload.rb +11 -0
- data/lib/sprockets/base.rb +49 -257
- data/lib/sprockets/bower.rb +58 -0
- data/lib/sprockets/bundle.rb +65 -0
- data/lib/sprockets/cache/file_store.rb +165 -14
- data/lib/sprockets/cache/memory_store.rb +66 -0
- data/lib/sprockets/cache/null_store.rb +46 -0
- data/lib/sprockets/cache.rb +234 -0
- data/lib/sprockets/cached_environment.rb +69 -0
- data/lib/sprockets/closure_compressor.rb +53 -0
- data/lib/sprockets/coffee_script_processor.rb +25 -0
- data/lib/sprockets/coffee_script_template.rb +6 -0
- data/lib/sprockets/compressing.rb +74 -0
- data/lib/sprockets/configuration.rb +83 -0
- data/lib/sprockets/context.rb +125 -131
- data/lib/sprockets/dependencies.rb +73 -0
- data/lib/sprockets/digest_utils.rb +156 -0
- data/lib/sprockets/directive_processor.rb +209 -211
- data/lib/sprockets/eco_processor.rb +32 -0
- data/lib/sprockets/eco_template.rb +3 -35
- data/lib/sprockets/ejs_processor.rb +31 -0
- data/lib/sprockets/ejs_template.rb +3 -34
- data/lib/sprockets/encoding_utils.rb +258 -0
- data/lib/sprockets/engines.rb +45 -38
- data/lib/sprockets/environment.rb +17 -67
- data/lib/sprockets/erb_processor.rb +30 -0
- data/lib/sprockets/erb_template.rb +6 -0
- data/lib/sprockets/errors.rb +6 -13
- data/lib/sprockets/file_reader.rb +15 -0
- data/lib/sprockets/http_utils.rb +115 -0
- data/lib/sprockets/jst_processor.rb +35 -19
- data/lib/sprockets/legacy.rb +314 -0
- data/lib/sprockets/legacy_proc_processor.rb +35 -0
- data/lib/sprockets/legacy_tilt_processor.rb +29 -0
- data/lib/sprockets/loader.rb +176 -0
- data/lib/sprockets/manifest.rb +179 -98
- data/lib/sprockets/manifest_utils.rb +45 -0
- data/lib/sprockets/mime.rb +114 -32
- data/lib/sprockets/path_dependency_utils.rb +85 -0
- data/lib/sprockets/path_digest_utils.rb +47 -0
- data/lib/sprockets/path_utils.rb +282 -0
- data/lib/sprockets/paths.rb +81 -0
- data/lib/sprockets/processing.rb +157 -189
- data/lib/sprockets/processor_utils.rb +103 -0
- data/lib/sprockets/resolve.rb +208 -0
- data/lib/sprockets/sass_cache_store.rb +19 -15
- data/lib/sprockets/sass_compressor.rb +59 -0
- data/lib/sprockets/sass_functions.rb +2 -0
- data/lib/sprockets/sass_importer.rb +2 -29
- data/lib/sprockets/sass_processor.rb +285 -0
- data/lib/sprockets/sass_template.rb +4 -44
- data/lib/sprockets/server.rb +109 -84
- data/lib/sprockets/transformers.rb +145 -0
- data/lib/sprockets/uglifier_compressor.rb +63 -0
- data/lib/sprockets/uri_utils.rb +190 -0
- data/lib/sprockets/utils.rb +193 -44
- data/lib/sprockets/version.rb +1 -1
- data/lib/sprockets/yui_compressor.rb +65 -0
- data/lib/sprockets.rb +144 -53
- metadata +248 -238
- data/lib/sprockets/asset_attributes.rb +0 -126
- data/lib/sprockets/bundled_asset.rb +0 -79
- data/lib/sprockets/caching.rb +0 -96
- data/lib/sprockets/charset_normalizer.rb +0 -41
- data/lib/sprockets/index.rb +0 -99
- data/lib/sprockets/processed_asset.rb +0 -152
- data/lib/sprockets/processor.rb +0 -32
- data/lib/sprockets/safety_colons.rb +0 -28
- data/lib/sprockets/scss_template.rb +0 -13
- data/lib/sprockets/static_asset.rb +0 -57
- data/lib/sprockets/trail.rb +0 -90
data/bin/sprockets
CHANGED
@@ -40,6 +40,14 @@ OptionParser.new do |opts|
|
|
40
40
|
manifest = Sprockets::Manifest.new(environment, directory)
|
41
41
|
end
|
42
42
|
|
43
|
+
opts.on("--css-compressor=COMPRESSOR", "Use CSS compressor") do |compressor|
|
44
|
+
environment.css_compressor = compressor.to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("--js-compressor=COMPRESSOR", "Use JavaScript compressor") do |compressor|
|
48
|
+
environment.js_compressor = compressor.to_sym
|
49
|
+
end
|
50
|
+
|
43
51
|
opts.on("--noenv", "Disables .sprocketsrc file") do
|
44
52
|
end
|
45
53
|
|
data/lib/rake/sprocketstask.rb
CHANGED
@@ -37,6 +37,25 @@ module Rake
|
|
37
37
|
end
|
38
38
|
attr_writer :environment
|
39
39
|
|
40
|
+
# Returns cached cached environment
|
41
|
+
def cached
|
42
|
+
@cached ||= environment.cached if environment
|
43
|
+
end
|
44
|
+
alias_method :index, :cached
|
45
|
+
|
46
|
+
# `Manifest` instance used for already compiled assets.
|
47
|
+
#
|
48
|
+
# Will be created by default if an environment and output
|
49
|
+
# directory are given
|
50
|
+
def manifest
|
51
|
+
if !@manifest.is_a?(Sprockets::Manifest) && @manifest.respond_to?(:call)
|
52
|
+
@manifest = @manifest.call
|
53
|
+
else
|
54
|
+
@manifest
|
55
|
+
end
|
56
|
+
end
|
57
|
+
attr_writer :manifest
|
58
|
+
|
40
59
|
# Directory to write compiled assets too. As well as the manifest file.
|
41
60
|
#
|
42
61
|
# t.output = "./public/assets"
|
@@ -79,6 +98,7 @@ module Rake
|
|
79
98
|
def initialize(name = :assets)
|
80
99
|
@name = name
|
81
100
|
@environment = lambda { Sprockets::Environment.new(Dir.pwd) }
|
101
|
+
@manifest = lambda { Sprockets::Manifest.new(cached, output) }
|
82
102
|
@logger = Logger.new($stderr)
|
83
103
|
@logger.level = Logger::INFO
|
84
104
|
@keep = 2
|
@@ -117,24 +137,16 @@ module Rake
|
|
117
137
|
end
|
118
138
|
|
119
139
|
private
|
120
|
-
# Returns cached indexed environment
|
121
|
-
def index
|
122
|
-
@index ||= environment.index
|
123
|
-
end
|
124
|
-
|
125
|
-
# Returns manifest for tasks
|
126
|
-
def manifest
|
127
|
-
@manifest ||= Sprockets::Manifest.new(index, output)
|
128
|
-
end
|
129
|
-
|
130
140
|
# Sub out environment logger with our rake task logger that
|
131
141
|
# writes to stderr.
|
132
142
|
def with_logger
|
133
|
-
|
134
|
-
|
143
|
+
if env = manifest.environment
|
144
|
+
old_logger = env.logger
|
145
|
+
env.logger = @logger
|
146
|
+
end
|
135
147
|
yield
|
136
148
|
ensure
|
137
|
-
|
149
|
+
env.logger = old_logger if env
|
138
150
|
end
|
139
151
|
end
|
140
152
|
end
|
data/lib/sprockets/asset.rb
CHANGED
@@ -1,261 +1,199 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'fileutils'
|
2
|
+
require 'sprockets/digest_utils'
|
3
3
|
|
4
4
|
module Sprockets
|
5
|
-
# `Asset` is the base class for `BundledAsset` and `StaticAsset`.
|
6
5
|
class Asset
|
7
|
-
|
8
|
-
def self.from_hash(environment, hash)
|
9
|
-
return unless hash.is_a?(Hash)
|
6
|
+
attr_reader :logical_path
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@
|
40
|
-
@mtime = environment.stat(pathname).mtime
|
41
|
-
@length = environment.stat(pathname).size
|
42
|
-
@digest = environment.file_digest(pathname).hexdigest
|
8
|
+
# Private: Intialize Asset wrapper from attributes Hash.
|
9
|
+
#
|
10
|
+
# Asset wrappers should not be initialized directly, only
|
11
|
+
# Environment#find_asset should vend them.
|
12
|
+
#
|
13
|
+
# attributes - Hash of ivars
|
14
|
+
#
|
15
|
+
# Returns Asset.
|
16
|
+
def initialize(environment, attributes = {})
|
17
|
+
@environment = environment
|
18
|
+
@attributes = attributes
|
19
|
+
@content_type = attributes[:content_type]
|
20
|
+
@filename = attributes[:filename]
|
21
|
+
@id = attributes[:id]
|
22
|
+
@integrity = attributes[:integrity]
|
23
|
+
@load_path = attributes[:load_path]
|
24
|
+
@logical_path = attributes[:logical_path]
|
25
|
+
@metadata = attributes[:metadata]
|
26
|
+
@mtime = attributes[:mtime]
|
27
|
+
@name = attributes[:name]
|
28
|
+
@source = attributes[:source]
|
29
|
+
@uri = attributes[:uri]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Internal: Return all internal instance variables as a hash.
|
33
|
+
#
|
34
|
+
# Returns a Hash.
|
35
|
+
def to_hash
|
36
|
+
@attributes
|
43
37
|
end
|
44
38
|
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
if pathname = coder['pathname']
|
54
|
-
# Expand `$root` placeholder and wrapper string in a `Pathname`
|
55
|
-
@pathname = Pathname.new(expand_root_path(pathname))
|
56
|
-
end
|
39
|
+
# Public: Metadata accumulated from pipeline process.
|
40
|
+
#
|
41
|
+
# The API status of the keys is dependent on the pipeline processors
|
42
|
+
# itself. So some values maybe considered public and others internal.
|
43
|
+
# See the pipeline proccessor documentation itself.
|
44
|
+
#
|
45
|
+
# Returns Hash.
|
46
|
+
attr_reader :metadata
|
57
47
|
|
58
|
-
|
59
|
-
|
60
|
-
@mtime = Time.parse(mtime)
|
61
|
-
end
|
48
|
+
# Public: Returns String path of asset.
|
49
|
+
attr_reader :filename
|
62
50
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
51
|
+
# Internal: Unique asset object ID.
|
52
|
+
#
|
53
|
+
# Returns a String.
|
54
|
+
attr_reader :id
|
68
55
|
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
coder['mtime'] = mtime.iso8601
|
76
|
-
coder['length'] = length
|
77
|
-
coder['digest'] = digest
|
78
|
-
end
|
56
|
+
# Public: Internal URI to lookup asset by.
|
57
|
+
#
|
58
|
+
# NOT a publically accessible URL.
|
59
|
+
#
|
60
|
+
# Returns URI.
|
61
|
+
attr_reader :uri
|
79
62
|
|
80
|
-
# Return logical path with digest spliced in.
|
63
|
+
# Public: Return logical path with digest spliced in.
|
81
64
|
#
|
82
65
|
# "foo/bar-37b51d194a7513e45b56f6524f2d51f2.js"
|
83
66
|
#
|
67
|
+
# Returns String.
|
84
68
|
def digest_path
|
85
|
-
logical_path.sub(/\.(\w+)$/) { |ext| "-#{
|
69
|
+
logical_path.sub(/\.(\w+)$/) { |ext| "-#{etag}#{ext}" }
|
86
70
|
end
|
87
71
|
|
88
|
-
#
|
89
|
-
|
90
|
-
[]
|
91
|
-
end
|
72
|
+
# Public: Returns String MIME type of asset. Returns nil if type is unknown.
|
73
|
+
attr_reader :content_type
|
92
74
|
|
93
|
-
#
|
75
|
+
# Public: Get all externally linked asset filenames from asset.
|
94
76
|
#
|
95
|
-
#
|
96
|
-
# the asset's contents as a whole.
|
77
|
+
# All linked assets should be compiled anytime this asset is.
|
97
78
|
#
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
[self]
|
79
|
+
# Returns Set of String asset URIs.
|
80
|
+
def links
|
81
|
+
metadata[:links] || Set.new
|
102
82
|
end
|
103
83
|
|
104
|
-
#
|
105
|
-
|
106
|
-
|
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
|
+
# Public: Return `String` of concatenated source.
|
93
|
+
#
|
94
|
+
# Returns String.
|
95
|
+
def source
|
96
|
+
if @source
|
97
|
+
@source
|
98
|
+
else
|
99
|
+
# File is read everytime to avoid memory bloat of large binary files
|
100
|
+
File.binread(filename)
|
101
|
+
end
|
107
102
|
end
|
108
103
|
|
109
|
-
#
|
104
|
+
# Public: Alias for #source.
|
105
|
+
#
|
106
|
+
# Returns String.
|
110
107
|
def to_s
|
111
108
|
source
|
112
109
|
end
|
113
110
|
|
114
|
-
#
|
115
|
-
#
|
116
|
-
|
117
|
-
|
111
|
+
# Public: Get charset of source.
|
112
|
+
#
|
113
|
+
# Returns a String charset name or nil if binary.
|
114
|
+
def charset
|
115
|
+
metadata[:charset]
|
118
116
|
end
|
119
117
|
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
# Used to test if cached models need to be rebuilt.
|
124
|
-
def fresh?(environment)
|
125
|
-
# Check current mtime and digest
|
126
|
-
dependency_fresh?(environment, self)
|
118
|
+
# Public: Returns Integer length of source.
|
119
|
+
def length
|
120
|
+
metadata[:length]
|
127
121
|
end
|
122
|
+
alias_method :bytesize, :length
|
128
123
|
|
129
|
-
#
|
130
|
-
|
124
|
+
# Public: Returns String hexdigest of source.
|
125
|
+
def hexdigest
|
126
|
+
DigestUtils.pack_hexdigest(metadata[:digest])
|
127
|
+
end
|
128
|
+
|
129
|
+
# Deprecated: Returns String hexdigest of source.
|
131
130
|
#
|
132
|
-
#
|
133
|
-
|
134
|
-
|
131
|
+
# In 4.x this will be changed to return a raw Digest byte String.
|
132
|
+
alias_method :digest, :hexdigest
|
133
|
+
|
134
|
+
# Pubic: ETag String of Asset.
|
135
|
+
alias_method :etag, :hexdigest
|
136
|
+
|
137
|
+
# Public: Returns String base64 digest of source.
|
138
|
+
def base64digest
|
139
|
+
DigestUtils.pack_base64digest(metadata[:digest])
|
135
140
|
end
|
136
141
|
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
|
142
|
+
# Public: A "named information" URL for subresource integrity.
|
143
|
+
attr_reader :integrity
|
144
|
+
|
145
|
+
# Public: Add enumerator to allow `Asset` instances to be used as Rack
|
146
|
+
# compatible body objects.
|
147
|
+
#
|
148
|
+
# block
|
149
|
+
# part - String body chunk
|
150
|
+
#
|
151
|
+
# Returns nothing.
|
152
|
+
def each
|
153
|
+
yield to_s
|
154
|
+
end
|
141
155
|
|
156
|
+
# Deprecated: Save asset to disk.
|
157
|
+
#
|
158
|
+
# filename - String target
|
159
|
+
#
|
160
|
+
# Returns nothing.
|
161
|
+
def write_to(filename)
|
142
162
|
FileUtils.mkdir_p File.dirname(filename)
|
143
163
|
|
144
|
-
|
145
|
-
|
146
|
-
# Run contents through `Zlib`
|
147
|
-
gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
|
148
|
-
gz.write to_s
|
149
|
-
gz.close
|
150
|
-
else
|
151
|
-
# Write out as is
|
152
|
-
f.write to_s
|
153
|
-
f.close
|
154
|
-
end
|
164
|
+
PathUtils.atomic_write(filename) do |f|
|
165
|
+
f.write source
|
155
166
|
end
|
156
167
|
|
157
|
-
# Atomic write
|
158
|
-
FileUtils.mv("#{filename}+", filename)
|
159
|
-
|
160
168
|
# Set mtime correctly
|
161
169
|
File.utime(mtime, mtime, filename)
|
162
170
|
|
163
171
|
nil
|
164
|
-
ensure
|
165
|
-
# Ensure tmp file gets cleaned up
|
166
|
-
FileUtils.rm("#{filename}+") if File.exist?("#{filename}+")
|
167
172
|
end
|
168
173
|
|
169
|
-
# Pretty inspect
|
174
|
+
# Public: Pretty inspect
|
175
|
+
#
|
176
|
+
# Returns String.
|
170
177
|
def inspect
|
171
|
-
"#<#{self.class}
|
172
|
-
"pathname=#{pathname.to_s.inspect}, " +
|
173
|
-
"mtime=#{mtime.inspect}, " +
|
174
|
-
"digest=#{digest.inspect}" +
|
175
|
-
">"
|
178
|
+
"#<#{self.class}:#{object_id.to_s(16)} #{uri.inspect}>"
|
176
179
|
end
|
177
180
|
|
181
|
+
# Public: Implements Object#hash so Assets can be used as a Hash key or
|
182
|
+
# in a Set.
|
183
|
+
#
|
184
|
+
# Returns Integer hash of the id.
|
178
185
|
def hash
|
179
|
-
|
186
|
+
id.hash
|
180
187
|
end
|
181
188
|
|
182
|
-
#
|
189
|
+
# Public: Compare assets.
|
190
|
+
#
|
191
|
+
# Assets are equal if they share the same path and digest.
|
192
|
+
#
|
193
|
+
# Returns true or false.
|
183
194
|
def eql?(other)
|
184
|
-
|
185
|
-
other.logical_path == self.logical_path &&
|
186
|
-
other.mtime.to_i == self.mtime.to_i &&
|
187
|
-
other.digest == self.digest
|
195
|
+
self.class == other.class && self.id == other.id
|
188
196
|
end
|
189
197
|
alias_method :==, :eql?
|
190
|
-
|
191
|
-
protected
|
192
|
-
# Internal: String paths that are marked as dependencies after processing.
|
193
|
-
#
|
194
|
-
# Default to an empty `Array`.
|
195
|
-
def dependency_paths
|
196
|
-
@dependency_paths ||= []
|
197
|
-
end
|
198
|
-
|
199
|
-
# Internal: `ProccessedAsset`s that are required after processing.
|
200
|
-
#
|
201
|
-
# Default to an empty `Array`.
|
202
|
-
def required_assets
|
203
|
-
@required_assets ||= []
|
204
|
-
end
|
205
|
-
|
206
|
-
# Get pathname with its root stripped.
|
207
|
-
def relative_pathname
|
208
|
-
@relative_pathname ||= Pathname.new(relativize_root_path(pathname))
|
209
|
-
end
|
210
|
-
|
211
|
-
# Replace `$root` placeholder with actual environment root.
|
212
|
-
def expand_root_path(path)
|
213
|
-
path.to_s.sub(/^\$root/, @root)
|
214
|
-
end
|
215
|
-
|
216
|
-
# Replace actual environment root with `$root` placeholder.
|
217
|
-
def relativize_root_path(path)
|
218
|
-
path.to_s.sub(/^#{Regexp.escape(@root)}/, '$root')
|
219
|
-
end
|
220
|
-
|
221
|
-
# Check if dependency is fresh.
|
222
|
-
#
|
223
|
-
# `dep` is a `Hash` with `path`, `mtime` and `hexdigest` keys.
|
224
|
-
#
|
225
|
-
# A `Hash` is used rather than other `Asset` object because we
|
226
|
-
# want to test non-asset files and directories.
|
227
|
-
def dependency_fresh?(environment, dep)
|
228
|
-
path, mtime, hexdigest = dep.pathname.to_s, dep.mtime, dep.digest
|
229
|
-
|
230
|
-
stat = environment.stat(path)
|
231
|
-
|
232
|
-
# If path no longer exists, its definitely stale.
|
233
|
-
if stat.nil?
|
234
|
-
return false
|
235
|
-
end
|
236
|
-
|
237
|
-
# Compare dependency mime to the actual mtime. If the
|
238
|
-
# dependency mtime is newer than the actual mtime, the file
|
239
|
-
# hasn't changed since we created this `Asset` instance.
|
240
|
-
#
|
241
|
-
# However, if the mtime is newer it doesn't mean the asset is
|
242
|
-
# stale. Many deployment environments may recopy or recheckout
|
243
|
-
# assets on each deploy. In this case the mtime would be the
|
244
|
-
# time of deploy rather than modified time.
|
245
|
-
if mtime >= stat.mtime
|
246
|
-
return true
|
247
|
-
end
|
248
|
-
|
249
|
-
digest = environment.file_digest(path)
|
250
|
-
|
251
|
-
# If the mtime is newer, do a full digest comparsion. Return
|
252
|
-
# fresh if the digests match.
|
253
|
-
if hexdigest == digest.hexdigest
|
254
|
-
return true
|
255
|
-
end
|
256
|
-
|
257
|
-
# Otherwise, its stale.
|
258
|
-
false
|
259
|
-
end
|
260
198
|
end
|
261
199
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Sprockets
|
2
|
+
module Autoload
|
3
|
+
autoload :Closure, 'sprockets/autoload/closure'
|
4
|
+
autoload :CoffeeScript, 'sprockets/autoload/coffee_script'
|
5
|
+
autoload :Eco, 'sprockets/autoload/eco'
|
6
|
+
autoload :EJS, 'sprockets/autoload/ejs'
|
7
|
+
autoload :Sass, 'sprockets/autoload/sass'
|
8
|
+
autoload :Uglifier, 'sprockets/autoload/uglifier'
|
9
|
+
autoload :YUI, 'sprockets/autoload/yui'
|
10
|
+
end
|
11
|
+
end
|