or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-loading.mdconfiguration.mdindex.mdtemplate-tags.md

asset-loading.mddocs/

0

# Asset Loading

1

2

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

3

4

## Capabilities

5

6

### Asset Loader Singleton

7

8

Central singleton class managing all Vite app configurations and asset loading operations.

9

10

```python { .api }

11

class DjangoViteAssetLoader:

12

"""

13

Singleton class handling Vite asset loading across multiple app configurations.

14

15

Routes asset and URL generation to appropriate DjangoViteAppClient instances.

16

"""

17

18

@classmethod

19

def instance(cls) -> 'DjangoViteAssetLoader':

20

"""

21

Get singleton instance.

22

23

Returns:

24

DjangoViteAssetLoader: Only instance of the class

25

"""

26

27

def check(self, **kwargs) -> List[Warning]:

28

"""

29

Check manifest files validity for apps with dev_mode=False.

30

31

Returns:

32

List of Django system check warnings

33

"""

34

```

35

36

**Basic Usage:**

37

```python

38

from django_vite.core.asset_loader import DjangoViteAssetLoader

39

40

# Get singleton instance

41

loader = DjangoViteAssetLoader.instance()

42

43

# Generate asset HTML

44

asset_html = loader.generate_vite_asset('src/main.js')

45

46

# Get asset URL only

47

asset_url = loader.generate_vite_asset_url('src/logo.png')

48

```

49

50

### Asset Generation Methods

51

52

Generate HTML tags and URLs for Vite-managed assets.

53

54

```python { .api }

55

def generate_vite_asset(

56

self,

57

path: str,

58

app: str = "default",

59

**kwargs

60

) -> str:

61

"""

62

Generate script/link tags for JS/TS asset with dependencies.

63

64

Args:

65

path: Path to Vite JS/TS asset

66

app: App configuration name (default: "default")

67

**kwargs: Additional attributes for generated tags

68

69

Returns:

70

HTML string with all required tags

71

72

Raises:

73

DjangoViteConfigNotFoundError: If app config not found

74

DjangoViteAssetNotFoundError: If asset not found (production only)

75

"""

76

77

def generate_vite_asset_url(self, path: str, app: str = "default") -> str:

78

"""

79

Generate URL for Vite-managed asset.

80

81

Args:

82

path: Path to Vite asset

83

app: App configuration name (default: "default")

84

85

Returns:

86

Asset URL string

87

"""

88

89

def preload_vite_asset(self, path: str, app: str = "default") -> str:

90

"""

91

Generate modulepreload tags for JS/TS asset and dependencies.

92

93

Args:

94

path: Path to Vite JS/TS asset

95

app: App configuration name (default: "default")

96

97

Returns:

98

HTML string with preload link tags

99

"""

100

```

101

102

**Asset Generation Examples:**

103

```python

104

loader = DjangoViteAssetLoader.instance()

105

106

# Basic asset generation

107

main_js = loader.generate_vite_asset('src/main.js')

108

109

# With custom attributes

110

analytics_js = loader.generate_vite_asset(

111

'src/analytics.js',

112

defer=True,

113

data_module="analytics"

114

)

115

116

# Multi-app usage

117

admin_js = loader.generate_vite_asset('src/admin.js', app='admin')

118

119

# Asset URL only

120

logo_url = loader.generate_vite_asset_url('src/images/logo.png')

121

122

# Preload assets

123

preload_html = loader.preload_vite_asset('src/main.js')

124

```

125

126

### Development Support Methods

127

128

Generate HMR client and React refresh scripts for development mode.

129

130

```python { .api }

131

def generate_vite_ws_client(self, app: str = "default", **kwargs) -> str:

132

"""

133

Generate Vite WebSocket client for HMR.

134

135

Args:

136

app: App configuration name (default: "default")

137

**kwargs: Additional attributes for script tag

138

139

Returns:

140

Script tag HTML (empty in production)

141

"""

142

143

def generate_vite_react_refresh_url(self, app: str = "default", **kwargs) -> str:

144

"""

145

Generate Vite React Refresh runtime script.

146

147

Args:

148

app: App configuration name (default: "default")

149

**kwargs: Additional attributes for script tags

150

151

Returns:

152

Inline script HTML (empty in production)

153

"""

154

```

155

156

**Development Examples:**

157

```python

158

loader = DjangoViteAssetLoader.instance()

159

160

# HMR client

161

hmr_client = loader.generate_vite_ws_client()

162

163

# React refresh runtime

164

react_refresh = loader.generate_vite_react_refresh_url()

165

166

# With custom attributes

167

hmr_with_attrs = loader.generate_vite_ws_client(data_turbo_track="reload")

168

```

169

170

### Legacy Browser Support Methods

171

172

Generate legacy browser polyfills and asset versions.

173

174

