Standalone template tag for loading webpack manifest files from multiple Django packages/apps
Project description
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:
- Loads the main webpack manifest (from your dashboard/main app)
- Automatically discovers and loads manifest files from all installed Django packages
- Namespaces manifests by app to prevent naming collisions
- Auto-detects the current app from template context for seamless usage
- Makes all assets available via the
{% manifest %}template tag - Zero dependencies - doesn't rely on unmaintained packages like
django-manifest-loader
Key Features
- Automatic Namespacing: Each app's manifest is namespaced, so
config.jsinpackage1doesn't conflict withconfig.jsinpackage2 - 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:
- Discovery: Finds
manifest.jsonfiles in all Django apps using staticfiles finders - Namespacing: Each app's manifest is stored under its app name (e.g.,
package1,package2) - Auto-Detection: When rendering a template, extracts the app name from the template path (e.g.,
package1/form.html→package1) - 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:
- Main manifest: Searches for
manifest.jsonin static directories - Package manifests: Iterates through all
INSTALLED_APPSand checks each for<app_name>/manifest.json - Merging: All found manifests are merged into a single dictionary (later entries override earlier ones)
- 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:
- Runs all tests across Python 3.10-3.12 and Django 4.2-5.1
- Runs all linters (flake8, black, isort, ruff)
- Builds the package
- 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_multi_manifest_loader-0.1.3.tar.gz.
File metadata
- Download URL: django_multi_manifest_loader-0.1.3.tar.gz
- Upload date:
- Size: 11.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f69f9833f36680f25fcda3ca935fff8df0e2ff2526046c5ad94454841e859c1
|
|
| MD5 |
68e3bc7f8e7f29f97e9f65f9b1b6b10e
|
|
| BLAKE2b-256 |
55cd5c5856a9e3407d51a1111c2f9b6fa893e16934536a16b0656d82807249d5
|
Provenance
The following attestation bundles were made for django_multi_manifest_loader-0.1.3.tar.gz:
Publisher:
ci.yml on pescheckit/django-multi-manifest-loader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_multi_manifest_loader-0.1.3.tar.gz -
Subject digest:
9f69f9833f36680f25fcda3ca935fff8df0e2ff2526046c5ad94454841e859c1 - Sigstore transparency entry: 753324893
- Sigstore integration time:
-
Permalink:
pescheckit/django-multi-manifest-loader@5a6d18c276cd9e509b8db59b551a6e8a03c8772e -
Branch / Tag:
refs/tags/0.1.3 - Owner: https://github.com/pescheckit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@5a6d18c276cd9e509b8db59b551a6e8a03c8772e -
Trigger Event:
release
-
Statement type:
File details
Details for the file django_multi_manifest_loader-0.1.3-py3-none-any.whl.
File metadata
- Download URL: django_multi_manifest_loader-0.1.3-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdbea17d44798cd3d80ab7910b1d1f032d662984f330937622950518844a03d4
|
|
| MD5 |
02456a33fc43d8c4669eb570a7e6a3eb
|
|
| BLAKE2b-256 |
9b50a452daf66072ee366817dcc3de612078f216cf8aef0b627055e3b6080d53
|
Provenance
The following attestation bundles were made for django_multi_manifest_loader-0.1.3-py3-none-any.whl:
Publisher:
ci.yml on pescheckit/django-multi-manifest-loader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_multi_manifest_loader-0.1.3-py3-none-any.whl -
Subject digest:
fdbea17d44798cd3d80ab7910b1d1f032d662984f330937622950518844a03d4 - Sigstore transparency entry: 753324896
- Sigstore integration time:
-
Permalink:
pescheckit/django-multi-manifest-loader@5a6d18c276cd9e509b8db59b551a6e8a03c8772e -
Branch / Tag:
refs/tags/0.1.3 - Owner: https://github.com/pescheckit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@5a6d18c276cd9e509b8db59b551a6e8a03c8772e -
Trigger Event:
release
-
Statement type: