In this tutorial, you will learn how to compress and optimize your static files i.e., javascript (.js) and CSS (.css) files for production. You will work with django-compressor to compress CSS and JS and django-htmlmin to minify HTML files. You can refer to the source code of this project here.

Django Compressor is a python package for the Django web framework to compress and minify CSS and JS files using {% load compress %} tag.

Let's start with installing the dependencies.

Install Dependencies

To optimize static files, you need to install the following dependencies. First, let's install memcached for caching static files. It's optional but it will speed up your static files serving, so totally worth it. Try it

# Install Memcache
sudo apt-get install Memcached # Ubuntu
brew install memcached # Mac

# Start memcache
sudo service memcached start # Ubuntu
brew services start memcached # Mac

Now install the required PIP packages

If using virtual environment, activate it using source venv/bin/activate before installing pip packages. You can learn more about virtual environment here.

pip install python-memcached
pip install django-compressor
pip install django-htmlmin

Default settings for Django compressor

Open up your settings.py file and make these changes

Configure Memcached

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

Memcached runs through localhost port 11211 by default, so there’s no further configuration here.

[Optional]: There are other options to have a dedicated Memcached server or have Memcached store files locally. Django documentation has more information on how to set that up.

Add compressor to your installed apps

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'compressor',
]

Add middlewares

MIDDLEWARE = [
    'django.middleware.gzip.GZipMiddleware', #This one
    'htmlmin.middleware.HtmlMinifyMiddleware', #This one
    'htmlmin.middleware.MarkRequestMiddleware', #This one

    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Configure static files settings

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
STATIC_ROOT = os.path.join(BASE_DIR,"static_root")

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

    # Add this
    'compressor.finders.CompressorFinder',
)

Add compressor and minified settings

COMPRESS_ENABLED = True
COMPRESS_CSS_HASHING_METHOD = 'content'
COMPRESS_FILTERS = {
    'css':[
        'compressor.filters.css_default.CssAbsoluteFilter',
        'compressor.filters.cssmin.rCSSMinFilter',
    ],
    'js':[
        'compressor.filters.jsmin.JSMinFilter',
    ]
}
HTML_MINIFY = True
KEEP_COMMENTS_ON_MINIFYING = True

Compressing files with an example

To compress CSS and JS, load the compress tag just like you load static tag

{% load static %}

{% load compress %}

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>

  {% compress css %}
  <link rel="stylesheet" href="{% static 'style.css' %}">
  {% endcompress %}

  {% compress js %}
  <script src="{% static 'script.js' %}"></script>
  {% endcompress %}

</head>
<body>
  <center>
    <h1>Raturi.in</h1>
    <h1 class="heading">Hello Lets compress</h1>
    <p class="para">I am just a para</p>
    <button onclick="change_colors()">Change colors</button>
  </center>
</body>
</html>

Compressed files will look something like this

# CSS
<link rel="stylesheet" href="/static/CACHE/css/output.f7c661b7a124.css" type="text/css" charset="utf-8">

# JS
<script src="/static/CACHE/css/output.f7c661b7a124.css" type="text/css" charset="utf-8"></script>

# Run your server and you can check your source code to verify it.

Run the command below to compress in the given sequence

python manage.py collectstatic
python manage.py compress --force
python manage.py runserver

Now if you check your source code, you will see that your files are compressed. Mine looks like this:

django-compress1-min

django_compress2-min

For production, in your settings.py set COMPRESS_ENABLED like below

COMPRESS_ENABLED = not DEBUG

Django compressor Usage

Django Compressor can be used by loading a compress tag and then enclosing the HTML, CSS files inside the compress tags.

Syntax of Django compressor:

{% load compress %}
{% compress <js/css> [<file/inline/preload> [block_name]] %}
<html of inline or linked JS/CSS>
{% endcompress %}

Let's see some examples

Compressing CSS and JS file

{% compress css %}
<link rel="stylesheet" href="{% static 'css/style.css' %}" type="text/css" charset="utf-8">

<style type="text/css">p { border:15px solid blue;}</style>

<link rel="stylesheet" href="/static/css/two.css" type="text/css" charset="utf-8">
{% endcompress %}

{% compress js %}
<script defer type="text/javascript" src="{% static 'custom/js/lozad.min.js' %}"></script>
<script>
    function loadAdsenseScript(url) {
        let script = document.createElement('script');
        script.src = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
        script.defer = true;
        script['data-ad-client'] = "ca-XXX";
        document.head.appendChild(script);
    }
</script>
{% endcompress %}

Output

<link rel="stylesheet" href="/static/CACHE/css/output.f7c661b7a124.css" type="text/css" charset="utf-8">
<script type="text/javascript" src="/static/CACHE/js/base.3f33b9146e12.js" charset="utf-8"></script>

You can add inline parameter if you want content directly rendered to the page instead of a separate file

{% compress js inline %}
    <script>
        window.dataLayer = window.dataLayer || [];

        function gtag() {
            dataLayer.push(arguments);
        }

        gtag('js', new Date());

        gtag('config', 'G-asdww');
    </script>
{% endcompress %}

You can also add preload parameter to generate the preload tag for the compressed file in the template

{% compress js preload %}
    <script>
    // On page load or when changing themes, best to add inline in `head` to avoid FOUC
    if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
        document.documentElement.classList.add('dark');
    } else {
        document.documentElement.classList.remove('dark')
    }
</script>
{% endcompress %}

Output:

<link rel="preload" href="/static/CACHE/js/d014sdf14fc6.js" as="style" />

That's all for a setup of the Django compressor. You can check the source code of this project here.

You can also check out more django-tutorials