```python { .api }

175

def generate_vite_legacy_polyfills(

176

self,

177

app: str = "default",

178

nomodule: bool = True,

179

**kwargs

180

) -> str:

181

"""

182

Generate legacy browser polyfills script tag.

183

184

Args:

185

app: App configuration name (default: "default")

186

nomodule: Set nomodule attribute (default: True)

187

**kwargs: Additional attributes for script tag

188

189

Returns:

190

Script tag HTML (empty in development)

191

192

Raises:

193

DjangoViteAssetNotFoundError: If polyfills not found in manifest

194

"""

195

196

def generate_vite_legacy_asset(

197

self,

198

path: str,

199

app: str = "default",

200

**kwargs

201

) -> str:

202

"""

203

Generate legacy asset script tag.

204

205

Args:

206

path: Path to legacy asset (must contain '-legacy')

207

app: App configuration name (default: "default")

208

**kwargs: Additional attributes for script tag

209

210

Returns:

211

Script tag HTML (empty in development)

212

"""

213

```

214

215

**Legacy Support Examples:**

216

```python

217

loader = DjangoViteAssetLoader.instance()

218

219

# Legacy polyfills

220

polyfills = loader.generate_vite_legacy_polyfills()

221

222

# Legacy asset

223

legacy_main = loader.generate_vite_legacy_asset('src/main-legacy.js')

224

225

# Without nomodule attribute

226

polyfills_no_nomodule = loader.generate_vite_legacy_polyfills(nomodule=False)

227

```

228

229

### App Client Management

230

231

Individual app client for managing assets within a specific Vite app configuration.

232

233

```python { .api }

234

class DjangoViteAppClient:

235

"""

236

Interface for generating assets and URLs from one Vite app configuration.

237

"""

238

239

def __init__(self, config: DjangoViteConfig, app_name: str = "default"):

240

"""

241

Initialize app client with configuration.

242

243

Args:

244

config: DjangoViteConfig instance

245

app_name: Name of the app configuration

246

"""

247

248

def generate_vite_asset(self, path: str, **kwargs) -> str:

249

"""Generate script/link tags for JS/TS asset with dependencies."""

250

251

def preload_vite_asset(self, path: str) -> str:

252

"""Generate modulepreload tags for JS/TS asset."""

253

254

def generate_vite_asset_url(self, path: str) -> str:

255

"""Generate URL for Vite-managed asset."""

256

```

257

258

**Direct App Client Usage:**

259

```python

260

from django_vite.core.asset_loader import DjangoViteAppClient

261

from django_vite import DjangoViteConfig

262

263

# Create custom configuration

264

config = DjangoViteConfig(

265

dev_mode=False,

266

dev_server_port=3000,

267

static_url_prefix="custom/"

268

)

269

270

# Create app client

271

client = DjangoViteAppClient(config, app_name="custom")

272

273

# Generate assets

274

asset_html = client.generate_vite_asset('src/main.js')

275

asset_url = client.generate_vite_asset_url('src/logo.png')

276

```

277

278

### URL Generation Methods

279

280

Low-level URL generation for development and production servers.

281

282

```python { .api }

283

def get_dev_server_url(self, path: str) -> str:

284

"""

285

Generate URL to asset served by Vite development server.

286

287

Args:

288

path: Path to asset

289

290

Returns:

291

Full URL to development server asset

292

"""

293

294

def get_production_server_url(self, path: str) -> str:

295

"""

296

Generate URL to asset served during production.

297

298

Args:

299

path: Path to asset

300

301

Returns:

302

Production server URL (may use Django staticfiles)

303

"""

304

```

305

306

**URL Generation Examples:**

307

```python

308

# Get app client

309

loader = DjangoViteAssetLoader.instance()

310

client = loader._get_app_client("default")

311

312

# Development URL

313

dev_url = client.get_dev_server_url('src/main.js')

314

# Result: "http://localhost:5173/static/src/main.js"

315

316

# Production URL

317

prod_url = client.get_production_server_url('main.abc123.js')

318

# Result: "/static/main.abc123.js" or CDN URL if using staticfiles storage

319

```

320

321

### Manifest Client

322

323

Handles parsing and accessing entries from Vite's manifest.json file.

324

325

