condenser 1.2 → 1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/condenser/asset.rb +69 -35
- data/lib/condenser/build_cache.rb +22 -9
- data/lib/condenser/context.rb +9 -25
- data/lib/condenser/helpers/parse_helpers.rb +8 -1
- data/lib/condenser/manifest.rb +3 -1
- data/lib/condenser/pipeline.rb +8 -3
- data/lib/condenser/processors/babel_processor.rb +9 -15
- data/lib/condenser/processors/css_media_combiner_processor.rb +81 -0
- data/lib/condenser/processors/js_analyzer.rb +41 -8
- data/lib/condenser/processors/node_processor.rb +1 -0
- data/lib/condenser/processors/purgecss_processor.rb +6 -4
- data/lib/condenser/processors/rollup_processor.rb +38 -36
- data/lib/condenser/resolve.rb +27 -6
- data/lib/condenser/templating_engine/ejs.rb +1 -1
- data/lib/condenser/transformers/dart_sass_transformer.rb +285 -0
- data/lib/condenser/transformers/jst_transformer.rb +67 -17
- data/lib/condenser/transformers/sass/functions.rb +133 -0
- data/lib/condenser/transformers/sass/importer.rb +48 -0
- data/lib/condenser/transformers/sass.rb +4 -0
- data/lib/condenser/transformers/sass_transformer.rb +124 -281
- data/lib/condenser/transformers/svg_transformer/base.rb +26 -0
- data/lib/condenser/transformers/svg_transformer/tag.rb +54 -0
- data/lib/condenser/transformers/svg_transformer/template.rb +151 -0
- data/lib/condenser/transformers/svg_transformer/template_error.rb +2 -0
- data/lib/condenser/transformers/svg_transformer/value.rb +13 -0
- data/lib/condenser/transformers/svg_transformer/var_generator.rb +10 -0
- data/lib/condenser/transformers/svg_transformer.rb +19 -0
- data/lib/condenser/version.rb +1 -1
- data/lib/condenser.rb +17 -5
- data/test/cache_test.rb +157 -18
- data/test/dependency_test.rb +51 -2
- data/test/manifest_test.rb +34 -0
- data/test/minifiers/terser_minifier_test.rb +0 -1
- data/test/minifiers/uglify_minifier_test.rb +0 -1
- data/test/postprocessors/css_media_combiner_test.rb +107 -0
- data/test/postprocessors/purgecss_test.rb +62 -0
- data/test/preprocessor/babel_test.rb +703 -298
- data/test/preprocessor/js_analyzer_test.rb +35 -2
- data/test/processors/rollup_test.rb +50 -20
- data/test/resolve_test.rb +18 -9
- data/test/server_test.rb +15 -10
- data/test/templates/ejs_test.rb +2 -11
- data/test/templates/erb_test.rb +0 -5
- data/test/test_helper.rb +8 -3
- data/test/transformers/dart_scss_test.rb +139 -0
- data/test/transformers/jst_test.rb +165 -21
- data/test/transformers/scss_test.rb +14 -0
- data/test/transformers/svg_test.rb +40 -0
- metadata +23 -6
- data/lib/condenser/transformers/sass_transformer/importer.rb +0 -50
@@ -0,0 +1,151 @@
|
|
1
|
+
class Condenser::SVGTransformer::Template
|
2
|
+
|
3
|
+
include Condenser::ParseHelpers
|
4
|
+
|
5
|
+
attr_accessor :source
|
6
|
+
|
7
|
+
START_TAGS = ['<']
|
8
|
+
CLOSE_TAGS = ['/>', '>']
|
9
|
+
VOID_ELEMENTS = ['!DOCTYPE', '?xml']
|
10
|
+
|
11
|
+
def initialize(source)
|
12
|
+
@source = source.strip
|
13
|
+
process
|
14
|
+
end
|
15
|
+
|
16
|
+
def process
|
17
|
+
seek(0)
|
18
|
+
@tree = [Condenser::SVGTransformer::Base.new]
|
19
|
+
@stack = [:str]
|
20
|
+
|
21
|
+
while !eos?
|
22
|
+
case @stack.last
|
23
|
+
when :str
|
24
|
+
scan_until(Regexp.new("(#{START_TAGS.map{|s| Regexp.escape(s) }.join('|')}|\\z)"))
|
25
|
+
if !matched.nil? && START_TAGS.include?(matched)
|
26
|
+
@stack << :tag
|
27
|
+
end
|
28
|
+
when :tag
|
29
|
+
scan_until(Regexp.new("(\\/|[^\\s>]+)"))
|
30
|
+
if matched == '/'
|
31
|
+
@stack.pop
|
32
|
+
@stack << :close_tag
|
33
|
+
else
|
34
|
+
@tree << Condenser::SVGTransformer::Tag.new(matched)
|
35
|
+
@stack << :tag_attr_key
|
36
|
+
end
|
37
|
+
when :close_tag
|
38
|
+
scan_until(Regexp.new("([^\\s>]+)"))
|
39
|
+
|
40
|
+
el = @tree.pop
|
41
|
+
if el.tag_name != matched
|
42
|
+
raise Condenser::SVGTransformer::TemplateError.new("Expected to close #{el.tag_name.inspect} tag, instead closed #{matched.inspect}\n#{cursor}")
|
43
|
+
end
|
44
|
+
if !['!DOCTYPE', '?xml'].include?(el.tag_name)
|
45
|
+
@tree.last.children << el
|
46
|
+
scan_until(Regexp.new("(#{CLOSE_TAGS.map{|s| Regexp.escape(s) }.join('|')})"))
|
47
|
+
@stack.pop
|
48
|
+
end
|
49
|
+
when :tag_attr_key
|
50
|
+
scan_until(Regexp.new("(#{CLOSE_TAGS.map{|s| Regexp.escape(s) }.join('|')}|[^\\s=>]+)"))
|
51
|
+
if CLOSE_TAGS.include?(matched)
|
52
|
+
if matched == '/>' || VOID_ELEMENTS.include?(@tree.last.tag_name)
|
53
|
+
el = @tree.pop
|
54
|
+
@tree.last.children << el
|
55
|
+
@stack.pop
|
56
|
+
@stack.pop
|
57
|
+
else
|
58
|
+
@stack << :str
|
59
|
+
end
|
60
|
+
else
|
61
|
+
key = if matched.start_with?('"') && matched.end_with?('"')
|
62
|
+
matched[1..-2]
|
63
|
+
elsif matched.start_with?('"') && matched.end_with?('"')
|
64
|
+
matched[1..-2]
|
65
|
+
else
|
66
|
+
matched
|
67
|
+
end
|
68
|
+
@tree.last.attrs << key
|
69
|
+
@stack << :tag_attr_value_tx
|
70
|
+
end
|
71
|
+
when :tag_attr_value_tx
|
72
|
+
scan_until(Regexp.new("(#{(CLOSE_TAGS).map{|s| Regexp.escape(s) }.join('|')}|=|\\S)"))
|
73
|
+
tag_key = @tree.last.attrs.pop
|
74
|
+
if CLOSE_TAGS.include?(matched)
|
75
|
+
el = @tree.last
|
76
|
+
el.attrs << tag_key
|
77
|
+
if VOID_ELEMENTS.include?(el.tag_name)
|
78
|
+
@tree.pop
|
79
|
+
@tree.last.children << el
|
80
|
+
end
|
81
|
+
@stack.pop
|
82
|
+
@stack.pop
|
83
|
+
@stack.pop
|
84
|
+
elsif matched == '='
|
85
|
+
@stack.pop
|
86
|
+
@tree.last.attrs << tag_key
|
87
|
+
@stack << :tag_attr_value
|
88
|
+
else
|
89
|
+
@stack.pop
|
90
|
+
@tree.last.attrs << tag_key
|
91
|
+
rewind(1)
|
92
|
+
end
|
93
|
+
|
94
|
+
when :tag_attr_value
|
95
|
+
scan_until(Regexp.new("(#{CLOSE_TAGS.map{|s| Regexp.escape(s) }.join('|')}|'|\"|\\S+)"))
|
96
|
+
|
97
|
+
if matched == '"'
|
98
|
+
@stack.pop
|
99
|
+
@stack << :tag_attr_value_double_quoted
|
100
|
+
elsif matched == "'"
|
101
|
+
@stack.pop
|
102
|
+
@stack << :tag_attr_value_single_quoted
|
103
|
+
else
|
104
|
+
@stack.pop
|
105
|
+
key = @tree.last.attrs.pop
|
106
|
+
@tree.last.namespace = matched if key == 'xmlns'
|
107
|
+
@tree.last.attrs << { key => matched }
|
108
|
+
end
|
109
|
+
when :tag_attr_value_double_quoted
|
110
|
+
quoted_value = ''
|
111
|
+
scan_until(/"/)
|
112
|
+
quoted_value << pre_match if !pre_match.strip.empty?
|
113
|
+
rewind(1)
|
114
|
+
|
115
|
+
quoted_value = Condenser::SVGTransformer::Value.new(quoted_value)
|
116
|
+
|
117
|
+
key = @tree.last.attrs.pop
|
118
|
+
@tree.last.namespace = quoted_value if key == 'xmlns'
|
119
|
+
if @tree.last.attrs.last.is_a?(Hash) && !@tree.last.attrs.last.has_key?(key)
|
120
|
+
@tree.last.attrs.last[key] = quoted_value
|
121
|
+
else
|
122
|
+
@tree.last.attrs << { key => quoted_value }
|
123
|
+
end
|
124
|
+
scan_until(/\"/)
|
125
|
+
@stack.pop
|
126
|
+
when :tag_attr_value_single_quoted
|
127
|
+
quoted_value = ''
|
128
|
+
scan_until(/(')/)
|
129
|
+
quoted_value << pre_match if !pre_match.strip.empty?
|
130
|
+
rewind(1)
|
131
|
+
|
132
|
+
quoted_value = Condenser::SVGTransformer::Value.new(quoted_value)
|
133
|
+
|
134
|
+
key = @tree.last.attrs.pop
|
135
|
+
@tree.last.namespace = quoted_value if key == 'xmlns'
|
136
|
+
if @tree.last.attrs.last.is_a?(Hash) && !@tree.last.attrs.last.has_key?(key)
|
137
|
+
@tree.last.attrs.last[key] = quoted_value
|
138
|
+
else
|
139
|
+
@tree.last.attrs << { key => quoted_value }
|
140
|
+
end
|
141
|
+
scan_until(/\'/)
|
142
|
+
@stack.pop
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def to_module
|
148
|
+
@tree.first.to_module
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Condenser::SVGTransformer
|
2
|
+
|
3
|
+
autoload :Base, File.expand_path('../svg_transformer/base', __FILE__)
|
4
|
+
autoload :Tag, File.expand_path('../svg_transformer/tag', __FILE__)
|
5
|
+
autoload :Template, File.expand_path('../svg_transformer/template', __FILE__)
|
6
|
+
autoload :TemplateError, File.expand_path('../svg_transformer/template_error', __FILE__)
|
7
|
+
autoload :Value, File.expand_path('../svg_transformer/value', __FILE__)
|
8
|
+
autoload :VarGenerator, File.expand_path('../svg_transformer/var_generator', __FILE__)
|
9
|
+
|
10
|
+
def self.setup(env)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.call(environment, input)
|
14
|
+
input[:source] = Condenser::SVGTransformer::Template.new(input[:source]).to_module
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
|
data/lib/condenser/version.rb
CHANGED
data/lib/condenser.rb
CHANGED
@@ -19,19 +19,25 @@ class Condenser
|
|
19
19
|
autoload :RollupProcessor, 'condenser/processors/rollup_processor'
|
20
20
|
autoload :JSAnalyzer, 'condenser/processors/js_analyzer'
|
21
21
|
autoload :PurgeCSSProcessor,'condenser/processors/purgecss_processor'
|
22
|
+
autoload :CSSMediaCombinerProcessor,'condenser/processors/css_media_combiner_processor'
|
22
23
|
autoload :NodeProcessor, 'condenser/processors/node_processor'
|
23
24
|
autoload :UglifyMinifier, 'condenser/minifiers/uglify_minifier'
|
24
25
|
autoload :TerserMinifier, 'condenser/minifiers/terser_minifier'
|
25
26
|
autoload :Erubi, 'condenser/templating_engine/erb'
|
27
|
+
autoload :Sass, 'condenser/transformers/sass'
|
26
28
|
autoload :SassMinifier, 'condenser/minifiers/sass_minifier'
|
27
|
-
autoload :
|
29
|
+
autoload :DartSassTransformer, 'condenser/transformers/dart_sass_transformer'
|
30
|
+
autoload :DartScssTransformer, 'condenser/transformers/dart_sass_transformer'
|
31
|
+
autoload :SassTransformer, 'condenser/transformers/sass_transformer'
|
28
32
|
autoload :ScssTransformer, 'condenser/transformers/sass_transformer'
|
29
|
-
autoload :
|
33
|
+
autoload :EjsTemplate, 'condenser/templating_engine/ejs'
|
30
34
|
autoload :JstTransformer, 'condenser/transformers/jst_transformer'
|
35
|
+
autoload :SVGTransformer, 'condenser/transformers/svg_transformer'
|
31
36
|
autoload :FileWriter, 'condenser/writers/file_writer'
|
32
37
|
autoload :ZlibWriter, 'condenser/writers/zlib_writer'
|
33
38
|
autoload :BrotliWriter, 'condenser/writers/brotli_writer'
|
34
39
|
autoload :BuildCache, 'condenser/build_cache'
|
40
|
+
autoload :ParseHelpers, 'condenser/helpers/parse_helpers'
|
35
41
|
|
36
42
|
def self.configure(&block)
|
37
43
|
instance_eval(&block)
|
@@ -56,8 +62,8 @@ class Condenser
|
|
56
62
|
configure(&block)
|
57
63
|
elsif pipeline != false
|
58
64
|
self.configure do
|
59
|
-
|
60
|
-
register_preprocessor 'application/javascript', Condenser::BabelProcessor
|
65
|
+
register_preprocessor 'application/javascript', Condenser::JSAnalyzer
|
66
|
+
# register_preprocessor 'application/javascript', Condenser::BabelProcessor
|
61
67
|
register_exporter 'application/javascript', Condenser::RollupProcessor
|
62
68
|
register_minifier 'application/javascript', Condenser::UglifyMinifier
|
63
69
|
|
@@ -132,6 +138,9 @@ Condenser.configure do
|
|
132
138
|
# CSS
|
133
139
|
register_mime_type 'text/css', extension: '.css', charset: :css
|
134
140
|
|
141
|
+
# PDF
|
142
|
+
register_mime_type 'application/pdf', extensions: %w(.pdf)
|
143
|
+
|
135
144
|
# SASS
|
136
145
|
register_mime_type 'text/sass', extensions: %w(.sass .css.sass)
|
137
146
|
# register_transformer 'text/sass', 'text/css', SassProcessor
|
@@ -145,12 +154,15 @@ Condenser.configure do
|
|
145
154
|
|
146
155
|
# EJS
|
147
156
|
register_mime_type 'application/ejs', extensions: '.ejs', charset: :unicode
|
148
|
-
register_template 'application/ejs', Condenser::
|
157
|
+
register_template 'application/ejs', Condenser::EjsTemplate
|
149
158
|
|
150
159
|
# JST
|
151
160
|
register_mime_type 'application/jst', extensions: '.jst', charset: :unicode
|
152
161
|
register_transformer 'application/jst', 'application/javascript', Condenser::JstTransformer
|
153
162
|
|
163
|
+
# SVG
|
164
|
+
register_transformer 'image/svg+xml', 'application/javascript', Condenser::SVGTransformer
|
165
|
+
|
154
166
|
# Writers
|
155
167
|
register_mime_type 'application/gzip', extensions: %w(.gz .gzip)
|
156
168
|
register_mime_type 'application/brotli', extension: %w(.br)
|
data/test/cache_test.rb
CHANGED
@@ -60,6 +60,19 @@ class CacheTest < ActiveSupport::TestCase
|
|
60
60
|
CSS
|
61
61
|
end
|
62
62
|
|
63
|
+
test 'changing a source file on calls needs_reprocessing! and needs_reexporting! once' do
|
64
|
+
file 'test.txt.erb', "1<%= 1 + 1 %>3\n"
|
65
|
+
assert_file 'test.txt', 'text/plain', <<~CSS
|
66
|
+
123
|
67
|
+
CSS
|
68
|
+
|
69
|
+
asset = @env.find('test.txt')
|
70
|
+
|
71
|
+
asset.expects(:needs_reprocessing!).once
|
72
|
+
asset.expects(:needs_reexporting!).once
|
73
|
+
file 'test.txt.erb', "1<%= 1 + 2 %>5\n"
|
74
|
+
end
|
75
|
+
|
63
76
|
test 'changing a js dependency reflects in the next call' do
|
64
77
|
file 'main.js', <<-JS
|
65
78
|
import { cube } from 'math';
|
@@ -74,11 +87,11 @@ class CacheTest < ActiveSupport::TestCase
|
|
74
87
|
JS
|
75
88
|
|
76
89
|
assert_exported_file 'main.js', 'application/javascript', <<~CSS
|
77
|
-
!function(){
|
90
|
+
!function(){var o;console.log((o=5)*o)}();
|
78
91
|
CSS
|
79
92
|
|
80
93
|
assert_exported_file 'main.js', 'application/javascript', <<~CSS
|
81
|
-
!function(){
|
94
|
+
!function(){var o;console.log((o=5)*o)}();
|
82
95
|
CSS
|
83
96
|
|
84
97
|
file 'math.js', <<-JS
|
@@ -88,7 +101,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
88
101
|
JS
|
89
102
|
|
90
103
|
assert_exported_file 'main.js', 'application/javascript', <<~CSS
|
91
|
-
!function(){
|
104
|
+
!function(){var o;console.log((o=5)*o*o)}();
|
92
105
|
CSS
|
93
106
|
end
|
94
107
|
|
@@ -123,10 +136,10 @@ class CacheTest < ActiveSupport::TestCase
|
|
123
136
|
JS
|
124
137
|
|
125
138
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
126
|
-
|
139
|
+
console.log(5);
|
127
140
|
JS
|
128
141
|
assert_exported_file 'b.js', 'application/javascript', <<~JS
|
129
|
-
|
142
|
+
console.log(5);
|
130
143
|
JS
|
131
144
|
|
132
145
|
file 'dep.js', <<-JS
|
@@ -134,15 +147,14 @@ class CacheTest < ActiveSupport::TestCase
|
|
134
147
|
JS
|
135
148
|
|
136
149
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
137
|
-
|
150
|
+
console.log(10);
|
138
151
|
JS
|
139
152
|
assert_exported_file 'b.js', 'application/javascript', <<~JS
|
140
|
-
|
153
|
+
console.log(10);
|
141
154
|
JS
|
142
|
-
|
143
155
|
end
|
144
156
|
|
145
|
-
test 'a dependency is
|
157
|
+
test 'a dependency is superceeded by a new file' do
|
146
158
|
Dir.mkdir(File.join(@path, 'a'))
|
147
159
|
Dir.mkdir(File.join(@path, 'b'))
|
148
160
|
@env.clear_path
|
@@ -158,7 +170,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
158
170
|
JS
|
159
171
|
|
160
172
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
161
|
-
|
173
|
+
console.log(5);
|
162
174
|
JS
|
163
175
|
|
164
176
|
file 'a/dep.js', <<-JS
|
@@ -166,7 +178,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
166
178
|
JS
|
167
179
|
|
168
180
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
169
|
-
|
181
|
+
console.log(10);
|
170
182
|
JS
|
171
183
|
end
|
172
184
|
|
@@ -186,7 +198,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
186
198
|
JS
|
187
199
|
|
188
200
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
189
|
-
|
201
|
+
console.log(5);
|
190
202
|
JS
|
191
203
|
|
192
204
|
file 'a/deps/dep.js', <<-JS
|
@@ -194,7 +206,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
194
206
|
JS
|
195
207
|
|
196
208
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
197
|
-
|
209
|
+
console.log(10);
|
198
210
|
JS
|
199
211
|
|
200
212
|
file 'a/deps/dep.js', <<-JS
|
@@ -202,7 +214,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
202
214
|
JS
|
203
215
|
|
204
216
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
205
|
-
|
217
|
+
console.log(20);
|
206
218
|
JS
|
207
219
|
end
|
208
220
|
|
@@ -221,6 +233,21 @@ class CacheTest < ActiveSupport::TestCase
|
|
221
233
|
CSS
|
222
234
|
end
|
223
235
|
|
236
|
+
test '2a new dependency for a glob call is reflected in the next call' do
|
237
|
+
file "dir/a.svg", "<svg>test</svg>"
|
238
|
+
file 'test.scss', 'body { background: image-url("dir/a.svg") }'
|
239
|
+
|
240
|
+
assert_exported_file 'test.css', 'text/css', <<~CSS
|
241
|
+
body{background:url(/assets/dir/a-01a4bd3cb9faa518c5df2d2fcc8e6cd0ba24cfc3e9438dd01455ab1e59a39068.svg)}
|
242
|
+
CSS
|
243
|
+
|
244
|
+
file "dir/a.svg", "<svg>tests</svg>"
|
245
|
+
|
246
|
+
assert_exported_file 'test.css', 'text/css', <<~CSS
|
247
|
+
body{background:url(/assets/dir/a-1d7d038c7ace080963e116cbb962075a38d5e5dc68c6ff688e42d213dd432256.svg)}
|
248
|
+
CSS
|
249
|
+
end
|
250
|
+
|
224
251
|
test 'a dependency is removed for a glob call when one of it dependencies is delted' do
|
225
252
|
file "css/a.scss", "body { color: blue; }"
|
226
253
|
file "css/b.scss", "body { color: green; }"
|
@@ -237,14 +264,14 @@ class CacheTest < ActiveSupport::TestCase
|
|
237
264
|
CSS
|
238
265
|
end
|
239
266
|
|
240
|
-
test 'a dependency is added then changed should flush the parent' do
|
267
|
+
test 'a dependency is added then changed should flush the parent (JS)' do
|
241
268
|
file 'a.js', "console.log('a');\n"
|
242
269
|
file 'b.js', <<~JS
|
243
270
|
export default function b () { console.log('b'); }
|
244
271
|
JS
|
245
272
|
|
246
273
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
247
|
-
|
274
|
+
console.log("a");
|
248
275
|
JS
|
249
276
|
|
250
277
|
file 'a.js', <<~JS
|
@@ -254,7 +281,7 @@ class CacheTest < ActiveSupport::TestCase
|
|
254
281
|
JS
|
255
282
|
|
256
283
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
257
|
-
|
284
|
+
console.log("a"),console.log("b");
|
258
285
|
JS
|
259
286
|
|
260
287
|
file 'b.js', <<~JS
|
@@ -262,7 +289,119 @@ class CacheTest < ActiveSupport::TestCase
|
|
262
289
|
JS
|
263
290
|
|
264
291
|
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
265
|
-
|
292
|
+
console.log("a"),console.log("c");
|
266
293
|
JS
|
267
294
|
end
|
295
|
+
|
296
|
+
test 'a dependency is added then changed should flush the parent (CSS)' do
|
297
|
+
file 'a.scss', "body { background: aqua; }"
|
298
|
+
file 'b.scss', <<~JS
|
299
|
+
body { background: blue; }
|
300
|
+
JS
|
301
|
+
|
302
|
+
assert_exported_file 'a.css', 'text/css', <<~JS
|
303
|
+
body{background:aqua}
|
304
|
+
JS
|
305
|
+
|
306
|
+
file 'a.scss', <<~JS
|
307
|
+
@import "b";
|
308
|
+
body { background: aqua; }
|
309
|
+
JS
|
310
|
+
|
311
|
+
assert_exported_file 'a.css', 'text/css', <<~JS
|
312
|
+
body{background:blue}body{background:aqua}
|
313
|
+
JS
|
314
|
+
|
315
|
+
file 'b.scss', <<~JS
|
316
|
+
body { background: green; }
|
317
|
+
JS
|
318
|
+
|
319
|
+
assert_exported_file 'a.css', 'text/css', <<~JS
|
320
|
+
body{background:green}body{background:aqua}
|
321
|
+
JS
|
322
|
+
end
|
323
|
+
|
324
|
+
test 'ensure the build cache only walks the dependency tree once' do
|
325
|
+
# a
|
326
|
+
# | |
|
327
|
+
# b c
|
328
|
+
# |
|
329
|
+
# d
|
330
|
+
|
331
|
+
file 'd.js', "export default function d () { console.log('d'); }\n"
|
332
|
+
file 'b.js', "export default function b () { console.log('b'); }\n"
|
333
|
+
file 'c.js', <<~JS
|
334
|
+
import d from 'd';
|
335
|
+
|
336
|
+
export default function c () { console.log('c'); d(); }
|
337
|
+
JS
|
338
|
+
file 'a.js', <<~JS
|
339
|
+
import b from 'b';
|
340
|
+
import c from 'c';
|
341
|
+
|
342
|
+
console.log('a'); b(); c();
|
343
|
+
JS
|
344
|
+
|
345
|
+
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
346
|
+
console.log("a"),console.log("b"),console.log("c"),console.log("d");
|
347
|
+
JS
|
348
|
+
|
349
|
+
file 'd.js', "export default function e () { console.log('e'); }\n"
|
350
|
+
|
351
|
+
pd = @env.build_cache.instance_variable_get(:@process_dependencies)
|
352
|
+
pd["#{@path}/a.js"] ||= Set.new
|
353
|
+
pd["#{@path}/b.js"] ||= Set.new
|
354
|
+
pd["#{@path}/c.js"] ||= Set.new
|
355
|
+
pd["#{@path}/d.js"] ||= Set.new
|
356
|
+
pd["#{@path}/a.js"].expects(:<<).with { |a| a.source_file == "#{@path}/a.js" }.once
|
357
|
+
pd["#{@path}/b.js"].expects(:<<).with { |a| a.source_file == "#{@path}/b.js" }.never
|
358
|
+
pd["#{@path}/c.js"].expects(:<<).with { |a| a.source_file == "#{@path}/c.js" }.never
|
359
|
+
pd["#{@path}/d.js"].expects(:<<).with { |a| a.source_file == "#{@path}/d.js" }.once
|
360
|
+
|
361
|
+
assert_exported_file 'a.js', 'application/javascript', <<~JS
|
362
|
+
console.log("a"),console.log("b"),console.log("c"),console.log("e");
|
363
|
+
JS
|
364
|
+
end
|
365
|
+
|
366
|
+
test 'same files in diffrent dirs sharing a cache doesnt poison the cache (ie capistrano deploys)' do
|
367
|
+
cachepath = Dir.mktmpdir
|
368
|
+
|
369
|
+
dir = File.realpath(Dir.mktmpdir)
|
370
|
+
base1 = File.join(dir, 'a')
|
371
|
+
base2 = File.join(dir, 'b')
|
372
|
+
base3 = File.join(dir, 'c')
|
373
|
+
Dir.mkdir(base1)
|
374
|
+
Dir.mkdir(base2)
|
375
|
+
|
376
|
+
[base1, base2, base3].each do |b|
|
377
|
+
file 'test.js', "export default function c () { console.log('t'); }\n", base: b
|
378
|
+
file 'test/b.js', <<~JS, base: b
|
379
|
+
import c from './c';
|
380
|
+
export default function b () { console.log('b'); c(); }
|
381
|
+
JS
|
382
|
+
file 'test/a.js', <<~JS, base: b
|
383
|
+
import t from 'test';
|
384
|
+
import b from './b';
|
385
|
+
|
386
|
+
console.log('a');
|
387
|
+
b();
|
388
|
+
JS
|
389
|
+
end
|
390
|
+
|
391
|
+
file 'test/c.js', "export default function c () { console.log('c'); }\n", base: base1
|
392
|
+
file 'test/c.js', "export default function c () { console.log('d'); }\n", base: base2
|
393
|
+
file 'test/c.js', "export default function c () { console.log('e'); }\n", base: base3
|
394
|
+
|
395
|
+
# Set the cache
|
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("a"),console.log("b"),console.log("c");', env1.find('test/a.js').export.source
|
398
|
+
|
399
|
+
# Poison the cache
|
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("a"),console.log("b"),console.log("d");', env2.find('test/a.js').export.source
|
402
|
+
|
403
|
+
# Fails to find dependency change because cache is missing the dependency
|
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("a"),console.log("b"),console.log("e");', env3.find('test/a.js').export.source
|
406
|
+
end
|
268
407
|
end
|
data/test/dependency_test.rb
CHANGED
@@ -17,7 +17,7 @@ class DependencyTest < ActiveSupport::TestCase
|
|
17
17
|
JS
|
18
18
|
|
19
19
|
asset = @env.find('name.js')
|
20
|
-
assert_equal asset.instance_variable_get(:@process_dependencies), ["models
|
20
|
+
assert_equal asset.instance_variable_get(:@process_dependencies).to_a, [["models/*", ["application/javascript"]],["helpers/*", ["application/javascript"]]]
|
21
21
|
|
22
22
|
|
23
23
|
assert_file 'name.js', 'application/javascript', <<~JS
|
@@ -54,7 +54,7 @@ class DependencyTest < ActiveSupport::TestCase
|
|
54
54
|
JS
|
55
55
|
|
56
56
|
asset = @env.find('name.js')
|
57
|
-
assert_equal asset.instance_variable_get(:@process_dependencies), ["models
|
57
|
+
assert_equal asset.instance_variable_get(:@process_dependencies).to_a, [["models/*", ["application/javascript"]],["helpers/*", ["application/javascript"]]]
|
58
58
|
|
59
59
|
|
60
60
|
assert_file 'name.js', 'application/javascript', <<~JS
|
@@ -74,4 +74,53 @@ class DependencyTest < ActiveSupport::TestCase
|
|
74
74
|
JS
|
75
75
|
end
|
76
76
|
|
77
|
+
test 'js depending on another file type with JSAnalzyer' do
|
78
|
+
@env.unregister_preprocessor 'application/javascript', Condenser::BabelProcessor
|
79
|
+
@env.register_preprocessor 'application/javascript', Condenser::JSAnalyzer
|
80
|
+
@env.unregister_minifier('application/javascript')
|
81
|
+
|
82
|
+
file 'a.js', ''
|
83
|
+
file 'b.rb', ''
|
84
|
+
file 'models/a.js', ''
|
85
|
+
file 'models/b.rb', ''
|
86
|
+
|
87
|
+
file 'name.js.erb', <<~JS
|
88
|
+
// depends_on **/*.rb
|
89
|
+
|
90
|
+
console.log([<%= Dir.children("#{@path}").sort.map(&:inspect).join(', ') %>]);
|
91
|
+
JS
|
92
|
+
|
93
|
+
asset = @env.find('name.js')
|
94
|
+
assert_equal asset.instance_variable_get(:@process_dependencies).to_a, [["**/*", ["application/ruby"]]]
|
95
|
+
assert_equal asset.process_dependencies.map(&:source_file), ["#{@path}/b.rb", "#{@path}/models/b.rb"]
|
96
|
+
end
|
97
|
+
|
98
|
+
test 'relative imports with JSAnalzyer' do
|
99
|
+
@env.unregister_preprocessor 'application/javascript', Condenser::BabelProcessor
|
100
|
+
@env.register_preprocessor 'application/javascript', Condenser::JSAnalyzer
|
101
|
+
@env.unregister_minifier('application/javascript')
|
102
|
+
|
103
|
+
file 'a/a.js', <<~JS
|
104
|
+
export decault function () { console.log("a/a"); }
|
105
|
+
JS
|
106
|
+
file 'b/a.js', <<~JS
|
107
|
+
export decault function () { console.log("a/a"); }
|
108
|
+
JS
|
109
|
+
|
110
|
+
file 'a/b.js', <<~JS
|
111
|
+
import fn from './a';
|
112
|
+
a();
|
113
|
+
console.log("a/b");
|
114
|
+
JS
|
115
|
+
file 'b/b.js', <<~JS
|
116
|
+
import fn from './a';
|
117
|
+
a();
|
118
|
+
console.log("b/b");
|
119
|
+
JS
|
120
|
+
|
121
|
+
asset = @env.find('a/b.js')
|
122
|
+
assert_equal asset.instance_variable_get(:@export_dependencies).to_a, [["#{@path}/a/a", ["application/javascript"]]]
|
123
|
+
assert_equal asset.export_dependencies.map(&:source_file), ["#{@path}/a/a.js"]
|
124
|
+
end
|
125
|
+
|
77
126
|
end
|
data/test/manifest_test.rb
CHANGED
@@ -66,6 +66,40 @@ class ManifestTest < ActiveSupport::TestCase
|
|
66
66
|
assert_equal asset.path, data['application.js']['path']
|
67
67
|
end
|
68
68
|
|
69
|
+
test "compile asset dependencies includes the dependencies" do
|
70
|
+
file 'foo.svg', <<-SVG
|
71
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
72
|
+
<path d="M6 18L18 6M6 6l12 12" />
|
73
|
+
</svg>
|
74
|
+
SVG
|
75
|
+
|
76
|
+
file 'test.scss', <<-SCSS
|
77
|
+
body {
|
78
|
+
background: asset-url("foo.svg");
|
79
|
+
}
|
80
|
+
SCSS
|
81
|
+
|
82
|
+
manifest = Condenser::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
83
|
+
|
84
|
+
main_digest_path = @env['test.css'].path
|
85
|
+
dep_digest_path = @env['foo.svg'].path
|
86
|
+
|
87
|
+
assert !File.exist?("#{@dir}/#{main_digest_path}")
|
88
|
+
assert !File.exist?("#{@dir}/#{dep_digest_path}")
|
89
|
+
|
90
|
+
manifest.compile('test.css')
|
91
|
+
assert File.directory?(manifest.dir)
|
92
|
+
assert File.file?(manifest.filename)
|
93
|
+
|
94
|
+
assert File.exist?("#{@dir}/manifest.json")
|
95
|
+
assert File.exist?("#{@dir}/#{main_digest_path}")
|
96
|
+
assert File.exist?("#{@dir}/#{dep_digest_path}")
|
97
|
+
|
98
|
+
data = JSON.parse(File.read(manifest.filename))
|
99
|
+
assert_equal main_digest_path, data['test.css']['path']
|
100
|
+
assert_equal dep_digest_path, data['foo.svg']['path']
|
101
|
+
end
|
102
|
+
|
69
103
|
# TODO:
|
70
104
|
# test "compile asset with aliased index links" do
|
71
105
|
# manifest = Sprockets::Manifest.new(@env, File.join(@dir, 'manifest.json'))
|
@@ -4,7 +4,6 @@ class TerserMinifierTest < ActiveSupport::TestCase
|
|
4
4
|
|
5
5
|
def setup
|
6
6
|
super
|
7
|
-
@env.unregister_preprocessor('application/javascript', Condenser::BabelProcessor)
|
8
7
|
@env.unregister_exporter('application/javascript', Condenser::RollupProcessor)
|
9
8
|
@env.register_minifier('application/javascript', Condenser::TerserMinifier)
|
10
9
|
end
|