---
name: webpack-loader
description: "django-webpack-loader package guide for integrating Django templates with webpack bundle output"
metadata:
  languages: "python"
  versions: "3.2.3"
  revision: 1
  updated-on: "2026-03-12"
  source: maintainer
  tags: "django,webpack,staticfiles,templates,frontend,assets"
---

# django-webpack-loader Python Package Guide

## What It Does

`django-webpack-loader` connects Django templates to assets built by Webpack. It reads the JSON stats file generated by `webpack-bundle-tracker`, then renders the right `<script>` and `<link>` tags from Django templates.

This entry is pinned to `django-webpack-loader==3.2.3`, which matches the version used here and the current PyPI release as of March 12, 2026.

## Supported Stack

PyPI classifiers for `3.2.3` list:

- Python `3.8` through `3.13`
- Django `4.2`, `5.0`, `5.1`, and `5.2`

The maintainer README says support generally tracks Python, Django, and Node LTS releases, and the exact tested matrix lives in `tests/tox.ini`.

Examples in the upstream README assume Webpack 5.

## Install

Install both sides of the integration:

```bash
pip install django-webpack-loader==3.2.3
npm install --save-dev webpack-bundle-tracker
```

Common Python package-manager alternatives:

```bash
uv add django-webpack-loader==3.2.3
poetry add django-webpack-loader==3.2.3
```

`django-webpack-loader` does not build assets itself. You still need a working Webpack config and a build step that writes `webpack-stats.json`.

## Minimal Setup

### 1. Configure Webpack to emit bundle files and a stats file

```javascript
// webpack.config.js
const path = require("path");
const BundleTracker = require("webpack-bundle-tracker");

module.exports = {
  context: __dirname,
  entry: {
    main: "./assets/js/index.js",
  },
  output: {
    path: path.resolve(__dirname, "assets/webpack_bundles/"),
    publicPath: "auto",
    filename: "[name]-[contenthash].js",
    clean: true,
  },
  plugins: [
    new BundleTracker({
      path: __dirname,
      filename: "webpack-stats.json",
    }),
  ],
};
```

Important alignment points:

- Webpack `output.path`
- Webpack `output.publicPath`
- Django `STATICFILES_DIRS`
- Django `WEBPACK_LOADER.DEFAULT.BUNDLE_DIR_NAME`
- Django `WEBPACK_LOADER.DEFAULT.STATS_FILE`

If these drift, tag generation usually breaks even though the bundle build itself succeeded.

### 2. Configure Django

```python
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
DEBUG = True

INSTALLED_APPS = [
    # ...
    "webpack_loader",
]

STATIC_URL = "/static/"
STATICFILES_DIRS = [
    BASE_DIR / "assets",
]

WEBPACK_LOADER = {
    "DEFAULT": {
        "BUNDLE_DIR_NAME": "webpack_bundles/",
        "CACHE": not DEBUG,
        "STATS_FILE": BASE_DIR / "webpack-stats.json",
        "POLL_INTERVAL": 0.1,
        "IGNORE": [r".+\\.hot-update.js", r".+\\.map"],
    }
}
```

What the main settings do:

- `BUNDLE_DIR_NAME`: bundle subpath inside your static assets tree
- `CACHE`: usually `False` in development and `True` in production
- `STATS_FILE`: absolute path to the JSON file emitted by `webpack-bundle-tracker`
- `POLL_INTERVAL`: poll cadence when `CACHE=False`
- `IGNORE`: regexes for files that should not render as template tags

In production, `POLL_INTERVAL` is ignored because the loader reads the stats file once and keeps bundle paths in memory.

### 3. Build frontend assets before rendering templates

Development:

```bash
# shell 1
npx webpack --mode=development --watch

# shell 2
python manage.py runserver
```

Production:

```bash
NODE_ENV=production npx webpack --progress --bail --mode=production
python manage.py collectstatic --noinput
```

Run the Webpack build before `collectstatic`. If you reverse that order, Django may collect stale or missing bundles.

## Core Usage

### Render bundles in templates

```django
{% load render_bundle from webpack_loader %}
<!doctype html>
<html>
  <head>
    {% render_bundle "main" "css" %}
  </head>
  <body>
    {% render_bundle "main" "js" %}
  </body>
</html>
```

`render_bundle` looks up the entrypoint in `webpack-stats.json` and emits the matching tags.

### Preload assets

```django
{% load render_bundle from webpack_loader %}
{% render_bundle "main" "css" is_preload=True %}
{% render_bundle "main" "js" is_preload=True %}
```

Use `is_preload=True` when you want preload link tags in addition to normal rendering.

### Avoid duplicate shared chunks

```django
{% load render_bundle from webpack_loader %}
{% render_bundle "vendor" "js" skip_common_chunks=True %}
{% render_bundle "dashboard" "js" skip_common_chunks=True %}
```

