condenser 0.0.1
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +1 -0
- data/lib/condenser.rb +108 -0
- data/lib/condenser/asset.rb +221 -0
- data/lib/condenser/cache/memory_store.rb +92 -0
- data/lib/condenser/cache/null_store.rb +37 -0
- data/lib/condenser/context.rb +272 -0
- data/lib/condenser/encoding_utils.rb +155 -0
- data/lib/condenser/environment.rb +50 -0
- data/lib/condenser/errors.rb +11 -0
- data/lib/condenser/export.rb +68 -0
- data/lib/condenser/manifest.rb +89 -0
- data/lib/condenser/pipeline.rb +82 -0
- data/lib/condenser/processors/babel.min.js +25 -0
- data/lib/condenser/processors/babel_processor.rb +87 -0
- data/lib/condenser/processors/node_processor.rb +38 -0
- data/lib/condenser/processors/rollup.js +24083 -0
- data/lib/condenser/processors/rollup_processor.rb +164 -0
- data/lib/condenser/processors/sass_importer.rb +81 -0
- data/lib/condenser/processors/sass_processor.rb +300 -0
- data/lib/condenser/resolve.rb +202 -0
- data/lib/condenser/server.rb +307 -0
- data/lib/condenser/templating_engine/erb.rb +21 -0
- data/lib/condenser/utils.rb +32 -0
- data/lib/condenser/version.rb +3 -0
- data/lib/condenser/writers/file_writer.rb +28 -0
- data/lib/condenser/writers/zlib_writer.rb +42 -0
- data/test/cache_test.rb +24 -0
- data/test/environment_test.rb +49 -0
- data/test/manifest_test.rb +513 -0
- data/test/pipeline_test.rb +31 -0
- data/test/preprocessor/babel_test.rb +21 -0
- data/test/processors/rollup_test.rb +71 -0
- data/test/resolve_test.rb +105 -0
- data/test/server_test.rb +361 -0
- data/test/templates/erb_test.rb +18 -0
- data/test/test_helper.rb +68 -0
- data/test/transformers/scss_test.rb +49 -0
- metadata +193 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require "erubi"
|
2
|
+
|
3
|
+
class Condenser
|
4
|
+
class Erubi
|
5
|
+
|
6
|
+
def self.call(environment, data)
|
7
|
+
source = ::Erubi::Engine.new(data[:source], {
|
8
|
+
preamble: "@output_buffer = String.new;",
|
9
|
+
bufvar: "@output_buffer",
|
10
|
+
postamble: "@output_buffer.to_s"
|
11
|
+
}).src
|
12
|
+
|
13
|
+
source = eval("proc { #{source} }", nil, data[:filename] || "(erubi)")
|
14
|
+
source = environment.new_context_class.instance_eval(&source)
|
15
|
+
|
16
|
+
|
17
|
+
data[:source] = source
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Condenser
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
# Public: Write to a file atomically. Useful for situations where you
|
5
|
+
# don't want other processes or threads to see half-written files.
|
6
|
+
#
|
7
|
+
# Utils.atomic_write('important.file') do |file|
|
8
|
+
# file.write('hello')
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# Returns nothing.
|
12
|
+
def self.atomic_write(filename)
|
13
|
+
dirname, basename = File.split(filename)
|
14
|
+
basename = [
|
15
|
+
basename,
|
16
|
+
Thread.current.object_id,
|
17
|
+
Process.pid,
|
18
|
+
rand(1000000)
|
19
|
+
].join('.'.freeze)
|
20
|
+
tmpname = File.join(dirname, basename)
|
21
|
+
|
22
|
+
File.open(tmpname, 'wb+') do |f|
|
23
|
+
yield f
|
24
|
+
end
|
25
|
+
|
26
|
+
File.rename(tmpname, filename)
|
27
|
+
ensure
|
28
|
+
File.delete(tmpname) if File.exist?(tmpname)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'condenser/utils'
|
2
|
+
|
3
|
+
class Condenser
|
4
|
+
# Writes a an asset file to disk
|
5
|
+
class FileWriter
|
6
|
+
|
7
|
+
def skip?(asset, logger)
|
8
|
+
if ::File.exist?(asset.path)
|
9
|
+
logger.debug "Skipping #{ asset.filename }, already exists"
|
10
|
+
true
|
11
|
+
else
|
12
|
+
logger.info "Writing #{ asset.filename }"
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(output_directory, asset)
|
18
|
+
filename = File.join(output_directory, asset.path)
|
19
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
20
|
+
Utils.atomic_write(filename) do |file|
|
21
|
+
file.write(asset.source)
|
22
|
+
end
|
23
|
+
|
24
|
+
[asset.filename]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'condenser/utils'
|
3
|
+
|
4
|
+
class Condenser
|
5
|
+
# Generates a `.gz` file using the zlib algorithm built into
|
6
|
+
# Ruby's standard library.
|
7
|
+
class ZlibWriter
|
8
|
+
|
9
|
+
# What mime types should we compress? This list comes from:
|
10
|
+
# https://www.fastly.com/blog/new-gzip-settings-and-deciding-what-compress
|
11
|
+
COMPRESSALBE_TYPES = %w( text/html application/x-javascript text/css
|
12
|
+
application/javascript text/javascript text/plain text/xml
|
13
|
+
application/json application/vnd.ms-fontobject application/x-font-opentype
|
14
|
+
application/x-font-truetype application/x-font-ttf application/xml font/eot
|
15
|
+
font/opentype font/otf image/svg+xml image/vnd.microsoft.icon image/x-icon)
|
16
|
+
|
17
|
+
def skip?(asset, logger)
|
18
|
+
target = "#{asset.path}.gz"
|
19
|
+
if ::File.exist?(target)
|
20
|
+
logger.debug "Skipping #{ target }, already exists"
|
21
|
+
true
|
22
|
+
else
|
23
|
+
logger.info "Writing #{ target }"
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(output_directory, asset)
|
29
|
+
filename = File.join(output_directory, "#{asset.path}.gz")
|
30
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
31
|
+
Utils.atomic_write(filename) do |file|
|
32
|
+
gz = Zlib::GzipWriter.new(file, Zlib::BEST_COMPRESSION)
|
33
|
+
gz.write(asset.source)
|
34
|
+
gz.close
|
35
|
+
# File.utime(mtime, mtime, file.path)
|
36
|
+
end
|
37
|
+
|
38
|
+
["#{asset.filename}.gz"]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/test/cache_test.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CacheTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@env.cache = Condenser::Cache::MemoryStore.new
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'resolving and asset twice only compiles once' do
|
11
|
+
file 'test.txt.erb', "1<%= 1 + 1 %>3\n"
|
12
|
+
|
13
|
+
assert_file 'test.txt', 'text/plain', <<~CSS
|
14
|
+
123
|
15
|
+
CSS
|
16
|
+
|
17
|
+
Condenser::Erubi.stubs(:call).never
|
18
|
+
|
19
|
+
assert_file 'test.txt', 'text/plain', <<~CSS
|
20
|
+
123
|
21
|
+
CSS
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EnvironmentTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@env.clear_path
|
8
|
+
end
|
9
|
+
|
10
|
+
test "working directory is the default root" do
|
11
|
+
assert_equal Dir.pwd, Condenser.new.root
|
12
|
+
end
|
13
|
+
|
14
|
+
test "default logger level is set to warn" do
|
15
|
+
assert_equal Logger::WARN, @env.logger.level
|
16
|
+
end
|
17
|
+
|
18
|
+
test "paths" do
|
19
|
+
assert_equal [], @env.path
|
20
|
+
end
|
21
|
+
|
22
|
+
test "prepend_path" do
|
23
|
+
assert_equal [], @env.path
|
24
|
+
@env.prepend_path 'a'
|
25
|
+
@env.prepend_path 'b'
|
26
|
+
assert_equal ['b', 'a'].map { |d| File.expand_path(d, @path) }, @env.path
|
27
|
+
end
|
28
|
+
|
29
|
+
test "append_path" do
|
30
|
+
assert_equal [], @env.path
|
31
|
+
@env.append_path 'a'
|
32
|
+
@env.append_path 'b'
|
33
|
+
assert_equal ['a', 'b'].map { |d| File.expand_path(d, @path) }, @env.path
|
34
|
+
end
|
35
|
+
|
36
|
+
test "clear_path" do
|
37
|
+
@env.append_path 'a'
|
38
|
+
assert_not_empty @env.path
|
39
|
+
@env.clear_path
|
40
|
+
assert_empty @env.path
|
41
|
+
end
|
42
|
+
|
43
|
+
test "digestor=" do
|
44
|
+
assert_equal @env.digestor, Digest::SHA256
|
45
|
+
@env.digestor = Digest::MD5
|
46
|
+
assert_equal @env.digestor, Digest::MD5
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,513 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ManifestTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@dir = Dir.mktmpdir
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
super
|
12
|
+
FileUtils.remove_entry(@dir, true)
|
13
|
+
end
|
14
|
+
|
15
|
+
test "specify full manifest filename" do
|
16
|
+
directory = Dir::tmpdir
|
17
|
+
filename = File.join(directory, 'manifest.json')
|
18
|
+
|
19
|
+
manifest = Condenser::Manifest.new(@env, filename)
|
20
|
+
|
21
|
+
assert_equal directory, manifest.directory
|
22
|
+
assert_equal filename, manifest.filename
|
23
|
+
end
|
24
|
+
|
25
|
+
test "specify manifest directory yields manifest.json" do
|
26
|
+
manifest = Condenser::Manifest.new(@env, @dir)
|
27
|
+
|
28
|
+
assert_equal @dir, manifest.directory
|
29
|
+
assert_match('manifest.json', File.basename(manifest.filename))
|
30
|
+
end
|
31
|
+
|
32
|
+
test "must specify manifest directory or filename" do
|
33
|
+
assert_raises ArgumentError do
|
34
|
+
Condenser::Manifest.new(@env)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
test "must specify env to compile assets" do
|
39
|
+
manifest = Condenser::Manifest.new(@dir)
|
40
|
+
|
41
|
+
assert_raises Condenser::Error do
|
42
|
+
manifest.compile('application.js')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
test "compile asset" do
|
47
|
+
file 'application.js', <<-JS
|
48
|
+
console.log(1);
|
49
|
+
JS
|
50
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
51
|
+
|
52
|
+
asset = @env['application.js']
|
53
|
+
assert !File.exist?("#{@dir}/#{asset.path}")
|
54
|
+
|
55
|
+
manifest.compile('application.js')
|
56
|
+
assert File.directory?(manifest.directory)
|
57
|
+
assert File.file?(manifest.filename)
|
58
|
+
|
59
|
+
assert File.exist?("#{@dir}/manifest.json")
|
60
|
+
assert File.exist?("#{@dir}/#{asset.path}")
|
61
|
+
assert File.exist?("#{@dir}/#{asset.path}.gz")
|
62
|
+
|
63
|
+
data = JSON.parse(File.read(manifest.filename))
|
64
|
+
assert data['application.js']
|
65
|
+
assert data['application.js']['size'] > 16
|
66
|
+
assert_equal asset.path, data['application.js']['path']
|
67
|
+
end
|
68
|
+
|
69
|
+
# TODO:
|
70
|
+
# test "compile asset with aliased index links" do
|
71
|
+
# manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
72
|
+
#
|
73
|
+
# main_digest_path = @env['alias-index-link.js'].path
|
74
|
+
# dep_digest_path = @env['coffee.js'].path
|
75
|
+
#
|
76
|
+
# assert !File.exist?("#{@dir}/#{main_digest_path}")
|
77
|
+
# assert !File.exist?("#{@dir}/#{dep_digest_path}")
|
78
|
+
#
|
79
|
+
# manifest.compile('alias-index-link.js')
|
80
|
+
# assert File.directory?(manifest.directory)
|
81
|
+
# assert File.file?(manifest.filename)
|
82
|
+
#
|
83
|
+
# assert File.exist?("#{@dir}/manifest.json")
|
84
|
+
# assert File.exist?("#{@dir}/#{main_digest_path}")
|
85
|
+
# assert File.exist?("#{@dir}/#{dep_digest_path}")
|
86
|
+
#
|
87
|
+
# data = JSON.parse(File.read(manifest.filename))
|
88
|
+
#
|
89
|
+
# assert data['files'][main_digest_path]
|
90
|
+
# assert data['files'][dep_digest_path]
|
91
|
+
# assert_equal "alias-index-link.js", data['files'][main_digest_path]['logical_path']
|
92
|
+
# assert_equal "coffee.js", data['files'][dep_digest_path]['logical_path']
|
93
|
+
# assert_equal main_digest_path, data['assets']['alias-index-link.js']
|
94
|
+
# assert_equal dep_digest_path, data['assets']['coffee.js']
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
test "compile to directory and seperate location" do
|
98
|
+
file 'application.js', <<-JS
|
99
|
+
console.log(1);
|
100
|
+
JS
|
101
|
+
|
102
|
+
root = File.join(Dir::tmpdir, 'public')
|
103
|
+
dir = File.join(root, 'assets')
|
104
|
+
path = File.join(root, 'manifests', 'manifest-123.json')
|
105
|
+
|
106
|
+
FileUtils.remove_entry(root, true)
|
107
|
+
|
108
|
+
assert !File.exist?(root)
|
109
|
+
manifest = Condenser::Manifest.new(@env, dir, path)
|
110
|
+
|
111
|
+
manifest.compile('application.js')
|
112
|
+
assert File.directory?(manifest.directory)
|
113
|
+
assert File.file?(path)
|
114
|
+
FileUtils.remove_entry(root, true)
|
115
|
+
end
|
116
|
+
|
117
|
+
# TODO:
|
118
|
+
# test "compile asset with absolute path" do
|
119
|
+
# manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
120
|
+
#
|
121
|
+
# digest_path = @env['gallery.js'].path
|
122
|
+
#
|
123
|
+
# assert !File.exist?("#{@dir}/#{digest_path}")
|
124
|
+
#
|
125
|
+
# manifest.compile(fixture_path('default/gallery.js'))
|
126
|
+
#
|
127
|
+
# assert File.exist?("#{@dir}/manifest.json")
|
128
|
+
# assert File.exist?("#{@dir}/#{digest_path}")
|
129
|
+
#
|
130
|
+
# data = JSON.parse(File.read(manifest.filename))
|
131
|
+
# assert data['files'][digest_path]
|
132
|
+
# assert_equal digest_path, data['assets']['gallery.js']
|
133
|
+
# end
|
134
|
+
|
135
|
+
test "compile multiple assets" do
|
136
|
+
file 'application.js', <<-JS
|
137
|
+
console.log(1);
|
138
|
+
JS
|
139
|
+
|
140
|
+
file 'gallery.css', <<-CSS
|
141
|
+
* { color: green }
|
142
|
+
CSS
|
143
|
+
|
144
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
145
|
+
|
146
|
+
app_digest_path = @env.find_export('application.js').path
|
147
|
+
gallery_digest_path = @env.find_export('gallery.css').path
|
148
|
+
|
149
|
+
assert !File.exist?("#{@dir}/#{app_digest_path}")
|
150
|
+
assert !File.exist?("#{@dir}/#{gallery_digest_path}")
|
151
|
+
|
152
|
+
manifest.compile('application.js', 'gallery.css')
|
153
|
+
|
154
|
+
assert File.exist?("#{@dir}/manifest.json")
|
155
|
+
puts app_digest_path
|
156
|
+
puts Dir.glob(File.join(@dir, '**/*'))
|
157
|
+
assert File.exist?("#{@dir}/#{app_digest_path}")
|
158
|
+
assert File.exist?("#{@dir}/#{gallery_digest_path}")
|
159
|
+
|
160
|
+
data = JSON.parse(File.read(manifest.filename))
|
161
|
+
assert data['application.js']
|
162
|
+
assert data['gallery.css']
|
163
|
+
assert_equal app_digest_path, data['application.js']['path']
|
164
|
+
assert_equal gallery_digest_path, data['gallery.css']['path']
|
165
|
+
end
|
166
|
+
|
167
|
+
# TODO:
|
168
|
+
# test "compile with transformed asset" do
|
169
|
+
# assert svg_digest_path = @env['logo.svg'].path
|
170
|
+
# assert png_digest_path = @env['logo.png'].path
|
171
|
+
#
|
172
|
+
# assert !File.exist?("#{@dir}/#{svg_digest_path}")
|
173
|
+
# assert !File.exist?("#{@dir}/#{png_digest_path}")
|
174
|
+
#
|
175
|
+
# manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
176
|
+
# manifest.compile('logo.svg', 'logo.png')
|
177
|
+
#
|
178
|
+
# assert File.exist?("#{@dir}/manifest.json")
|
179
|
+
# assert File.exist?("#{@dir}/#{svg_digest_path}")
|
180
|
+
# assert File.exist?("#{@dir}/#{png_digest_path}")
|
181
|
+
#
|
182
|
+
# data = JSON.parse(File.read(manifest.filename))
|
183
|
+
# assert data['files'][svg_digest_path]
|
184
|
+
# assert data['files'][png_digest_path]
|
185
|
+
# assert_equal svg_digest_path, data['assets']['logo.svg']
|
186
|
+
# assert_equal png_digest_path, data['assets']['logo.png']
|
187
|
+
# end
|
188
|
+
|
189
|
+
# TODO:
|
190
|
+
# test "compile asset with links" do
|
191
|
+
# manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
192
|
+
#
|
193
|
+
# main_digest_path = @env['gallery-link.js'].path
|
194
|
+
# dep_digest_path = @env['gallery.js'].path
|
195
|
+
#
|
196
|
+
# assert !File.exist?("#{@dir}/#{main_digest_path}")
|
197
|
+
# assert !File.exist?("#{@dir}/#{dep_digest_path}")
|
198
|
+
#
|
199
|
+
# manifest.compile('gallery-link.js')
|
200
|
+
# assert File.directory?(manifest.directory)
|
201
|
+
# assert File.file?(manifest.filename)
|
202
|
+
#
|
203
|
+
# assert File.exist?("#{@dir}/manifest.json")
|
204
|
+
# assert File.exist?("#{@dir}/#{main_digest_path}")
|
205
|
+
# assert File.exist?("#{@dir}/#{dep_digest_path}")
|
206
|
+
#
|
207
|
+
# data = JSON.parse(File.read(manifest.filename))
|
208
|
+
# assert data['files'][main_digest_path]
|
209
|
+
# assert data['files'][dep_digest_path]
|
210
|
+
# assert_equal "gallery-link.js", data['files'][main_digest_path]['logical_path']
|
211
|
+
# assert_equal "gallery.js", data['files'][dep_digest_path]['logical_path']
|
212
|
+
# assert_equal main_digest_path, data['assets']['gallery-link.js']
|
213
|
+
# assert_equal dep_digest_path, data['assets']['gallery.js']
|
214
|
+
# end
|
215
|
+
|
216
|
+
# TODO:
|
217
|
+
# test "compile nested asset with links" do
|
218
|
+
# manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
219
|
+
#
|
220
|
+
# main_digest_path = @env['explore-link.js'].path
|
221
|
+
# dep_digest_path = @env['gallery-link.js'].path
|
222
|
+
# subdep_digest_path = @env['gallery.js'].path
|
223
|
+
#
|
224
|
+
# assert !File.exist?("#{@dir}/#{main_digest_path}")
|
225
|
+
# assert !File.exist?("#{@dir}/#{dep_digest_path}")
|
226
|
+
# assert !File.exist?("#{@dir}/#{subdep_digest_path}")
|
227
|
+
#
|
228
|
+
# manifest.compile('explore-link.js')
|
229
|
+
# assert File.directory?(manifest.directory)
|
230
|
+
# assert File.file?(manifest.filename)
|
231
|
+
#
|
232
|
+
# assert File.exist?("#{@dir}/manifest.json")
|
233
|
+
# assert File.exist?("#{@dir}/#{main_digest_path}")
|
234
|
+
# assert File.exist?("#{@dir}/#{dep_digest_path}")
|
235
|
+
# assert File.exist?("#{@dir}/#{subdep_digest_path}")
|
236
|
+
#
|
237
|
+
# data = JSON.parse(File.read(manifest.filename))
|
238
|
+
# assert data['files'][main_digest_path]
|
239
|
+
# assert data['files'][dep_digest_path]
|
240
|
+
# assert data['files'][subdep_digest_path]
|
241
|
+
# assert_equal "explore-link.js", data['files'][main_digest_path]['logical_path']
|
242
|
+
# assert_equal "gallery-link.js", data['files'][dep_digest_path]['logical_path']
|
243
|
+
# assert_equal "gallery.js", data['files'][subdep_digest_path]['logical_path']
|
244
|
+
# assert_equal main_digest_path, data['assets']['explore-link.js']
|
245
|
+
# assert_equal dep_digest_path, data['assets']['gallery-link.js']
|
246
|
+
# assert_equal subdep_digest_path, data['assets']['gallery.js']
|
247
|
+
# end
|
248
|
+
|
249
|
+
test "recompile asset" do
|
250
|
+
file 'application.js', "console.log(1);"
|
251
|
+
|
252
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
253
|
+
|
254
|
+
digest_path = @env['application.js'].path
|
255
|
+
assert !File.exist?("#{@dir}/#{digest_path}"), Dir["#{@dir}/*"].inspect
|
256
|
+
|
257
|
+
manifest.compile('application.js')
|
258
|
+
|
259
|
+
assert File.exist?("#{@dir}/manifest.json")
|
260
|
+
assert File.exist?("#{@dir}/#{digest_path}")
|
261
|
+
|
262
|
+
data = JSON.parse(File.read(manifest.filename))
|
263
|
+
assert data['application.js']
|
264
|
+
assert_equal digest_path, data['application.js']['path']
|
265
|
+
|
266
|
+
File.write(File.join(@path, 'application.js'), "console.log(2);")
|
267
|
+
|
268
|
+
# mtime = Time.now + 1
|
269
|
+
# File.utime(mtime, mtime, filename)
|
270
|
+
new_digest_path = @env['application.js'].path
|
271
|
+
assert_not_equal new_digest_path, digest_path
|
272
|
+
|
273
|
+
manifest.compile('application.js')
|
274
|
+
|
275
|
+
assert File.exist?("#{@dir}/manifest.json")
|
276
|
+
assert File.exist?("#{@dir}/#{digest_path}")
|
277
|
+
assert File.exist?("#{@dir}/#{new_digest_path}")
|
278
|
+
|
279
|
+
data = JSON.parse(File.read(manifest.filename))
|
280
|
+
assert data['application.js']
|
281
|
+
assert_equal new_digest_path, data['application.js']['path']
|
282
|
+
end
|
283
|
+
|
284
|
+
test "test manifest does not exist" do
|
285
|
+
file 'application.js', "console.log(1);"
|
286
|
+
|
287
|
+
assert !File.exist?("#{@dir}/manifest.json")
|
288
|
+
|
289
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
290
|
+
manifest.compile('application.js')
|
291
|
+
|
292
|
+
assert File.exist?("#{@dir}/manifest.json")
|
293
|
+
data = JSON.parse(File.read(manifest.filename))
|
294
|
+
assert data['application.js']
|
295
|
+
end
|
296
|
+
|
297
|
+
test "test blank manifest" do
|
298
|
+
file 'application.js', "console.log(1);"
|
299
|
+
|
300
|
+
assert !File.exist?("#{@dir}/manifest.json")
|
301
|
+
|
302
|
+
FileUtils.mkdir_p(@dir)
|
303
|
+
File.write("#{@dir}/manifest.json", '{}')
|
304
|
+
assert_equal "{}", File.read("#{@dir}/manifest.json")
|
305
|
+
|
306
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
307
|
+
manifest.compile('application.js')
|
308
|
+
|
309
|
+
assert File.exist?("#{@dir}/manifest.json")
|
310
|
+
data = JSON.parse(File.read(manifest.filename))
|
311
|
+
assert data['application.js']
|
312
|
+
end
|
313
|
+
|
314
|
+
test "test skip invalid manifest" do
|
315
|
+
file 'application.js', "console.log(1);"
|
316
|
+
|
317
|
+
assert !File.exist?("#{@dir}/manifest.json")
|
318
|
+
|
319
|
+
FileUtils.mkdir_p(@dir)
|
320
|
+
File.write("#{@dir}/manifest.json", "not valid json;")
|
321
|
+
assert_equal "not valid json;", File.read("#{@dir}/manifest.json")
|
322
|
+
|
323
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
324
|
+
manifest.compile('application.js')
|
325
|
+
|
326
|
+
assert File.exist?("#{@dir}/manifest.json")
|
327
|
+
data = JSON.parse(File.read(manifest.filename))
|
328
|
+
assert data['application.js']
|
329
|
+
end
|
330
|
+
|
331
|
+
test "nil environment raises compilation error" do
|
332
|
+
assert !File.exist?("#{@dir}/manifest.json")
|
333
|
+
|
334
|
+
manifest = Condenser::Manifest.new(nil, File.join(@dir, 'manifest.json'))
|
335
|
+
assert_raises Condenser::Error do
|
336
|
+
manifest.compile('application.js')
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
test "no environment raises compilation error" do
|
341
|
+
assert !File.exist?("#{@dir}/manifest.json")
|
342
|
+
|
343
|
+
manifest = Condenser::Manifest.new(File.join(@dir, 'manifest.json'))
|
344
|
+
assert_raises Condenser::Error do
|
345
|
+
manifest.compile('application.js')
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
# TODO:
|
350
|
+
# test "find_sources with environment" do
|
351
|
+
# manifest = Sprockets::Manifest.new(@env, @dir)
|
352
|
+
#
|
353
|
+
# result = manifest.find_sources("mobile/a.js", "mobile/b.js")
|
354
|
+
# assert_equal ["var A;\n", "var B;\n"], result.to_a.sort
|
355
|
+
#
|
356
|
+
# result = manifest.find_sources("not_existent.js", "also_not_existent.js")
|
357
|
+
# assert_equal [], result.to_a
|
358
|
+
#
|
359
|
+
# result = manifest.find_sources("mobile/a.js", "also_not_existent.js")
|
360
|
+
# assert_equal ["var A;\n"], result.to_a
|
361
|
+
# end
|
362
|
+
|
363
|
+
# TODO:
|
364
|
+
# test "find_sources without environment" do
|
365
|
+
# manifest = Sprockets::Manifest.new(@env, @dir)
|
366
|
+
# manifest.compile('mobile/a.js', 'mobile/b.js')
|
367
|
+
#
|
368
|
+
# manifest = Sprockets::Manifest.new(nil, @dir)
|
369
|
+
#
|
370
|
+
# result = manifest.find_sources("mobile/a.js", "mobile/b.js")
|
371
|
+
# assert_equal ["var A;\n", "var B;\n"], result.to_a
|
372
|
+
#
|
373
|
+
# result = manifest.find_sources("not_existent.js", "also_not_existent.js")
|
374
|
+
# assert_equal [], result.to_a
|
375
|
+
#
|
376
|
+
# result = manifest.find_sources("mobile/a.js", "also_not_existent.js")
|
377
|
+
# assert_equal ["var A;\n"], result.to_a
|
378
|
+
# end
|
379
|
+
|
380
|
+
test "compress non-binary assets" do
|
381
|
+
file 'gallery.css', 'x'
|
382
|
+
file 'application.js', 'x'
|
383
|
+
file 'logo.svg', 'x'
|
384
|
+
file 'favicon.ico', 'x'
|
385
|
+
|
386
|
+
manifest = Condenser::Manifest.new(@env, @dir)
|
387
|
+
%W{ gallery.css application.js logo.svg favicon.ico }.each do |file_name|
|
388
|
+
original_path = @env[file_name].path
|
389
|
+
manifest.compile(file_name)
|
390
|
+
assert File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to generate gzipped file: '#{original_path}.gz' but it did not"
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
# TODO:
|
395
|
+
# test "writes gzip files even if files were already on disk" do
|
396
|
+
# @env.gzip = false
|
397
|
+
# manifest = Sprockets::Manifest.new(@env, @dir)
|
398
|
+
# files = %W{ gallery.css application.js logo.svg favicon.ico}
|
399
|
+
# files.each do |file_name|
|
400
|
+
# original_path = @env[file_name].path
|
401
|
+
# manifest.compile(file_name)
|
402
|
+
# assert File.exist?("#{@dir}/#{original_path}"), "Expecting '#{@dir}/#{original_path}' to exist but did not"
|
403
|
+
# end
|
404
|
+
#
|
405
|
+
# @env.gzip = true
|
406
|
+
# files.each do |file_name|
|
407
|
+
# original_path = @env[file_name].path
|
408
|
+
# manifest.compile(file_name)
|
409
|
+
# assert File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to generate gzipped file: '#{original_path}.gz' but it did not"
|
410
|
+
# end
|
411
|
+
# end
|
412
|
+
|
413
|
+
# TODO:
|
414
|
+
# test "disable file gzip" do
|
415
|
+
# @env.gzip = false
|
416
|
+
# manifest = Sprockets::Manifest.new(@env, @dir)
|
417
|
+
# %W{ gallery.css application.js logo.svg favicon.ico }.each do |file_name|
|
418
|
+
# original_path = @env[file_name].path
|
419
|
+
# manifest.compile(file_name)
|
420
|
+
# refute File.exist?("#{@dir}/#{original_path}.gz"), "Expecting '#{original_path}' to not generate gzipped file: '#{original_path}.gz' but it did"
|
421
|
+
# end
|
422
|
+
# end
|
423
|
+
|
424
|
+
test "do not compress binary assets" do
|
425
|
+
file 'blank.gif', Random.new.bytes(128)
|
426
|
+
|
427
|
+
manifest = Condenser::Manifest.new(@env, @path)
|
428
|
+
%W{ blank.gif }.each do |file_name|
|
429
|
+
original_path = @env[file_name].path
|
430
|
+
manifest.compile(file_name)
|
431
|
+
refute File.exist?("#{@path}/#{original_path}.gz"), "Expecting '#{original_path}' to not generate gzipped file: '#{original_path}.gz' but it did"
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
# TODO:
|
436
|
+
# test 'raises exception when gzip fails' do
|
437
|
+
# manifest = Sprockets::Manifest.new(@env, @dir)
|
438
|
+
# Zlib::GzipWriter.stub(:new, -> (io, level) { fail 'kaboom' }) do
|
439
|
+
# ex = assert_raises(RuntimeError) { manifest.compile('application.js') }
|
440
|
+
# assert_equal 'kaboom', ex.message
|
441
|
+
# end
|
442
|
+
# end
|
443
|
+
#
|
444
|
+
# # Sleep duration to context switch between concurrent threads.
|
445
|
+
# CONTEXT_SWITCH_DURATION = 0.1
|
446
|
+
#
|
447
|
+
# # Record Exporter sequence with a delay to test concurrency.
|
448
|
+
# class SlowExporter < Sprockets::Exporters::Base
|
449
|
+
# class << self
|
450
|
+
# attr_accessor :seq
|
451
|
+
# end
|
452
|
+
#
|
453
|
+
# def call
|
454
|
+
# SlowExporter.seq << '0'
|
455
|
+
# sleep CONTEXT_SWITCH_DURATION
|
456
|
+
# SlowExporter.seq << '1'
|
457
|
+
# end
|
458
|
+
# end
|
459
|
+
#
|
460
|
+
# class SlowExporter2 < SlowExporter
|
461
|
+
# end
|
462
|
+
#
|
463
|
+
# test 'concurrent exporting' do
|
464
|
+
# # Register 2 exporters and compile 2 files to ensure that
|
465
|
+
# # all 4 exporting tasks run concurrently.
|
466
|
+
# SlowExporter.seq = []
|
467
|
+
# @env.register_exporter 'image/png',SlowExporter
|
468
|
+
# @env.register_exporter 'image/png',SlowExporter2
|
469
|
+
# Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
|
470
|
+
# refute_equal %w(0 1 0 1 0 1 0 1), SlowExporter.seq
|
471
|
+
# end
|
472
|
+
#
|
473
|
+
# test 'sequential exporting' do
|
474
|
+
# @env.export_concurrent = false
|
475
|
+
# SlowExporter.seq = []
|
476
|
+
# @env.register_exporter 'image/png',SlowExporter
|
477
|
+
# @env.register_exporter 'image/png',SlowExporter2
|
478
|
+
# Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
|
479
|
+
# assert_equal %w(0 1 0 1 0 1 0 1), SlowExporter.seq
|
480
|
+
# end
|
481
|
+
#
|
482
|
+
# # Record Processor sequence with a delay to test concurrency.
|
483
|
+
# class SlowProcessor
|
484
|
+
# attr_reader :seq
|
485
|
+
#
|
486
|
+
# def initialize
|
487
|
+
# @seq = []
|
488
|
+
# end
|
489
|
+
#
|
490
|
+
# def call(_)
|
491
|
+
# seq << '0'
|
492
|
+
# sleep CONTEXT_SWITCH_DURATION
|
493
|
+
# seq << '1'
|
494
|
+
# nil
|
495
|
+
# end
|
496
|
+
# end
|
497
|
+
#
|
498
|
+
# test 'concurrent processing' do
|
499
|
+
# processor = SlowProcessor.new
|
500
|
+
# @env.register_postprocessor 'image/png', processor
|
501
|
+
# Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
|
502
|
+
# refute_equal %w(0 1 0 1), processor.seq
|
503
|
+
# end
|
504
|
+
#
|
505
|
+
# test 'sequential processing' do
|
506
|
+
# @env.export_concurrent = false
|
507
|
+
# processor = SlowProcessor.new
|
508
|
+
# @env.register_postprocessor 'image/png', processor
|
509
|
+
# Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
|
510
|
+
# assert_equal %w(0 1 0 1), processor.seq
|
511
|
+
# end
|
512
|
+
|
513
|
+
end
|