Skip to main content

Django Multi-Manifest Loader

A simple, standalone template tag for loading webpack manifest files from multiple Django packages/apps. Zero dependencies on unmaintained packages.

Problem

When using webpack with multiple Django packages (like righttowork-check, criminalrecords-check, etc.), each package generates its own manifest.json file with hashed asset filenames for cache busting. However, most manifest loaders only read a single manifest file, making it impossible to reference assets from installed packages.

Solution

django-multi-manifest-loader provides a standalone template tag that:

  1. Loads the main webpack manifest (from your dashboard/main app)
  2. Automatically discovers and loads manifest files from all installed Django packages
  3. Namespaces manifests by app to prevent naming collisions
  4. Auto-detects the current app from template context for seamless usage
  5. Makes all assets available via the {% manifest %} template tag
  6. Zero dependencies - doesn't rely on unmaintained packages like django-manifest-loader

Key Features

  • Automatic Namespacing: Each app's manifest is namespaced, so config.js in package1 doesn't conflict with config.js in package2
  • Smart Auto-Detection: Automatically uses the correct app's assets based on which template is rendering
  • Explicit App Parameter: Use app='appname' parameter when you need assets from a specific app
  • Fallback to Main: If an asset isn't found in the current app, falls back to the main app's manifest

Installation

pip install django-multi-manifest-loader

Or install from source:

cd django-multi-manifest-loader
pip install -e .

Usage

1. Add to INSTALLED_APPS

In your settings.py:

INSTALLED_APPS = [
    # ...
    'django_multi_manifest_loader',
    # ...
]

2. Configure (Optional)

In your settings.py:

DJANGO_MULTI_MANIFEST_LOADER = {
    'cache': True,  # Enable caching (default: True in production, False in DEBUG)
    'main_app_name': 'dashboard',  # Name for main app manifests (default: 'main')
}

3. Use in Templates

The manifest tag automatically detects which app's template is rendering and loads the correct assets:

{% load manifest %}