For `skip_common_chunks` to work, the template context must include `request`. In typical Django setups that means keeping `django.template.context_processors.request` enabled.

### Access the public URL for a Webpack-managed static file

```django
{% load webpack_static from webpack_loader %}
<img src="{% webpack_static 'logo.png' %}" alt="Logo">
```

`webpack_static` returns the public path for the original asset. It does not necessarily return the hashed filename generated when that asset is imported and transformed inside JavaScript.

### Get file URLs without rendering tags

```django
{% load get_files from webpack_loader %}
{% get_files "editor" "css" as editor_css_files %}
<link rel="stylesheet" href="{{ editor_css_files.0.url }}">
```

Use `get_files` when another library needs a URL rather than a rendered `<script>` or `<link>` tag.

## Configuration Patterns

### Multiple Webpack stats files

```python
WEBPACK_LOADER = {
    "DEFAULT": {
        "BUNDLE_DIR_NAME": "webpack_bundles/",
        "STATS_FILE": BASE_DIR / "webpack-stats.json",
    },
    "DASHBOARD": {
        "BUNDLE_DIR_NAME": "dashboard_bundles/",
        "STATS_FILE": BASE_DIR / "webpack-stats-dashboard.json",
    },
}
```

```django
{% load render_bundle from webpack_loader %}
{% render_bundle "main" config="DASHBOARD" extension="js" %}
```

Use separate configs when different frontend builds emit different stats files.

### Custom loader classes and remote stats files

`LOADER_CLASS` lets you replace the default filesystem-backed loader. This is the main extension point when your stats file lives in object storage, a cache, a database, or an authenticated HTTP endpoint.

```python
import requests
from webpack_loader.loaders import WebpackLoader

class ExternalWebpackLoader(WebpackLoader):
    def load_assets(self):
        response = requests.get(
            self.config["STATS_URL"],
            headers={"Authorization": f"Bearer {self.config['STATS_TOKEN']}"},
            timeout=5,
        )
        response.raise_for_status()
        return response.json()

WEBPACK_LOADER = {
    "DEFAULT": {
        "LOADER_CLASS": "project.loaders.ExternalWebpackLoader",
        "STATS_URL": "https://assets.example.com/webpack-stats.json",
        "STATS_TOKEN": "...",
    }
}
```

The package has no built-in auth model. If stats come from a protected service, keep credentials inside your loader implementation and normal Django settings or secret management.

### Security-related settings

Upstream documents these options for stricter frontend delivery:

- `INTEGRITY`: emit Subresource Integrity attributes when the stats file includes integrity hashes
- `CROSSORIGIN`: set the `crossorigin` attribute for cross-origin asset loading
- `CSP_NONCE`: add nonces for `django-csp` with strict CSP policies
- `TIMEOUT`: bound how long the loader waits for an in-progress build

These settings only help if the Webpack side is configured consistently. For example, `INTEGRITY` depends on integrity data being present in the stats output.

## Testing

Template rendering fails in tests if the test process expects a real stats file but no frontend build ran first. The documented escape hatch is:

```python
WEBPACK_LOADER["DEFAULT"]["LOADER_CLASS"] = "webpack_loader.loaders.FakeWebpackLoader"
```

Use that in test settings when unit tests should render templates without invoking the frontend pipeline.

## Common Pitfalls

### Stats file path mismatch

The most common failure is that Webpack writes `webpack-stats.json` to one location while Django reads from another. Verify the exact absolute path on both sides.

### `STATICFILES_DIRS`, `BUNDLE_DIR_NAME`, and `output.path` do not describe the same tree

If these settings disagree, `render_bundle` can emit URLs that `collectstatic` never published.

### Build order is wrong in production

Run Webpack first, then `collectstatic`. If a platform auto-runs `collectstatic`, override that behavior and invoke it after the Webpack build.

### `skip_common_chunks` does not work

This usually means `request` is missing from the template context.

### `webpack_static` returns a different file than JavaScript imports use

That is expected when Webpack post-processes or hashes imported assets. `webpack_static` is for the original asset path.

### Cross-origin bundles need more than just a CDN URL

If bundles load from another origin, verify `publicPath`, and if you enable Subresource Integrity also set `CROSSORIGIN` consistently.

## Version-Sensitive Notes

- `3.2.3` is the current PyPI release documented here.
- Upstream examples are written for Webpack 5.
- The maintainer README recommends keeping at least minor-version parity between `django-webpack-loader` and `webpack-bundle-tracker` when dealing with older migrations.
- If you are migrating code from `django-webpack-loader<1.0.0`, you also need `webpack-bundle-tracker>=1.0.0`.
- For exact tested compatibility, check the package's `tests/tox.ini` in the upstream repository rather than guessing from third-party blog posts.

## Official Sources

- Repository / maintainer docs: https://github.com/django-webpack/django-webpack-loader
- PyPI package page: https://pypi.org/project/django-webpack-loader/
