Django-compressor: No way to get this to work on Heroku

Created on 6 Mar 2014  ·  24Comments  ·  Source: django-compressor/django-compressor

Searching around the web there doesn't seem a straight forward way to get this to work on heroku.

I figured that putting everything on S3 as is the heroku recommended way for files would be the way to go. Then I read this: http://django-compressor.readthedocs.org/en/latest/remote-storages/
which is all fine but after having done that it doesn't say what the result is. Do I run collectstatic, compress, both? Do I do it locally or do I let the heroku push hook do it for me? Or do I in fact disable the heroku collectstatic because I don't have lessc &co in the heroku environment anyway.

So at the least this would be a documentation bug for this page: http://django-compressor.readthedocs.org/en/latest/remote-storages/

In principle this should work on heroku as well if you generate everything offline and check them into your version control, right?

There are these articles about setting up node and less in the heroku environment but they seem a bit excessive and don't in fact work:
http://marklmiddleton.com/2013/using-less-with-django-on-heroku/
http://www.sore.nu/blog/2012/dec/30/fieldguide-django-bootstrap-less-coffeescript-and-/

Am I missing anything here? After spending half a day on this yesterday I'm giving up (the clear alternative is compiling everything locally using the standard front end tools).

deployment

Most helpful comment

OK, here's something that is working for me and has survived dyno restart. My key goals here were 1) not needing to add a whole ruby/JS buildpack situation solely for my asset pipeline; 2) not needing to set up S3; 3) having it happen automatically as part of deployment rather than requiring local steps.

So:

1) Configure whitenoise according to Heroku's instructions.

2) add django-libsass to your requirements.

3) In your settings file:

INSTALLED_APPS += ('compressor',)

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'compressor.finders.CompressorFinder',
)

COMPRESS_ENABLED = True
COMPRESS_OFFLINE = True

COMPRESS_PRECOMPILERS = (
    ('text/x-sass', 'django_libsass.SassCompiler'),
    ('text/x-scss', 'django_libsass.SassCompiler'),
)

4) Add a bin/post_compile file containing

python manage.py compress
python manage.py collectstatic --noinput

(Note that this must be in post_compile. It cannot be a release task because of the ephemeral filesystem - the files you generate during compression won't stick around if you run them in a release task. But running them in post_compile seems to work, and to survive dyno restart.)

All 24 comments

Not a bug ;)

But there were many questions ;)

  • in most load-scenarios I would use dj-static (as seen in the heroku docs) or whitenoise for serving static files on heroku.
  • if everything is configured fine, heroku runs collectstatic for you when you push your code
  • if you want to add offline-compression, you can add a post_compile script (see here) that runs compress for you
  • don't offline-compress locally, let heroku do this for you.
  • for installing lessc on heroku is another task, I would have to google and try, too .. But your first link looks promising (at least the post_compile script).

In the section linked above under "Using staticfiles" still no idea why you need to make your own storage subclass or what you need to do after you've done it.

I tried installing lessc on heroku but if the post_compile script given doesn't work directly, this is extremely tedious to debug and frankly it doesn't sound like a good idea to create a container with everything and the kitchen sink.

Amazed at how hard this is still, but if anybody tells me what is happening here: http://django-compressor.readthedocs.org/en/latest/remote-storages/
I'll be happy to add a documentation patch.

I created a fork of django-skel that supports django-compressor, scss compilation, bower, and bunch of other stuff (and have it running on heroku). Is anyone interested in seeing it?

I think people would definitely be interested in seeing stuff that works!

@therippa: I'd be interested in seeing that, too.

Compressor's Online mode doesn't work on Heroku because Whitenoise only checks the static folder when the app is loaded (see my comment on issue #680). To use compressor in production I think you need to use it in Offline mode and run python manage.py compress before the app loads using Heroku's post compile hook. Heroku will automatically run collect static for you so that isn't an issue. I found heroku-django-cookbook helpful. I'm using TypeScript on my Django/Heroku app so I also needed to install node etc. This is possible via the post compile hook, a custom pip package, or a custom build pack. I think the post compile hook is the easiest way.

As I had this problem in combination with sekizai, using offline compression wasn't really an option. But this problem is actually quite easily fixed be extending whitenoise, so here's my solution: https://gist.github.com/Chronial/45ce9f33615a3b24c51f

Maybe someone wants to add some tests and documentation to that and send a proper PR to whitenoise? :)