```python { .api }

326

class ManifestClient:

327

"""

328

Client for accessing entries in compiled Vite config's manifest.json.

329

Only parses manifest.json when dev_mode=False.

330

"""

331

332

def __init__(self, config: DjangoViteConfig, app_name: str = "default"):

333

"""

334

Initialize manifest client.

335

336

Args:

337

config: DjangoViteConfig instance

338

app_name: Name of the app configuration

339

"""

340

341

def get(self, path: str) -> ManifestEntry:

342

"""

343

Get ManifestEntry for given path.

344

345

Args:

346

path: Asset path in manifest

347

348

Returns:

349

ManifestEntry with file info and dependencies

350

351

Raises:

352

DjangoViteAssetNotFoundError: If path not found in manifest

353

"""

354

355

def check(self) -> List[Warning]:

356

"""

357

Check manifest file validity.

358

359

Returns:

360

List of Django system check warnings

361

"""

362

363

def load_manifest(self) -> dict:

364

"""

365

Read and parse manifest.json file.

366

367

Returns:

368

Dictionary with manifest contents

369

370

Raises:

371

DjangoViteManifestError: If manifest cannot be loaded or parsed

372

"""

373

```

374

375

**Manifest Client Usage:**

376

```python

377

from django_vite.core.asset_loader import DjangoViteAssetLoader

378

379

loader = DjangoViteAssetLoader.instance()

380

client = loader._get_app_client("default")

381

manifest = client.manifest

382

383

# Get manifest entry

384

try:

385

entry = manifest.get('src/main.js')

386

print(f"Compiled file: {entry.file}")

387

print(f"CSS dependencies: {entry.css}")

388

print(f"JS imports: {entry.imports}")

389

except DjangoViteAssetNotFoundError:

390

print("Asset not found in manifest")

391

392

# Check manifest validity

393

warnings = manifest.check()

394

for warning in warnings:

395

print(f"Manifest issue: {warning.msg}")

396

397

# Load raw manifest data

398

try:

399

raw_manifest = manifest.load_manifest()

400

print(f"Found {len(raw_manifest)} entries")

401

except DjangoViteManifestError as e:

402

print(f"Manifest error: {e}")

403

```

404

405

### Manifest Parsing Utilities

406

407

Internal utilities for parsing and processing Vite manifest files.

408

409

```python { .api }

410

class ParsedManifestOutput(NamedTuple):

411

"""Output from manifest parsing operations."""

412

entries: Dict[str, ManifestEntry] = {}

413

legacy_polyfills_entry: Optional[ManifestEntry] = None

414

415

def _parse_manifest(self) -> ParsedManifestOutput:

416

"""

417

Read and parse the Vite manifest file.

418

419

Returns:

420

ParsedManifestOutput with entries and legacy polyfills entry

421

422

Raises:

423

DjangoViteManifestError: If cannot load file or JSON is malformed

424

"""

425

```

426

427

### Manifest Entry Data

428

429

Data structure representing an entry in Vite's manifest.json.

430

431

```python { .api }

432

class ManifestEntry(NamedTuple):

433

"""

434

Represents an entry for a file inside the manifest.json.

435

"""

436

437

file: str # Compiled output file path

438

src: Optional[str] = None # Original source file path

439

isEntry: Optional[bool] = False # Whether it's an entry point

440

isDynamicEntry: Optional[bool] = False # Whether it's a dynamic entry

441

css: Optional[List[str]] = [] # CSS file dependencies

442

imports: Optional[List[str]] = [] # JavaScript import dependencies

443

dynamicImports: Optional[List[str]] = [] # Dynamic import dependencies

444

```

445

446

**Manifest Entry Example:**

447

```python

448

# Example manifest entry for 'src/main.js'

449

entry = ManifestEntry(

450

file='assets/main.abc123.js',

451

src='src/main.js',

452

isEntry=True,

453

css=['assets/main.def456.css'],

454

imports=['src/vendor.js'],

455

dynamicImports=['src/lazy-component.js']

456

)

457

458

# Access entry data

459

print(f"Output file: {entry.file}")

460

print(f"CSS files: {', '.join(entry.css)}")

461

print(f"Dependencies: {', '.join(entry.imports)}")

462

```

463

464

## Error Handling and Debugging

465

466

### System Checks

467

468

Django-vite includes Django system checks for validating configurations and manifest files.

469

470

```python

471

# Manual system check

472

from django_vite.core.asset_loader import DjangoViteAssetLoader

473

474

loader = DjangoViteAssetLoader.instance()

475

warnings = loader.check()

476

477

for warning in warnings:

478

print(f"{warning.id}: {warning.msg}")

479

if warning.hint:

480

print(f"Hint: {warning.hint}")

481

```

482

483

### Exception Handling

484

485

```python

486

from django_vite.core.exceptions import (

487

DjangoViteAssetNotFoundError,

488

DjangoViteManifestError,

489

DjangoViteConfigNotFoundError

490

)

491

492

loader = DjangoViteAssetLoader.instance()

493

494

try:

495

asset_html = loader.generate_vite_asset('src/missing.js')

496

except DjangoViteAssetNotFoundError as e:

497

print(f"Asset not found: {e}")

498

# Check manifest.json or Vite build configuration

499

500

except DjangoViteConfigNotFoundError as e:

501

print(f"Configuration error: {e}")

502

# Check DJANGO_VITE settings

503

504

except DjangoViteManifestError as e:

505

print(f"Manifest error: {e}")

506

# Check manifest.json file and path

507

```

