What I've learnt so far while testing django_compressor.
- it's fairly easy to setup. Broadly speaking, a few lines in
settings.py, some {% compress %} tags in templates around the JS/CSS
you want compressed/combined, and the next request to a page will
automatically run the filters/compressors, cache the output, and do
all the work, so that users get efficient content served. Also, it
does not impact the way we develop, and we don't need to put any
minified files in the git repository.
An example of template tag, from choice.html:
{% compress js %}
<script type="text/javascript" src="{% static
"ductus/modules/flashcards/js/choice.js" %}"></script>
<script type="text/javascript" src="{% static
"ductus/common/js/jQuery.jPlayer.2.1.0/jquery.jplayer.min.js"
%}"></script>
<script type="text/javascript" src="{% static
"ductus/common/js/audio_player.js" %}"></script>
{% endcompress %}
will turn into:
<script type="text/javascript" src="/static/CACHE/js/504776bdaa18.js"></script>
The resulting filename is a hash based on the content of the
compressed files, so a new filename will be created when we deploy new
code.
- to actually make use of the compression system, we need to setup a
(django) caching mechanism. Just a simple "file on disk" system is
good enough to start with. Best practice is to setup nginx to serve
the cached compressed files with an "Expires max" header, since we
know that filenames will change whenever the content changes.
- the other option (django-pipeline) will essentially provide the same
function. The difference being that compressor defines which files to
compress/combine in the templates (ie: where we call them), whereas
pipeline does that job in settings.py, which seems harder to implement
as we'd have to sync puppet and ductus repositories. With compressor,
we just define how things would happen in the ductus code, and
settings.py just says whether we do it or not.
About closure compiler:
- it has 3 different levels of optimisation. One removes whitespace
only. The second "simple" (default) shortens local variable names in
functions. The advanced one is really what we want to use (see below).
(
https://developers.google.com/closure/compiler/docs/compilation_levels
for details) It does not deal with CSS, we need YUI compressor for
that.
- YUI and closure compiler (CC in simple mode) are pretty equivalent
in terms of results on our code. (viewing a choice lesson, we get a
~10% discount on data transferred, media excluded). The real big
change is if we use CC's advanced mode, where we seem to hit ~30%
reduction, essentially because CC will look into jquery/ui and wipe
out any function that we do not use, BUT...
- our javascript code will require a bit of cleanup/optimisation to
allow for closure compiler's (CC) advanced optimisation mode.
Basically, tricks to tell the compiler which names it can crunch and
which ones are called in other files. As it is now, CC breaks the
code, which is anticipated, as explained in the docs. (full story at
https://developers.google.com/closure/compiler/docs/api-tutorial3)
- it's a java app, so we'd need java installed on the server. An
alternative is to rely on the google API which may be more efficient
than running the app ourselves. YUI compressor (for CSS) runs on java
too, although there are alternatives but they don't seem to be
maintained much.
Optmisation in general:
- google and yahoo give a lot of advice on best practices (good news
is: they seem to agree on things!) and firefox/chrome extensions to
help point out ways to improves pages (pagespeed or YSlow)
- from looking at things, jquery-ui is 30 to 50% of the weight of our
pages (excluding media). I'll look into getting rid of as much of it
as possible.
- the more doc I read, the more ideas for optimising I get, so I don't
think we need to go over the top with it. Deploying compressor,
setting up "cache forever" in nginx and getting rid of (obvious)
useless JS/CSS would be more than enough for a stage 1. When we start
feeling the limits of this, we can think of stage 2.
Enough for this round.