Note: If you still want pre-generation or heroku, you could start the server and send some requests in your post_build hook.

Whitenoise docs mention django-compressor at http://whitenoise.evans.io/en/stable/django.html#django-compressor

OK. This worked for me brilliantly!
Inside my root local directory (aka repo) I created a directory bin/ and inside that a file named post_compile. Inside the post_compile file I copy-pasted these data.
I did git add --all, git commit -m 'testing post_receive hook in Heroku', git push heroku master.
After the auto-run of collectstatic command by Heroku, it did run python manage.py compress and it did create a directory which contains all of my files compressed in one file!

remote:      $ python manage.py collectstatic --noinput
remote:        1247 static files copied to '/app/staticfiles'.
remote: 
remote: -----> Running post-compile hook
remote: -----> Compressing static files
remote:        Found 'compress' tags in:
remote:         /app/templates/base/base.html
remote:         /app/templates/info/areas.html
remote:         /app/templates/info/profile.html
remote:        Compressing... done
remote:        Compressed 1 block(s) from 3 template(s) for 1 context(s).

if you're seeing OfflineCompressionErrors, also check out https://github.com/django-compressor/django-compressor/issues/443 where people suggest more workarounds.

in the case of #831, what worked is doing offline compression locally, and pushing the result including the manifest.json to heroku. no S3 there though.

here is another config that works for the author: https://github.com/django-compressor/django-compressor/issues/855#issuecomment-303294202

OK, here's something that is working for me and has survived dyno restart. My key goals here were 1) not needing to add a whole ruby/JS buildpack situation solely for my asset pipeline; 2) not needing to set up S3; 3) having it happen automatically as part of deployment rather than requiring local steps.

So:

1) Configure whitenoise according to Heroku's instructions.

2) add django-libsass to your requirements.

3) In your settings file:

INSTALLED_APPS += ('compressor',)

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'compressor.finders.CompressorFinder',
)

COMPRESS_ENABLED = True
COMPRESS_OFFLINE = True

COMPRESS_PRECOMPILERS = (
    ('text/x-sass', 'django_libsass.SassCompiler'),
    ('text/x-scss', 'django_libsass.SassCompiler'),
)

4) Add a bin/post_compile file containing

python manage.py compress
python manage.py collectstatic --noinput

(Note that this must be in post_compile. It cannot be a release task because of the ephemeral filesystem - the files you generate during compression won't stick around if you run them in a release task. But running them in post_compile seems to work, and to survive dyno restart.)

@thatandromeda solution worked for me, many thanks!

@thatandromeda this solution may just be what I'm looking for (After 12 hours of trying tons of things). Where exactly does bin/post_compile go? how would I go about adding it? how do I tell heroku to use it?

@manikos @thatandromeda Should I run collectstatic before or after or both before and after compress? My compress management command says file not found:

ValueError: The file 'css/font-awesome.min.css' could not be found with <whitenoise.storage.CompressedManifestStaticFilesStorage object at 0x7f3e3fc3b828>.

@typistX You don't have to tell heroku anything, it automatically detects if you have a directory called bin in your project root (repo) and if there is a file called post_compile (no file extension) inside.

@thatandromeda You just saved me after 3 days of dealing with this crap. 🙏🏼

Sorry you're having this struggle / glad I could help!

@technolingo the compress needs to run after collectstatic.

Both solutions, @thatandromeda's and @manikos's worked for me, thank you! 😃
It is confirmed that this is not a bug, but just a lack of information about the deployment process on Heroku, mentioning it somewhere in the documentation sure would be of help.

I'll be happy to review and merge any pull request improving documentation. None of the active maintainers have an heroku account, so this is really up to users that do to suggest changes.

would a 1-click deploy button to heroku be welcome here? or just a document stepping through heroku deployment?

@morenoh149 In my view, what is most needed here is documentation, a "1-click deploy button" may help but when I was searching for _the bug_ I wanted to know what exactly the problem was.

Was this page helpful?
0 / 5 - 0 ratings