508

509

### Debug Asset Loading

510

511

```python

512

def debug_asset_loading():

513

"""Debug django-vite asset loading configuration."""

514

loader = DjangoViteAssetLoader.instance()

515

516

# Check all app configurations

517

for app_name, client in loader._apps.items():

518

print(f"\nApp: {app_name}")

519

print(f"Dev mode: {client.dev_mode}")

520

521

if client.dev_mode:

522

print(f"Dev server: {client.dev_server_protocol}://{client.dev_server_host}:{client.dev_server_port}")

523

else:

524

print(f"Manifest path: {client.manifest.manifest_path}")

525

526

# Check manifest validity

527

warnings = client.manifest.check()

528

if warnings:

529

for warning in warnings:

530

print(f"Warning: {warning.msg}")

531

else:

532

print("Manifest is valid")

533

```

534

535

### HTML Tag Generation Utilities

536

537

Low-level utilities for generating HTML tags used by the asset loading system.

538

539

```python { .api }

540

class TagGenerator:

541

"""Static methods for generating HTML tags."""

542

543

@staticmethod

544

def script(src: str, attrs: Dict[str, str]) -> str:

545

"""

546

Generate HTML script tag.

547

548

Args:

549

src: Source URL for the script

550

attrs: Dictionary of HTML attributes

551

552

Returns:

553

HTML script tag string

554

"""

555

556

@staticmethod

557

def stylesheet(href: str, attrs: Optional[Dict[str, str]] = None) -> str:

558

"""

559

Generate HTML link tag for CSS stylesheets.

560

561

Args:

562

href: CSS file URL

563

attrs: Optional dictionary of HTML attributes

564

565

Returns:

566

HTML link tag string

567

"""

568

569

@staticmethod

570

def stylesheet_preload(href: str, attrs: Optional[Dict[str, str]] = None) -> str:

571

"""

572

Generate HTML link preload tag for CSS.

573

574

Args:

575

href: CSS file URL

576

attrs: Optional dictionary of HTML attributes

577

578

Returns:

579

HTML link preload tag string

580

"""

581

582

@staticmethod

583

def preload(href: str, attrs: Dict[str, str]) -> str:

584

"""

585

Generate HTML link preload tag.

586

587

Args:

588

href: Resource URL

589

attrs: Dictionary of HTML attributes

590

591

Returns:

592

HTML link tag string

593

"""

594

595

def attrs_to_str(attrs: Dict[str, str]) -> str:

596

"""

597

Convert dictionary of attributes to HTML attribute string.

598

599

Args:

600

attrs: Dictionary of attribute name-value pairs

601

602

Returns:

603

Formatted HTML attributes string

604

"""

605

```

606

607

**Tag Generation Examples:**

608

```python

609

from django_vite.core.tag_generator import TagGenerator, attrs_to_str

610

611

# Generate script tag

612

script = TagGenerator.script(

613

'https://example.com/script.js',

614

{'type': 'module', 'defer': ''}

615

)

616

# Result: '<script type="module" defer="" src="https://example.com/script.js"></script>'

617

618

# Generate stylesheet link

619

css = TagGenerator.stylesheet(

620

'https://example.com/styles.css',

621

{'media': 'print'}

622

)

623

# Result: '<link media="print" rel="stylesheet" href="https://example.com/styles.css" />'

624

625

# Generate preload link

626

preload = TagGenerator.preload(

627

'https://example.com/font.woff2',

628

{'as': 'font', 'type': 'font/woff2', 'crossorigin': ''}

629

)

630

# Result: '<link href="https://example.com/font.woff2" as="font" type="font/woff2" crossorigin="" />'

631

632

# Convert attributes dictionary to string

633

attrs_str = attrs_to_str({'data-module': 'app', 'defer': ''})

634

# Result: 'data-module="app" defer=""'

635

```

636

637

## Performance Considerations

638

639

### Singleton Benefits

640

641

The DjangoViteAssetLoader singleton pattern ensures:

642

- Manifest files are parsed once and cached in memory

643

- Configuration is loaded once at startup

644

- Multiple asset requests reuse parsed data

645

646

### Manifest Parsing

647

648

- Manifest parsing happens once when dev_mode=False

649

- Parsing errors are cached to avoid repeated file system access

650

- System checks validate manifests at startup

651

652

### Development vs Production

653

654

**Development Mode:**

655

- No manifest parsing required

656

- Direct URLs to Vite dev server

657

- Minimal overhead per request

658

659

**Production Mode:**

660

- Manifest parsed once at startup

661

- Asset dependencies resolved from cached manifest data

662

- Static file URLs generated using Django's staticfiles system