{# In package1/templates/package1/form.html #}
{# Automatically uses package1's manifest #}
<script src="{% manifest 'config.js' %}"></script>
{# Returns: package1/js/config.abc123.js #}

{# In package2/templates/package2/wizard.html #}
{# Automatically uses package2's manifest #}
<script src="{% manifest 'config.js' %}"></script>
{# Returns: package2/js/config.xyz789.js #}

{# Explicit app parameter - use assets from another app #}
<script src="{% manifest 'main.js' app='dashboard' %}"></script>
{# Always returns dashboard's main.js #}

{# If not found in current app, falls back to main app #}
<link href="{% manifest 'shared-styles.css' %}" rel="stylesheet">

How It Works

The loader searches for manifest files in all installed Django apps and namespaces them by app:

  1. Discovery: Finds manifest.json files in all Django apps using staticfiles finders
  2. Namespacing: Each app's manifest is stored under its app name (e.g., package1, package2)
  3. Auto-Detection: When rendering a template, extracts the app name from the template path (e.g., package1/form.htmlpackage1)
  4. Resolution:
    • First tries the current app's manifest
    • Falls back to the main app if not found
    • Supports explicit app='appname' parameter for cross-app asset references

Result: No naming collisions! Each app's config.js is kept separate.

Package Manifest Example

In your Django package (e.g., righttowork-check), generate a manifest using webpack:

webpack.config.js:

const { WebpackManifestPlugin } = require('webpack-manifest-plugin');

module.exports = {
    output: {
        path: path.resolve(__dirname, 'static/righttoworkcheck/js/'),
        filename: '[name].[contenthash:8].js',
        publicPath: 'righttoworkcheck/js/'
    },
    plugins: [
        new WebpackManifestPlugin({
            fileName: '../manifest.json',
            publicPath: 'righttoworkcheck/js/',
        }),
    ],
};

This generates static/righttoworkcheck/manifest.json:

{
  "custom/candidate/wizard/multiple-upload.js": "righttoworkcheck/js/custom/candidate/wizard/multiple-upload.dd215078.js"
}

Configuration

All configuration is optional. Add to your settings.py:

DJANGO_MULTI_MANIFEST_LOADER = {
    # Enable/disable manifest caching
    # Default: True in production (not DEBUG), False in DEBUG mode
    'cache': True,

    # Name for main app manifests (manifests not tied to a specific app)
    # Default: 'main'
    'main_app_name': 'dashboard',

    # Enable debug logging to see which manifests are loaded
    # Default: False
    'debug': False,
}

Configuration Options

Option Type Default Description
cache bool not DEBUG Cache merged manifests in memory. Disable in development for hot reloading.
main_app_name str 'main' Name used for main/shared manifests that aren't tied to a specific app.
debug bool False Enable detailed logging of manifest loading process.

Development

Setup Development Environment

# Clone the repository
cd django-multi-manifest-loader

# Create virtual environment
python3 -m venv .venv

# Activate virtual environment
source .venv/bin/activate  # Linux/Mac
# or
.venv\Scripts\activate  # Windows

# Install package with dev dependencies
pip install -e ".[dev]"

Running Tests

# Run all tests
pytest

# Run with coverage report
pytest --cov=django_multi_manifest_loader --cov-report=term-missing

# Run specific test file
pytest tests/test_manifest_loader.py -v

Code Quality

# Run all quality checks
flake8 django_multi_manifest_loader/ tests/
black --check django_multi_manifest_loader/ tests/
isort --check-only django_multi_manifest_loader/ tests/
ruff check django_multi_manifest_loader/ tests/

# Auto-format code
black django_multi_manifest_loader/ tests/
isort django_multi_manifest_loader/ tests/
ruff check --fix django_multi_manifest_loader/ tests/

Clear Cache Programmatically

During development, you can clear the manifest cache:

from django_multi_manifest_loader import ManifestLoader
ManifestLoader.clear_cache()

Debug Mode

Enable debug mode to see detailed logging:

# settings.py
DJANGO_MULTI_MANIFEST_LOADER = {
    'debug': True,
}

This will log:

  • Number of manifest files found
  • Path to each manifest being loaded
  • Number of entries in each manifest
  • Total merged entries

Hot Reloading in Development

By default, caching is disabled in DEBUG mode (cache=not DEBUG). This means:

  • Production: Manifests are cached for performance
  • Development: Manifests are reloaded on each request for hot reloading

Requirements

  • Python >= 3.10
  • Django >= 4.0

No other dependencies! This package is completely standalone.

How It Works

The loader uses Django's staticfiles finders to discover manifest files:

  1. Main manifest: Searches for manifest.json in static directories
  2. Package manifests: Iterates through all INSTALLED_APPS and checks each for <app_name>/manifest.json
  3. Merging: All found manifests are merged into a single dictionary (later entries override earlier ones)
  4. Caching: Merged manifest is cached in memory (unless disabled)

Publishing

Automated Publishing to PyPI

The package automatically publishes to PyPI when you push a version tag:

# Update version in __init__.py
# Commit changes
git add django_multi_manifest_loader/__init__.py
git commit -m "Bump version to 0.2.0"

# Create and push tag
git tag v0.2.0
git push origin main --tags

This triggers the GitHub Actions workflow which:

  1. Runs all tests across Python 3.10-3.12 and Django 4.2-5.1
  2. Runs all linters (flake8, black, isort, ruff)
  3. Builds the package
  4. Publishes to PyPI using trusted publishing (no API tokens needed)

Manual Publishing

# Build package
python -m build

# Check package
twine check dist/*

# Upload to PyPI (requires PyPI credentials)
twine upload dist/*

License

MIT

Release files for django-multi-manifest-loader 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-multi-manifest-loader 0.1.3
File Size Uploaded
django_multi_manifest_loader-0.1.3.tar.gz 11.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-multi-manifest-loader 0.1.3
File Interpreter ABI Platform
django_multi_manifest_loader-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 20.4 kB

Release files / django_multi_manifest_loader-0.1.3.tar.gz

Download URL django_multi_manifest_loader-0.1.3.tar.gz
Size 11.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9f69f9833f36680f25fcda3ca935fff8df0e2ff2526046c5ad94454841e859c1
BLAKE2b-256 checksum
How to use checksums
55cd5c5856a9e3407d51a1111c2f9b6fa893e16934536a16b0656d82807249d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 9, 2025.

Transparency log

Release files / django_multi_manifest_loader-0.1.3-py3-none-any.whl

Download URL django_multi_manifest_loader-0.1.3-py3-none-any.whl
Size 9.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fdbea17d44798cd3d80ab7910b1d1f032d662984f330937622950518844a03d4
BLAKE2b-256 checksum
How to use checksums
9b50a452daf66072ee366817dcc3de612078f216cf8aef0b627055e3b6080d53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 9, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page