CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-vite

Integration of Vite in a Django project.

Pending
Overview
Eval results
Files

asset-loading.mddocs/

Asset Loading

Core asset loading system that manages Vite assets programmatically, handles manifest parsing and URL generation, and provides the foundation for Django template tag functionality.

Capabilities

Asset Loader Singleton

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')

Asset Generation Methods

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')

Development Support Methods

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")

Legacy Browser Support Methods

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)

App Client Management

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')

URL Generation Methods

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 storage

Manifest Client

Handles 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}")

Manifest Parsing Utilities

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
    """

Manifest Entry Data

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 dependencies

Manifest 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)}")

Error Handling and Debugging

System Checks

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}")

Exception Handling

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 path

Debug Asset Loading

def 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")

HTML Tag Generation Utilities

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=""'

Performance Considerations

Singleton Benefits

The DjangoViteAssetLoader singleton pattern ensures:

  • Manifest files are parsed once and cached in memory
  • Configuration is loaded once at startup
  • Multiple asset requests reuse parsed data

Manifest Parsing

  • Manifest parsing happens once when dev_mode=False
  • Parsing errors are cached to avoid repeated file system access
  • System checks validate manifests at startup

Development vs Production

Development Mode:

  • No manifest parsing required
  • Direct URLs to Vite dev server
  • Minimal overhead per request

Production Mode:

  • Manifest parsed once at startup
  • Asset dependencies resolved from cached manifest data
  • Static file URLs generated using Django's staticfiles system

Install with Tessl CLI

npx tessl i tessl/pypi-django-vite

docs

asset-loading.md

configuration.md

index.md

template-tags.md

tile.json