Django-compressor notes and tricks

If you'd like to have offline compression enabled then do not do next things:
Do not use nested css/js blocks that are extended in templates. Example of "bad" templates:

site_base.html:
{% block base_js %}
  {% compress js %}
      <script ...="..."></script">
      {% block extra_js %}{% endblock %}
  {% endcompress %}
{% endblock %}


view_template.html
{% extends "site_base.html" %}

{% block extra_js %}
     <script ...="..."></script">
{% endblock %}

This will work fine for in-request compression but will lead to errors for offline compression: it will say something like:
You have offline compression enabled but key "%s" is missing from offline manifest. You may need to run "python manage.py compress"
This happened because offline compression tries to parse templates and can't find compression tags from parent block (base_js). This may also happen if you extend by variable ({% extends base_template_variable %}) or place compress tag in if-blocks.


Templates that work fine with offline compression should look like this:

site_base.html:
{% block base_js %}
  {% compress js %}
      <script ...="..."></script">
  {% endcompress %}
{% endblock %}
view_template.html
{% extends "site_base.html" %}

{% block base_js %}
     {{ block.super }}
     <script ...="..."></script">
{% endblock %}

Offline compression is musthave for production. But for development it's better to have in-request compression that tracks all changes to static. This is easy to do with django-pipeline but django-compressor have no custom StaticFinders. But there is a workaround: let's just modify compress tag to collect static on every call!

# -*- coding: utf-8 -*-

from django import template
from django.core import management
from django.conf import settings

from compressor.templatetags.compress import compress as original_compress

register = template.Library()


@register.tag
def compress(parser, token):
     """Collect static before compressing. Only works with custom runserver management command.
   
    Default runserver triggers autoreload on this tag
   
    """
     if settings.IS_DEV:
         management.call_command('collectstatic', interactive=False, verbosity=0)
     return original_compress(parser, token)

When you add this to your project's or app's template tags you will find out that Django devserver restarts on every request. Django thinks that code is changing source because collectstatic wasn't called on devserver start. This can be fixed by overriding runserver. You can try this devserver management command:

# -*- coding: utf-8 -*-

from django.contrib.staticfiles.management.commands.runserver import Command as BaseCommand
from django.core import management


class Command(BaseCommand):

def inner_run(self, *args, **options):
     management.call_command('collectstatic', interactive=False)
     super(Command, self).inner_run(*args, **options)