condenser 1.4 → 1.5.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 +4 -4
- data/lib/condenser/asset.rb +55 -8
- data/lib/condenser/build_cache.rb +2 -0
- data/lib/condenser/cache/file_store.rb +1 -0
- data/lib/condenser/cache/memory_store.rb +1 -0
- data/lib/condenser/cache/null_store.rb +1 -0
- data/lib/condenser/cache_store.rb +1 -0
- data/lib/condenser/context.rb +1 -0
- data/lib/condenser/encoding_utils.rb +2 -0
- data/lib/condenser/environment.rb +2 -0
- data/lib/condenser/errors.rb +2 -0
- data/lib/condenser/export.rb +11 -6
- data/lib/condenser/helpers/parse_helpers.rb +19 -4
- data/lib/condenser/manifest.rb +6 -4
- data/lib/condenser/minifiers/sass_minifier.rb +2 -0
- data/lib/condenser/minifiers/terser_minifier.rb +2 -0
- data/lib/condenser/minifiers/uglify_minifier.rb +2 -0
- data/lib/condenser/pipeline.rb +2 -0
- data/lib/condenser/processors/babel_processor.rb +11 -2
- data/lib/condenser/processors/css_media_combiner_processor.rb +7 -5
- data/lib/condenser/processors/js_analyzer.rb +109 -37
- data/lib/condenser/processors/node_processor.rb +2 -0
- data/lib/condenser/processors/purgecss_processor.rb +2 -0
- data/lib/condenser/processors/rollup_processor.rb +289 -136
- data/lib/condenser/resolve.rb +15 -7
- data/lib/condenser/server.rb +22 -20
- data/lib/condenser/templating_engine/ejs.rb +2 -0
- data/lib/condenser/templating_engine/erb.rb +2 -0
- data/lib/condenser/transformers/dart_sass_transformer.rb +5 -3
- data/lib/condenser/transformers/jst_transformer.rb +2 -0
- data/lib/condenser/transformers/sass/functions.rb +2 -0
- data/lib/condenser/transformers/sass/importer.rb +2 -0
- data/lib/condenser/transformers/sass.rb +2 -0
- data/lib/condenser/transformers/sass_transformer.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/base.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/tag.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/template.rb +3 -1
- data/lib/condenser/transformers/svg_transformer/template_error.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/value.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/var_generator.rb +2 -0
- data/lib/condenser/transformers/svg_transformer.rb +2 -0
- data/lib/condenser/utils.rb +2 -0
- data/lib/condenser/version.rb +3 -1
- data/lib/condenser/writers/brotli_writer.rb +2 -0
- data/lib/condenser/writers/file_writer.rb +2 -0
- data/lib/condenser/writers/zlib_writer.rb +2 -0
- data/lib/condenser.rb +2 -0
- data/lib/rake/condensertask.rb +2 -0
- data/test/cache_test.rb +14 -14
- data/test/manifest_test.rb +17 -2
- data/test/postprocessors/css_media_combiner_test.rb +9 -12
- data/test/preprocessor/babel_test.rb +843 -327
- data/test/preprocessor/js_analyzer_test.rb +174 -5
- data/test/processors/rollup/dynamic_import_test.rb +358 -0
- data/test/processors/rollup_test.rb +37 -56
- data/test/resolve_test.rb +4 -9
- data/test/server_test.rb +6 -5
- data/test/transformers/dart_scss_test.rb +2 -2
- data/test/transformers/scss_test.rb +2 -2
- metadata +6 -11
- data/lib/condenser/minifiers/package-lock.json +0 -25
data/lib/condenser/server.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'set'
|
2
4
|
require 'time'
|
3
5
|
require 'rack/utils'
|
@@ -67,7 +69,7 @@ class Condenser
|
|
67
69
|
end
|
68
70
|
|
69
71
|
# Look up the asset.
|
70
|
-
asset = @condenser.find_export(path)
|
72
|
+
asset = @condenser.find_export(path, npm: true)
|
71
73
|
if asset.nil?
|
72
74
|
status = :not_found
|
73
75
|
elsif fingerprint && asset.etag != fingerprint
|
@@ -142,39 +144,39 @@ class Condenser
|
|
142
144
|
# Returns a 400 Forbidden response tuple
|
143
145
|
def bad_request_response(env)
|
144
146
|
if head_request?(env)
|
145
|
-
[ 400, { "
|
147
|
+
[ 400, { "content-type" => "text/plain", "content-length" => "0" }, [] ]
|
146
148
|
else
|
147
|
-
[ 400, { "
|
149
|
+
[ 400, { "content-type" => "text/plain", "content-length" => "11" }, [ "Bad Request" ] ]
|
148
150
|
end
|
149
151
|
end
|
150
152
|
|
151
153
|
# Returns a 403 Forbidden response tuple
|
152
154
|
def forbidden_response(env)
|
153
155
|
if head_request?(env)
|
154
|
-
[ 403, { "
|
156
|
+
[ 403, { "content-type" => "text/plain", "content-length" => "0" }, [] ]
|
155
157
|
else
|
156
|
-
[ 403, { "
|
158
|
+
[ 403, { "content-type" => "text/plain", "content-length" => "9" }, [ "Forbidden" ] ]
|
157
159
|
end
|
158
160
|
end
|
159
161
|
|
160
162
|
# Returns a 404 Not Found response tuple
|
161
163
|
def not_found_response(env)
|
162
164
|
if head_request?(env)
|
163
|
-
[ 404, { "
|
165
|
+
[ 404, { "content-type" => "text/plain", "content-length" => "0", "x-cascade" => "pass" }, [] ]
|
164
166
|
else
|
165
|
-
[ 404, { "
|
167
|
+
[ 404, { "content-type" => "text/plain", "content-length" => "9", "x-cascade" => "pass" }, [ "Not found" ] ]
|
166
168
|
end
|
167
169
|
end
|
168
170
|
|
169
171
|
def method_not_allowed_response
|
170
|
-
[ 405, { "
|
172
|
+
[ 405, { "content-type" => "text/plain", "content-length" => "18" }, [ "Method Not Allowed" ] ]
|
171
173
|
end
|
172
174
|
|
173
175
|
def precondition_failed_response(env)
|
174
176
|
if head_request?(env)
|
175
|
-
[ 412, { "
|
177
|
+
[ 412, { "content-type" => "text/plain", "content-length" => "0", "x-cascade" => "pass" }, [] ]
|
176
178
|
else
|
177
|
-
[ 412, { "
|
179
|
+
[ 412, { "content-type" => "text/plain", "content-length" => "19", "x-cascade" => "pass" }, [ "Precondition Failed" ] ]
|
178
180
|
end
|
179
181
|
end
|
180
182
|
|
@@ -183,7 +185,7 @@ class Condenser
|
|
183
185
|
def javascript_exception_response(exception)
|
184
186
|
err = "#{exception.class.name}: #{exception.message}\n (in #{exception.backtrace[0]})"
|
185
187
|
body = "throw Error(#{err.inspect})"
|
186
|
-
[ 200, { "
|
188
|
+
[ 200, { "content-type" => "application/javascript", "content-length" => body.bytesize.to_s }, [ body ] ]
|
187
189
|
end
|
188
190
|
|
189
191
|
# Returns a CSS response that hides all elements on the page and
|
@@ -236,7 +238,7 @@ class Condenser
|
|
236
238
|
}
|
237
239
|
CSS
|
238
240
|
|
239
|
-
[ 200, { "
|
241
|
+
[ 200, { "content-type" => "text/css; charset=utf-8", "content-length" => body.bytesize.to_s }, [ body ] ]
|
240
242
|
end
|
241
243
|
|
242
244
|
# Escape special characters for use inside a CSS content("...") string
|
@@ -252,18 +254,18 @@ class Condenser
|
|
252
254
|
headers = {}
|
253
255
|
|
254
256
|
# Set caching headers
|
255
|
-
headers["
|
256
|
-
headers["
|
257
|
+
headers["cache-control"] = String.new("public")
|
258
|
+
headers["etag"] = %("#{etag}")
|
257
259
|
|
258
260
|
# If the request url contains a fingerprint, set a long
|
259
261
|
# expires on the response
|
260
262
|
if path_fingerprint(env["PATH_INFO"])
|
261
|
-
headers["
|
263
|
+
headers["cache-control"] << ", max-age=31536000, immutable"
|
262
264
|
|
263
265
|
# Otherwise set `must-revalidate` since the asset could be modified.
|
264
266
|
else
|
265
|
-
headers["
|
266
|
-
headers["
|
267
|
+
headers["cache-control"] << ", must-revalidate"
|
268
|
+
headers["vary"] = "Accept-Encoding"
|
267
269
|
end
|
268
270
|
|
269
271
|
headers
|
@@ -273,10 +275,10 @@ class Condenser
|
|
273
275
|
headers = {}
|
274
276
|
|
275
277
|
# Set content length header
|
276
|
-
headers["
|
278
|
+
headers["content-length"] = length.to_s
|
277
279
|
|
278
280
|
if asset&.sourcemap
|
279
|
-
headers['
|
281
|
+
headers['sourcemap'] = env['SCRIPT_NAME'] + env['PATH_INFO'] + '.map'
|
280
282
|
end
|
281
283
|
|
282
284
|
# Set content type header
|
@@ -285,7 +287,7 @@ class Condenser
|
|
285
287
|
if type.start_with?("text/") && asset.charset
|
286
288
|
type += "; charset=#{asset.charset}"
|
287
289
|
end
|
288
|
-
headers["
|
290
|
+
headers["content-type"] = type
|
289
291
|
end
|
290
292
|
|
291
293
|
headers.merge(cache_headers(env, asset.etag))
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Condenser::DartSassTransformer < Condenser::NodeProcessor
|
2
4
|
|
3
5
|
@@helper_methods = Set.new
|
@@ -196,14 +198,14 @@ class Condenser::DartSassTransformer < Condenser::NodeProcessor
|
|
196
198
|
|
197
199
|
def exec_runtime(script)
|
198
200
|
io = IO.popen([binary, '-e', script], 'r+')
|
199
|
-
buffer =
|
201
|
+
buffer = String.new
|
200
202
|
result = nil
|
201
203
|
|
202
204
|
begin
|
203
205
|
while IO.select([io]) && io_read = io.read_nonblock(1_024)
|
204
206
|
buffer << io_read
|
205
207
|
messages = buffer.split("\n\n")
|
206
|
-
buffer = buffer.end_with?("\n\n") ?
|
208
|
+
buffer = buffer.end_with?("\n\n") ? String.new : messages.pop
|
207
209
|
|
208
210
|
messages.each do |message|
|
209
211
|
message = JSON.parse(message)
|
@@ -218,7 +220,7 @@ class Condenser::DartSassTransformer < Condenser::NodeProcessor
|
|
218
220
|
|
219
221
|
if importee.end_with?('*')
|
220
222
|
@context.depend_on(importee)
|
221
|
-
code =
|
223
|
+
code = String.new
|
222
224
|
resolve(importee, importer).each do |f, i|
|
223
225
|
code << "@import '#{f.filename}';\n"
|
224
226
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Condenser::SVGTransformer::Template
|
2
4
|
|
3
5
|
include Condenser::ParseHelpers
|
@@ -107,7 +109,7 @@ class Condenser::SVGTransformer::Template
|
|
107
109
|
@tree.last.attrs << { key => matched }
|
108
110
|
end
|
109
111
|
when :tag_attr_value_double_quoted
|
110
|
-
quoted_value =
|
112
|
+
quoted_value = String.new
|
111
113
|
scan_until(/"/)
|
112
114
|
quoted_value << pre_match if !pre_match.strip.empty?
|
113
115
|
rewind(1)
|
data/lib/condenser/utils.rb
CHANGED
data/lib/condenser/version.rb
CHANGED
data/lib/condenser.rb
CHANGED
data/lib/rake/condensertask.rb
CHANGED
data/test/cache_test.rb
CHANGED
@@ -86,13 +86,13 @@ class CacheTest < ActiveSupport::TestCase
|
|
86
86
|
}
|
87
87
|
JS
|
88
88
|
|
89
|
-
assert_exported_file 'main.js', 'application/javascript', <<~
|
90
|
-
|
91
|
-
|
89
|
+
assert_exported_file 'main.js', 'application/javascript', <<~JS
|
90
|
+
function cube(c){return c*c}console.log(cube(5));
|
91
|
+
JS
|
92
92
|
|
93
|
-
assert_exported_file 'main.js', 'application/javascript', <<~
|
94
|
-
|
95
|
-
|
93
|
+
assert_exported_file 'main.js', 'application/javascript', <<~JS
|
94
|
+
function cube(c){return c*c}console.log(cube(5));
|
95
|
+
JS
|
96
96
|
|
97
97
|
file 'math.js', <<-JS
|
98
98
|
export function cube ( x ) {
|
@@ -101,7 +101,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
101
101
|
JS
|
102
102
|
|
103
103
|
assert_exported_file 'main.js', 'application/javascript', <<~CSS
|
104
|
-
|
104
|
+
function cube(c){return c*c*c}console.log(cube(5));
|
105
105
|
CSS
|
106
106
|
end
|
107
107
|
|
@@ -281,7 +281,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
281
281
|
JS
|
282
282
|
|
283
283
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
284
|
-
console.log("
|
284
|
+
function b(){console.log("b")}console.log("a"),b();
|
285
285
|
JS
|
286
286
|
|
287
287
|
file 'b.js', <<~JS
|
@@ -289,7 +289,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
289
289
|
JS
|
290
290
|
|
291
291
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
292
|
-
console.log("
|
292
|
+
function b(){console.log("c")}console.log("a"),b();
|
293
293
|
JS
|
294
294
|
end
|
295
295
|
|
@@ -343,7 +343,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
343
343
|
JS
|
344
344
|
|
345
345
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
346
|
-
console.log("
|
346
|
+
function b(){console.log("b")}function d(){console.log("d")}function c(){console.log("c"),d()}console.log("a"),b(),c();
|
347
347
|
JS
|
348
348
|
|
349
349
|
file 'd.js', "export default function e () { console.log('e'); }\n"
|
@@ -359,7 +359,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
359
359
|
pd["#{@path}/d.js"].expects(:<<).with { |a| a.source_file == "#{@path}/d.js" }.once
|
360
360
|
|
361
361
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
362
|
-
console.log("
|
362
|
+
function b(){console.log("b")}function e(){console.log("e")}function c(){console.log("c"),e()}console.log("a"),b(),c();
|
363
363
|
JS
|
364
364
|
end
|
365
365
|
|
@@ -394,14 +394,14 @@ class CacheTest < ActiveSupport::TestCase
|
|
394
394
|
|
395
395
|
# Set the cache
|
396
396
|
env1 = Condenser.new(base1, logger: Logger.new(STDOUT, level: :debug), base: base1, npm_path: @npm_dir, cache: Condenser::Cache::FileStore.new(cachepath))
|
397
|
-
assert_equal 'console.log("
|
397
|
+
assert_equal 'function c(){console.log("c")}function b(){console.log("b"),c()}console.log("a"),b();', env1.find('test/a.js').export.source
|
398
398
|
|
399
399
|
# Poison the cache
|
400
400
|
env2 = Condenser.new(base2, logger: Logger.new(STDOUT, level: :debug), base: base2, npm_path: @npm_dir, cache: Condenser::Cache::FileStore.new(cachepath))
|
401
|
-
assert_equal 'console.log("
|
401
|
+
assert_equal 'function c(){console.log("d")}function b(){console.log("b"),c()}console.log("a"),b();', env2.find('test/a.js').export.source
|
402
402
|
|
403
403
|
# Fails to find dependency change because cache is missing the dependency
|
404
404
|
env3 = Condenser.new(base3, logger: Logger.new(STDOUT, level: :debug), base: base3, npm_path: @npm_dir, cache: Condenser::Cache::FileStore.new(cachepath))
|
405
|
-
assert_equal 'console.log("
|
405
|
+
assert_equal 'function c(){console.log("e")}function b(){console.log("b"),c()}console.log("a"),b();', env3.find('test/a.js').export.source
|
406
406
|
end
|
407
407
|
end
|
data/test/manifest_test.rb
CHANGED
@@ -62,8 +62,8 @@ class ManifestTest < ActiveSupport::TestCase
|
|
62
62
|
|
63
63
|
data = JSON.parse(File.read(manifest.filename))
|
64
64
|
assert data['application.js']
|
65
|
-
|
66
|
-
assert_equal
|
65
|
+
assert_equal asset.path, data['application.js']['path']
|
66
|
+
assert_equal 15, data['application.js']['size']
|
67
67
|
end
|
68
68
|
|
69
69
|
test "compile asset dependencies includes the dependencies" do
|
@@ -541,4 +541,19 @@ class ManifestTest < ActiveSupport::TestCase
|
|
541
541
|
# assert_equal %w(0 1 0 1), processor.seq
|
542
542
|
# end
|
543
543
|
|
544
|
+
test "javascript types are in the manifest" do
|
545
|
+
file 'application.js', <<-JS
|
546
|
+
console.log(1);
|
547
|
+
JS
|
548
|
+
|
549
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
550
|
+
manifest.compile('application.js')
|
551
|
+
assert File.directory?(manifest.dir)
|
552
|
+
assert File.file?(manifest.filename)
|
553
|
+
assert File.exist?("#{@dir}/manifest.json")
|
554
|
+
|
555
|
+
data = JSON.parse(File.read(manifest.filename))
|
556
|
+
assert data['application.js']
|
557
|
+
assert_equal "module", data['application.js']['type']
|
558
|
+
end
|
544
559
|
end
|
@@ -24,7 +24,7 @@ class MediaCombinerTest < ActiveSupport::TestCase
|
|
24
24
|
display: inline;
|
25
25
|
}
|
26
26
|
}
|
27
|
-
|
27
|
+
|
28
28
|
.test2{
|
29
29
|
display: block;
|
30
30
|
}
|
@@ -35,17 +35,14 @@ class MediaCombinerTest < ActiveSupport::TestCase
|
|
35
35
|
}
|
36
36
|
CSS
|
37
37
|
|
38
|
-
assert_exported_file 'main.css', 'text/css', <<~
|
38
|
+
assert_exported_file 'main.css', 'text/css', <<~CSS
|
39
39
|
.test{
|
40
40
|
display: block;
|
41
41
|
}
|
42
42
|
|
43
|
-
|
44
|
-
|
45
43
|
.test2{
|
46
44
|
display: block;
|
47
|
-
}
|
48
|
-
@media only screen and (max-width: 100px) {
|
45
|
+
}@media only screen and (max-width: 100px) {
|
49
46
|
.test {
|
50
47
|
display: inline-block;
|
51
48
|
color: blue;
|
@@ -59,7 +56,7 @@ class MediaCombinerTest < ActiveSupport::TestCase
|
|
59
56
|
display: inline;
|
60
57
|
}
|
61
58
|
}
|
62
|
-
|
59
|
+
CSS
|
63
60
|
end
|
64
61
|
|
65
62
|
test 'single line css' do
|
@@ -67,9 +64,9 @@ class MediaCombinerTest < ActiveSupport::TestCase
|
|
67
64
|
.test{display: block;} @media only screen and (max-width: 100px) {.test {display: inline-block;}}@media only screen and (max-width: 500px) {.test {display: inline;}}.test2{display: block;}@media only screen and (max-width: 100px) {.test2 {display: inline-block;}}
|
68
65
|
CSS
|
69
66
|
|
70
|
-
assert_exported_file 'main.css', 'text/css', <<~
|
71
|
-
.test{display: block;}
|
72
|
-
|
67
|
+
assert_exported_file 'main.css', 'text/css', <<~CSS
|
68
|
+
.test{display: block;}.test2{display: block;}@media only screen and (max-width: 100px) {.test {display: inline-block;}.test2 {display: inline-block;}}@media only screen and (max-width: 500px) {.test {display: inline;}}
|
69
|
+
CSS
|
73
70
|
end
|
74
71
|
|
75
72
|
|
@@ -88,7 +85,7 @@ class MediaCombinerTest < ActiveSupport::TestCase
|
|
88
85
|
}
|
89
86
|
CSS
|
90
87
|
|
91
|
-
assert_exported_file 'main.css', 'text/css', <<~
|
88
|
+
assert_exported_file 'main.css', 'text/css', <<~CSS
|
92
89
|
.trobber {
|
93
90
|
animation: throb 1s infinite;
|
94
91
|
}
|
@@ -100,7 +97,7 @@ class MediaCombinerTest < ActiveSupport::TestCase
|
|
100
97
|
opacity: 0;
|
101
98
|
}
|
102
99
|
}
|
103
|
-
|
100
|
+
CSS
|
104
101
|
end
|
105
102
|
|
106
103
|
|