[Fixed]-Django-compressor not setting absolute CSS image paths on Heroku

20šŸ‘

āœ…

I recently ran into this issue on heroku, and running the latest version of django-compressor (1.3) does not solve the problem. I will provide the solution that I am using, as well as an explanation of the problems I ran into along the way.

The solution

I created my own ā€˜CssAbsoluteFilterā€™ that removes the settings.DEBUG check from the ā€˜findā€™ method like this:

# compress_filters.py
from compressor.filters.css_default import CssAbsoluteFilter
from compressor.utils import staticfiles


class CustomCssAbsoluteFilter(CssAbsoluteFilter):
    def find(self, basename):
        # The line below is the original line.  I removed settings.DEBUG.
        # if settings.DEBUG and basename and staticfiles.finders:
        if basename and staticfiles.finders:
            return staticfiles.finders.find(basename)

# settings.py
COMPRESS_CSS_FILTERS = [
# 'compressor.filters.css_default.CssAbsoluteFilter',
'app.compress_filters.CustomCssAbsoluteFilter',
'compressor.filters.cssmin.CSSMinFilter',
]

The absolute urls now always work for me whether DEBUG = True or False.

The Problem

The issue is connected to ā€˜compressor.filters.css_default.CssAbsoluteFilterā€™, your DEBUG setting, and the fact that heroku has a read-only file system and overwrites your app files every time you deploy.

The reason compress works correctly on your development server is because CssAbsoluteFilter will always find your static files when DEBUG = True, even if you never run ā€˜collectstaticā€™. It looks for them in STATICFILES_DIRS.

When DEBUG = False on your production server, CssAbsoluteFilter assumes that static files have already been collected into your COMPRESS_ROOT and wonā€™t apply the absolute filter if it canā€™t find the files.

Jerdez, django-compressorā€™s author, explains it like this:

the CssAbsoluteFilter works with DEBUG = False if youā€™ve successfully provided the files to work with. During development compressors uses the staticfiles finder as a convenience so you donā€™t have to run collectstatic all the time.

Now for heroku. Even though you are storing your static files on S3, you need to also store them on heroku (using CachedS3BotoStorage). Since heroku is a read-only file system, the only way to do this is to let heroku collect your static files automatically during deployment (see https://devcenter.heroku.com/articles/django-assets).

In my experience, running ā€˜heroku run python manage.py collectstatic ā€“noinputā€™ manually or even in your Procfile will upload the files to S3, but it will NOT save the files to your STATIC_ROOT directory (which compressor uses by default as the COMPRESS_ROOT). You can confirm that your static files have been collected on heroku using ā€˜heroku run ls path/to/collectedā€™.

If your files have been collected on heroku successfully, you should be able to compress your files successfully as well, without the solution I provided above.

However, it seems heroku will only collect static files if you have made changes to your static files since your last deploy. If no changes have been made to your static files, you will see something like ā€œ0 of 250 static files copiedā€. This is a problem because heroku completely replaces your app contents when you deploy, so you lose whatever static files were previously collected in COMPRESS_ROOT/STATIC_ROOT. If you try to compress your files after the collected files no longer exist on heroku and DEBUG = False, the CssAbsoluteFilter will not replace the relative urls with absolute urls.

My solution above avoids the heroku problem altogether, and replaces relative css urls with absolute urls even when DEBUG = False.

Hopefully other people will find this information helpful as well.

0šŸ‘

Iā€™ve had this exact same problem for a month now, but this is fixed in the 1.3 release (3/18/13, so you were probably on 1.2), so just upgrade:

pip install -U django-compressor

The exact problem I gave up on working out, but itā€™s related to Heroku and CssAbsoluteFilter being called but failing at _converter method. Looking at the 1.3 changelog, the only related commit is this: https://github.com/jezdez/django_compressor/commit/8254f8d707f517ab154ad0d6d77dfc1ac292bf41

I gave up there, lifeā€™s too short.

šŸ‘¤yuanma

0šŸ‘

Meanwhile this has been fixed in django-compressor 1.6. From the changelog:

Apply CssAbsoluteFilter to precompiled css even when compression is disabled

i.e. the absolute filter is run even with DEBUG = True.

šŸ‘¤karyon

Leave a comment