An open API service indexing awesome lists of open source software.

https://github.com/openwisp/django-minify-compress-staticfiles

A modern Django package for minifying and compressing static files during collectstatic with minimal configuration.
https://github.com/openwisp/django-minify-compress-staticfiles

Last synced: 2 months ago
JSON representation

A modern Django package for minifying and compressing static files during collectstatic with minimal configuration.

Awesome Lists containing this project

README

          

Django Minify Compress StaticFiles
==================================

.. image:: https://github.com/openwisp/django-minify-compress-staticfiles/workflows/CI/badge.svg
:target: https://github.com/openwisp/django-minify-compress-staticfiles/actions
:alt: CI build status

.. image:: https://coveralls.io/repos/github/openwisp/django-minify-compress-staticfiles/badge.svg?branch=master
:target: https://coveralls.io/github/openwisp/django-minify-compress-staticfiles?branch=master
:alt: Coverage

.. image:: https://badge.fury.io/py/django-minify-compress-staticfiles.svg
:target: https://badge.fury.io/py/django-minify-compress-staticfiles
:alt: PyPI Version

.. image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg
:target: https://opensource.org/licenses/BSD-3-Clause
:alt: License

A modern Django package for minifying and compressing static files during
``collectstatic`` with minimal configuration.

Features
--------

- **CSS/JS Minification**: Uses ``rjsmin`` and ``rcssmin`` for fast
minification
- **Dual Compression**: Gzip and Brotli compression support
- **Django Integration**: Seamless integration with Django's static file
system
- **Selective Processing**: Only processes appropriate file types
- **Minified Filename Format**: Preserves Django's hash and adds ``.min``
before the extension: ``name.{hash}.min.ext``. This allows precompressed
files to be properly served as ``name.{hash}.min.ext.gz`` and
``name.{hash}.min.ext.br``.
- **Configurable**: Fine-grained control over processing options

Installation
------------

Install from PyPI:

.. code-block:: bash

pip install django-minify-compress-staticfiles

Configuration
-------------

For **Django 4.2+**, update your ``STORAGES`` setting:

.. code-block:: python

STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": "django_minify_compress_staticfiles.storage.MinicompressStorage",
},
}

For **Django < 4.2**, use the legacy setting:

.. code-block:: python

STATICFILES_STORAGE = "django_minify_compress_staticfiles.storage.MinicompressStorage"

Settings
--------

All settings use the ``MINICOMPRESS_`` prefix:

``MINICOMPRESS_ENABLED``
Enable/disable processing (default: ``True``)

``MINICOMPRESS_MINIFY_FILES``
Enable CSS/JS minification (default: ``True``)

``MINICOMPRESS_GZIP_COMPRESSION``
Enable Gzip compression (default: ``True``)

``MINICOMPRESS_BROTLI_COMPRESSION``
Enable Brotli compression (default: ``True``)

``MINICOMPRESS_MIN_FILE_SIZE``
Minimum file size for compression in bytes (default: ``200``)

``MINICOMPRESS_MAX_FILE_SIZE``
Maximum file size for processing in bytes (default: ``10485760``,
i.e., 10MB) Files larger than this are skipped to prevent memory
exhaustion. Adjust based on your available memory and security
requirements.

``MINICOMPRESS_MAX_FILES_PER_RUN``
Maximum number of files to process per ``collectstatic`` run (default:
``1000``) Prevents CPU and memory exhaustion when processing large
numbers of files. Increase only if you have verified your system can
handle it.

``MINICOMPRESS_COMPRESSION_LEVEL_GZIP``
Gzip compression level (default: ``6``, range: 0-9) Level 6 provides a
good balance between compression ratio and CPU usage. Higher values
(8-9) consume significantly more CPU with diminishing returns. Lower
values (0-5) are faster but produce larger compressed files.

``MINICOMPRESS_COMPRESSION_LEVEL_BROTLI``
Brotli compression quality (default: ``4``, range: 0-11) Level 4
offers excellent compression with reasonable CPU usage. Higher values
(8-11) can cause severe CPU spikes during ``collectstatic``. Lower
values (0-3) are faster but less effective compression.

