Support for async/defer

Now javascripts are compressed preserving async or defer.
This commit is contained in:
GermanoGuerrini
2013-12-04 15:02:46 +01:00
parent c961dadf6e
commit 5c1bd40550
6 changed files with 61 additions and 6 deletions

View File

@@ -12,14 +12,40 @@ class JsCompressor(Compressor):
def split_contents(self):
if self.split_content:
return self.split_content
self.nodes = []
for elem in self.parser.js_elems():
attribs = self.parser.elem_attribs(elem)
if 'src' in attribs:
basename = self.get_basename(attribs['src'])
filename = self.get_filename(basename)
content = (SOURCE_FILE, filename, basename, elem)
self.split_content.append(content)
else:
content = self.parser.elem_content(elem)
self.split_content.append((SOURCE_HUNK, content, None, elem))
content = (SOURCE_HUNK, self.parser.elem_content(elem), None, elem)
self.split_content.append(content)
extra_attr = ''
if 'async' in attribs:
extra_attr = ' async'
elif 'defer' in attribs:
extra_attr = ' defer'
# Append to the previous node if it had the same attribute
append_to_previous = self.nodes and self.nodes[-1][0] == extra_attr
if append_to_previous and settings.COMPRESS_ENABLED:
self.nodes[-1][1].split_content.append(content)
else:
node = JsCompressor(content=self.parser.elem_str(elem),
context=self.context)
node.split_content.append(content)
self.nodes.append((extra_attr, node))
return self.split_content
def output(self, *args, **kwargs):
if (settings.COMPRESS_ENABLED or settings.COMPRESS_PRECOMPILERS or
kwargs.get('forced', False)):
self.split_contents()
if hasattr(self, 'nodes'):
ret = []
for extra_attr, subnode in self.nodes:
subnode.extra_context.update({'extra_attr': extra_attr})
ret.append(subnode.output(*args, **kwargs))
return '\n'.join(ret)
return super(JsCompressor, self).output(*args, **kwargs)

View File

@@ -1 +1 @@
<script type="text/javascript" src="{{ compressed.url }}"></script>
<script type="text/javascript" src="{{ compressed.url }}"{{ compressed.extra_attr }}></script>

View File

@@ -0,0 +1 @@
hermanos = {}

View File

@@ -0,0 +1 @@
pollos = {}

View File

@@ -252,3 +252,31 @@ class CacheBackendTestCase(CompressorTestCase):
def test_correct_backend(self):
from compressor.cache import cache
self.assertEqual(cache.__class__, locmem.CacheClass)
class JsAsyncDeferTestCase(SimpleTestCase):
def setUp(self):
self.js = """\
<script src="/static/js/one.js" type="text/javascript"></script>
<script src="/static/js/two.js" type="text/javascript" async></script>
<script src="/static/js/three.js" type="text/javascript" defer></script>
<script type="text/javascript">obj.value = "value";</script>
<script src="/static/js/one.js" type="text/javascript" async></script>
<script src="/static/js/two.js" type="text/javascript" async></script>
<script src="/static/js/three.js" type="text/javascript"></script>"""
def test_js_output(self):
def extract_attr(tag):
if tag.has_attr('async'):
return 'async'
if tag.has_attr('defer'):
return 'defer'
js_node = JsCompressor(self.js)
output = [None, 'async', 'defer', None, 'async', None]
if six.PY3:
scripts = make_soup(js_node.output()).find_all('script')
attrs = [extract_attr(i) for i in scripts]
else:
scripts = make_soup(js_node.output()).findAll('script')
attrs = [s.get('async') or s.get('defer') for s in scripts]
self.assertEqual(output, attrs)

View File

@@ -56,8 +56,7 @@ class TestJinja2CompressorExtension(TestCase):
self.assertEqual(tag_body, template.render())
def test_empty_tag(self):
template = self.env.from_string("""{% compress js %}{% block js %}
{% endblock %}{% endcompress %}""")
template = self.env.from_string("""{% compress js %}{% block js %}{% endblock %}{% endcompress %}""")
context = {'STATIC_URL': settings.COMPRESS_URL}
self.assertEqual('', template.render(context))