Integration of Vite in a Django project.
—
Core asset loading system that manages Vite assets programmatically, handles manifest parsing and URL generation, and provides the foundation for Django template tag functionality.
Central singleton class managing all Vite app configurations and asset loading operations.
class DjangoViteAssetLoader:
"""
Singleton class handling Vite asset loading across multiple app configurations.
Routes asset and URL generation to appropriate DjangoViteAppClient instances.
"""
@classmethod
def instance(cls) -> 'DjangoViteAssetLoader':
"""
Get singleton instance.
Returns:
DjangoViteAssetLoader: Only instance of the class
"""
def check(self, **kwargs) -> List[Warning]:
"""
Check manifest files validity for apps with dev_mode=False.
Returns:
List of Django system check warnings
"""Basic Usage:
from django_vite.core.asset_loader import DjangoViteAssetLoader
# Get singleton instance
loader = DjangoViteAssetLoader.instance()
# Generate asset HTML
asset_html = loader.generate_vite_asset('src/main.js')
# Get asset URL only
asset_url = loader.generate_vite_asset_url('src/logo.png')Generate HTML tags and URLs for Vite-managed assets.
def generate_vite_asset(
self,
path: str,
app: str = "default",
**kwargs
) -> str:
"""
Generate script/link tags for JS/TS asset with dependencies.
Args:
path: Path to Vite JS/TS asset
app: App configuration name (default: "default")
**kwargs: Additional attributes for generated tags
Returns:
HTML string with all required tags
Raises:
DjangoViteConfigNotFoundError: If app config not found
DjangoViteAssetNotFoundError: If asset not found (production only)
"""
def generate_vite_asset_url(self, path: str, app: str = "default") -> str:
"""
Generate URL for Vite-managed asset.
Args:
path: Path to Vite asset
app: App configuration name (default: "default")
Returns:
Asset URL string
"""
def preload_vite_asset(self, path: str, app: str = "default") -> str:
"""
Generate modulepreload tags for JS/TS asset and dependencies.
Args:
path: Path to Vite JS/TS asset
app: App configuration name (default: "default")
Returns:
HTML string with preload link tags
"""Asset Generation Examples:
loader = DjangoViteAssetLoader.instance()
# Basic asset generation
main_js = loader.generate_vite_asset('src/main.js')
# With custom attributes
analytics_js = loader.generate_vite_asset(
'src/analytics.js',
defer=True,
data_module="analytics"
)
# Multi-app usage
admin_js = loader.generate_vite_asset('src/admin.js', app='admin')
# Asset URL only
logo_url = loader.generate_vite_asset_url('src/images/logo.png')
# Preload assets
preload_html = loader.preload_vite_asset('src/main.js')Generate HMR client and React refresh scripts for development mode.
def generate_vite_ws_client(self, app: str = "default", **kwargs) -> str:
"""
Generate Vite WebSocket client for HMR.
Args:
app: App configuration name (default: "default")
**kwargs: Additional attributes for script tag
Returns:
Script tag HTML (empty in production)
"""
def generate_vite_react_refresh_url(self, app: str = "default", **kwargs) -> str:
"""
Generate Vite React Refresh runtime script.
Args:
app: App configuration name (default: "default")
**kwargs: Additional attributes for script tags
Returns:
Inline script HTML (empty in production)
"""Development Examples:
loader = DjangoViteAssetLoader.instance()
# HMR client
hmr_client = loader.generate_vite_ws_client()
# React refresh runtime
react_refresh = loader.generate_vite_react_refresh_url()
# With custom attributes
hmr_with_attrs = loader.generate_vite_ws_client(data_turbo_track="reload")Generate legacy browser polyfills and asset versions.
def generate_vite_legacy_polyfills(
self,
app: str = "default",
nomodule: bool = True,
**kwargs
) -> str:
"""
Generate legacy browser polyfills script tag.
Args:
app: App configuration name (default: "default")
nomodule: Set nomodule attribute (default: True)
**kwargs: Additional attributes for script tag
Returns:
Script tag HTML (empty in development)
Raises:
DjangoViteAssetNotFoundError: If polyfills not found in manifest
"""
def generate_vite_legacy_asset(
self,
path: str,
app: str = "default",
**kwargs
) -> str:
"""
Generate legacy asset script tag.
Args:
path: Path to legacy asset (must contain '-legacy')
app: App configuration name (default: "default")
**kwargs: Additional attributes for script tag
Returns:
Script tag HTML (empty in development)
"""Legacy Support Examples:
loader = DjangoViteAssetLoader.instance()
# Legacy polyfills
polyfills = loader.generate_vite_legacy_polyfills()
# Legacy asset
legacy_main = loader.generate_vite_legacy_asset('src/main-legacy.js')
# Without nomodule attribute
polyfills_no_nomodule = loader.generate_vite_legacy_polyfills(nomodule=False)Individual app client for managing assets within a specific Vite app configuration.
class DjangoViteAppClient:
"""
Interface for generating assets and URLs from one Vite app configuration.
"""
def __init__(self, config: DjangoViteConfig, app_name: str = "default"):
"""
Initialize app client with configuration.
Args:
config: DjangoViteConfig instance
app_name: Name of the app configuration
"""
def generate_vite_asset(self, path: str, **kwargs) -> str:
"""Generate script/link tags for JS/TS asset with dependencies."""
def preload_vite_asset(self, path: str) -> str:
"""Generate modulepreload tags for JS/TS asset."""
def generate_vite_asset_url(self, path: str) -> str:
"""Generate URL for Vite-managed asset."""Direct App Client Usage:
from django_vite.core.asset_loader import DjangoViteAppClient
from django_vite import DjangoViteConfig
# Create custom configuration
config = DjangoViteConfig(
dev_mode=False,
dev_server_port=3000,
static_url_prefix="custom/"
)
# Create app client
client = DjangoViteAppClient(config, app_name="custom")
# Generate assets
asset_html = client.generate_vite_asset('src/main.js')
asset_url = client.generate_vite_asset_url('src/logo.png')Low-level URL generation for development and production servers.
def get_dev_server_url(self, path: str) -> str:
"""
Generate URL to asset served by Vite development server.
Args:
path: Path to asset
Returns:
Full URL to development server asset
"""
def get_production_server_url(self, path: str) -> str:
"""
Generate URL to asset served during production.
Args:
path: Path to asset
Returns:
Production server URL (may use Django staticfiles)
"""URL Generation Examples:
# Get app client
loader = DjangoViteAssetLoader.instance()
client = loader._get_app_client("default")
# Development URL
dev_url = client.get_dev_server_url('src/main.js')
# Result: "http://localhost:5173/static/src/main.js"
# Production URL
prod_url = client.get_production_server_url('main.abc123.js')
# Result: "/static/main.abc123.js" or CDN URL if using staticfiles storageHandles parsing and accessing entries from Vite's manifest.json file.
class ManifestClient:
"""
Client for accessing entries in compiled Vite config's manifest.json.
Only parses manifest.json when dev_mode=False.
"""
def __init__(self, config: DjangoViteConfig, app_name: str = "default"):
"""
Initialize manifest client.
Args:
config: DjangoViteConfig instance
app_name: Name of the app configuration
"""
def get(self, path: str) -> ManifestEntry:
"""
Get ManifestEntry for given path.
Args:
path: Asset path in manifest
Returns:
ManifestEntry with file info and dependencies
Raises:
DjangoViteAssetNotFoundError: If path not found in manifest
"""
def check(self) -> List[Warning]:
"""
Check manifest file validity.
Returns:
List of Django system check warnings
"""
def load_manifest(self) -> dict:
"""
Read and parse manifest.json file.
Returns:
Dictionary with manifest contents
Raises:
DjangoViteManifestError: If manifest cannot be loaded or parsed
"""Manifest Client Usage:
from django_vite.core.asset_loader import DjangoViteAssetLoader
loader = DjangoViteAssetLoader.instance()
client = loader._get_app_client("default")
manifest = client.manifest
# Get manifest entry
try:
entry = manifest.get('src/main.js')
print(f"Compiled file: {entry.file}")
print(f"CSS dependencies: {entry.css}")
print(f"JS imports: {entry.imports}")
except DjangoViteAssetNotFoundError:
print("Asset not found in manifest")
# Check manifest validity
warnings = manifest.check()
for warning in warnings:
print(f"Manifest issue: {warning.msg}")
# Load raw manifest data
try:
raw_manifest = manifest.load_manifest()
print(f"Found {len(raw_manifest)} entries")
except DjangoViteManifestError as e:
print(f"Manifest error: {e}")Internal utilities for parsing and processing Vite manifest files.
class ParsedManifestOutput(NamedTuple):
"""Output from manifest parsing operations."""
entries: Dict[str, ManifestEntry] = {}
legacy_polyfills_entry: Optional[ManifestEntry] = None
def _parse_manifest(self) -> ParsedManifestOutput:
"""
Read and parse the Vite manifest file.
Returns:
ParsedManifestOutput with entries and legacy polyfills entry
Raises:
DjangoViteManifestError: If cannot load file or JSON is malformed
"""Data structure representing an entry in Vite's manifest.json.
class ManifestEntry(NamedTuple):
"""
Represents an entry for a file inside the manifest.json.
"""
file: str # Compiled output file path
src: Optional[str] = None # Original source file path
isEntry: Optional[bool] = False # Whether it's an entry point
isDynamicEntry: Optional[bool] = False # Whether it's a dynamic entry
css: Optional[List[str]] = [] # CSS file dependencies
imports: Optional[List[str]] = [] # JavaScript import dependencies
dynamicImports: Optional[List[str]] = [] # Dynamic import dependenciesManifest Entry Example:
# Example manifest entry for 'src/main.js'
entry = ManifestEntry(
file='assets/main.abc123.js',
src='src/main.js',
isEntry=True,
css=['assets/main.def456.css'],
imports=['src/vendor.js'],
dynamicImports=['src/lazy-component.js']
)
# Access entry data
print(f"Output file: {entry.file}")
print(f"CSS files: {', '.join(entry.css)}")
print(f"Dependencies: {', '.join(entry.imports)}")Django-vite includes Django system checks for validating configurations and manifest files.
# Manual system check
from django_vite.core.asset_loader import DjangoViteAssetLoader
loader = DjangoViteAssetLoader.instance()
warnings = loader.check()
for warning in warnings:
print(f"{warning.id}: {warning.msg}")
if warning.hint:
print(f"Hint: {warning.hint}")from django_vite.core.exceptions import (
DjangoViteAssetNotFoundError,
DjangoViteManifestError,
DjangoViteConfigNotFoundError
)
loader = DjangoViteAssetLoader.instance()
try:
asset_html = loader.generate_vite_asset('src/missing.js')
except DjangoViteAssetNotFoundError as e:
print(f"Asset not found: {e}")
# Check manifest.json or Vite build configuration
except DjangoViteConfigNotFoundError as e:
print(f"Configuration error: {e}")
# Check DJANGO_VITE settings
except DjangoViteManifestError as e:
print(f"Manifest error: {e}")
# Check manifest.json file and pathdef debug_asset_loading():
"""Debug django-vite asset loading configuration."""
loader = DjangoViteAssetLoader.instance()
# Check all app configurations
for app_name, client in loader._apps.items():
print(f"\nApp: {app_name}")
print(f"Dev mode: {client.dev_mode}")
if client.dev_mode:
print(f"Dev server: {client.dev_server_protocol}://{client.dev_server_host}:{client.dev_server_port}")
else:
print(f"Manifest path: {client.manifest.manifest_path}")
# Check manifest validity
warnings = client.manifest.check()
if warnings:
for warning in warnings:
print(f"Warning: {warning.msg}")
else:
print("Manifest is valid")Low-level utilities for generating HTML tags used by the asset loading system.
class TagGenerator:
"""Static methods for generating HTML tags."""
@staticmethod
def script(src: str, attrs: Dict[str, str]) -> str:
"""
Generate HTML script tag.
Args:
src: Source URL for the script
attrs: Dictionary of HTML attributes
Returns:
HTML script tag string
"""
@staticmethod
def stylesheet(href: str, attrs: Optional[Dict[str, str]] = None) -> str:
"""
Generate HTML link tag for CSS stylesheets.
Args:
href: CSS file URL
attrs: Optional dictionary of HTML attributes
Returns:
HTML link tag string
"""
@staticmethod
def stylesheet_preload(href: str, attrs: Optional[Dict[str, str]] = None) -> str:
"""
Generate HTML link preload tag for CSS.
Args:
href: CSS file URL
attrs: Optional dictionary of HTML attributes
Returns:
HTML link preload tag string
"""
@staticmethod
def preload(href: str, attrs: Dict[str, str]) -> str:
"""
Generate HTML link preload tag.
Args:
href: Resource URL
attrs: Dictionary of HTML attributes
Returns:
HTML link tag string
"""
def attrs_to_str(attrs: Dict[str, str]) -> str:
"""
Convert dictionary of attributes to HTML attribute string.
Args:
attrs: Dictionary of attribute name-value pairs
Returns:
Formatted HTML attributes string
"""Tag Generation Examples:
from django_vite.core.tag_generator import TagGenerator, attrs_to_str
# Generate script tag
script = TagGenerator.script(
'https://example.com/script.js',
{'type': 'module', 'defer': ''}
)
# Result: '<script type="module" defer="" src="https://example.com/script.js"></script>'
# Generate stylesheet link
css = TagGenerator.stylesheet(
'https://example.com/styles.css',
{'media': 'print'}
)
# Result: '<link media="print" rel="stylesheet" href="https://example.com/styles.css" />'
# Generate preload link
preload = TagGenerator.preload(
'https://example.com/font.woff2',
{'as': 'font', 'type': 'font/woff2', 'crossorigin': ''}
)
# Result: '<link href="https://example.com/font.woff2" as="font" type="font/woff2" crossorigin="" />'
# Convert attributes dictionary to string
attrs_str = attrs_to_str({'data-module': 'app', 'defer': ''})
# Result: 'data-module="app" defer=""'The DjangoViteAssetLoader singleton pattern ensures:
Development Mode:
Production Mode:
Install with Tessl CLI
npx tessl i tessl/pypi-django-vite