``MINICOMPRESS_PRESERVE_COMMENTS``
Preserve bang comments in CSS/JS (default: ``True``)

``MINICOMPRESS_SUPPORTED_EXTENSIONS``
Dictionary of file extensions to process (default: css, js, txt, xml,
json, svg, md, rst, html, htm)

``MINICOMPRESS_EXCLUDE_PATTERNS``
List of glob patterns to exclude from processing (default:
``["*.min.*", "*-min.*", "*swagger-ui-*", "*.gz", "*.br", "*.zip"]``)
Pre-compressed files (e.g., ``.gz``, ``.br``, ``.zip``) are excluded
by default to prevent double-compression and security issues.

Usage
-----

Run ``collectstatic`` as usual:

.. code-block:: bash

python manage.py collectstatic --noinput

The package will automatically:

- Minify CSS and JavaScript files
- Create ``.gz`` and ``.br`` compressed versions
- Update Django's manifest with minified file paths
- Skip already processed files and patterns

Supported File Types
--------------------

**Minification**: CSS, JavaScript

**Compression**: CSS, JS, TXT, XML, JSON, SVG, MD, RST, HTML, HTM

Security and Performance Considerations
---------------------------------------

The package implements the following safeguards to mitigate common attack
vectors and ensure resource stability.

Path Traversal Protection
~~~~~~~~~~~~~~~~~~~~~~~~~

To prevent directory traversal attacks (e.g., ``../etc/passwd``), all file
paths undergo strict validation. The system enforces a boundary check
ensuring no read or write operations occur outside the defined
``STATIC_ROOT``. Any attempt to access parent directories via relative
paths is intercepted and blocked.

Memory Exhaustion Prevention
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To prevent memory exhaustion, the ``MAX_FILE_SIZE`` setting enforces a
hard cap on file processing. This prevents the application from attempting
to buffer or process excessively large files that could lead to
Out-Of-Memory (OOM) errors.

CPU Exhaustion & Resource Throttling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Compression is a CPU-intensive task. To balance throughput with system
stability, the default compression levels are tuned for efficiency:

- **Gzip:** Level 6
- **Brotli:** Level 4

These defaults prevent "CPU pinning" where a single request monopolizes
processor cycles.

Compression Bomb Protection
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The processor automatically excludes files that are already compressed
(e.g., ``.gz``, ``.br``, ``.zip``, ``.png``). This prevents recursive
compression cycles and "Zip Bomb" style attacks that could lead to
exponential CPU and disk space consumption.

Integrity & Cache Validation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

File fingerprinting uses **MD5** hashing to match Django's
``ManifestFilesMixin`` algorithm. This ensures consistency between
Django's hashed filenames and our minified filenames, allowing the
manifest to correctly map original files to their minified versions.

Recommended Settings for Production
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For production deployments with high security requirements:

.. code-block:: python

MINICOMPRESS_MAX_FILE_SIZE = 2097152 # 2MB
MINICOMPRESS_MAX_FILES_PER_RUN = 500
MINICOMPRESS_COMPRESSION_LEVEL_GZIP = 6
MINICOMPRESS_COMPRESSION_LEVEL_BROTLI = 4

For development environments with faster builds:

.. code-block:: python

MINICOMPRESS_COMPRESSION_LEVEL_GZIP = 1
MINICOMPRESS_COMPRESSION_LEVEL_BROTLI = 0
MINICOMPRESS_BROTLI_COMPRESSION = False # Disable for faster builds

Dependencies
------------

**Required**:

- Django >= 4.2
- Python >= 3.10
- ``brotli`` >= 1.0.0
- ``rjsmin`` >= 1.2.0
- ``rcssmin`` >= 1.1.0

License
-------

BSD 3-Clause License. See ``LICENSE`` file for details.

Contributing
------------

Contributions are welcome! Please see the `OpenWISP contributing
guidelines`_ for more information.

.. _openwisp contributing guidelines: https://openwisp.io/docs/stable/developer/contributing.html

Support
-------

- `Issue Tracker`_
- `OpenWISP Support`_

.. _issue tracker: https://github.com/openwisp/django-minify-compress-staticfiles/issues

.. _openwisp support: https://openwisp.org/support/