Bengal's asset pipeline provides efficient processing and delivery of static assets (CSS, JS, images, fonts) with optimization support.
Overview
The asset pipeline (bengal/assets/pipeline.py) is a lightweight system that:
- Discovers assets from site and theme directories
- Processes assets (minification, optimization)
- Manages asset fingerprinting for cache busting
- Copies processed assets to output directory
- Integrates with incremental builds
Asset Object (bengal/core/asset/)
Purpose
Represents a static file with metadata and processing capabilities
Key Attributes
1 2 3 4 5 6 7 8 | |
Asset Types
| Type | Extensions | Processing |
|---|---|---|
| CSS | .css,.scss,.sass,.less |
Minification, source maps |
| JavaScript | .js,.mjs,.ts |
Minification, source maps |
| Images | .jpg,.png,.gif,.webp,.svg |
Optimization, format conversion |
| Fonts | .woff,.woff2,.ttf,.otf |
Copy only (already optimized) |
| Data | .json,.yaml,.xml,.csv |
Copy, optional compression |
| Other | All others | Copy only |
Key Methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
Asset Discovery (bengal/discovery/asset_discovery.py)
Purpose
Finds all static assets in site and theme directories
Discovery Process
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
Exclusions
- Hidden files (
.gitignore,.DS_Store) - Cache directories (
.cache/,__pycache__/) - Build outputs (if nested incorrectly)
- Configurable ignore patterns
Asset Pipeline (bengal/assets/pipeline.py)
Purpose
Central coordinator for asset processing
Processing Flow
Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
Asset Dependency Tracking (bengal/cache/asset_dependency_map.py)
Purpose
Tracks relationships between assets (imports, references)
Use Cases
- CSS imports:
@import "variables.css" - JS imports:
import { foo } from './module.js' - Image references in CSS:
background: url('image.png')
Implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Integration with Incremental Builds
When a CSS file changes, all CSS files that import it are also rebuilt.
Configuration
Asset pipeline is configured viabengal.toml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Minification
CSS Minification
- Removes whitespace and comments
- Shortens color codes (#ffffff → #fff)
- Combines selectors
- Removes unused rules (future)
JavaScript Minification
- Removes whitespace and comments
- Shortens variable names (optional)
- Dead code elimination (optional)
Implementation
Uses a built-in Python minifier for CSS (safe whitespace/comment removal) andrjsminfor JS (pure Python, no Node.js required).lightningcsswas removed to support Python 3.14 free-threading.
Image Optimization
Supported Operations
- Lossless compression (PNG, WebP)
- Lossy compression with quality control (JPEG)
- Metadata stripping (EXIF, IPTC)
- Format conversion (e.g., PNG → WebP)
- Resizing (future)
- Responsive image generation (future)
Implementation
UsesPillowfor image processing (widely available, pure Python + C extensions)
Cache Busting
Fingerprinting Strategy
Assets can include content hash in filename:
Original: style.css
Fingerprinted: style.abc123.css
Template Integration
Fingerprinted paths available in templates:
1 2 3 | |
Benefits
- Long cache TTL (1 year+)
- No stale cache issues
- Automatic invalidation on changes
Asset Manifest System (0.1.4+)
Bengal generates a deterministicasset-manifest.jsonfile that maps logical asset names to their fingerprinted output files. This ensures reliable asset resolution and eliminates stale fingerprinted assets.
Purpose
The asset manifest solves several problems:
- Stale Assets: Prevents old fingerprinted files (e.g.,
style.95230091.css) from persisting after updates - Dev/Prod Sync: Ensures development and production CSS stay in sync
- Reliable Resolution: Provides deterministic asset resolution without glob matching
- Cache Busting: Enables long cache TTLs with automatic invalidation
Manifest Format
The manifest is written topublic/asset-manifest.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Manifest-Driven Resolution
Theasset_url()template helper consults the manifest first:
1 2 3 4 5 6 7 8 9 10 11 | |
Stale Fingerprint Cleanup
Before writing new fingerprinted files, Bengal:
- Loads existing manifest (if present)
- Identifies stale fingerprinted files (not in new manifest)
- Removes stale files from output directory
- Writes new manifest with updated mappings
This ensures only current assets exist in the output directory.
CLI Inspection
Usebengal assets statusto inspect asset mappings:
1 2 3 4 | |
This helps debug asset issues and verify manifest correctness.
Integration with Build Process
The manifest is generated during asset processing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Clean Output Builds
Use--clean-outputflag to ensure clean builds:
bengal build --clean-output
This removes all output files (including stale fingerprinted assets) before building, ensuring deterministic builds. Perfect for CI/CD pipelines.
Benefits
- Deterministic: Same logical path always resolves to same fingerprinted file
- Reliable: No glob matching fallback needed (though still supported for backward compatibility)
- Debuggable: Manifest provides visibility into asset mappings
- Clean: Stale assets automatically removed
- Fast: O(1) lookup via dictionary
See:bengal/assets/manifest.pyfor implementation details.
Performance
Parallel Processing
Assets are processed in parallel using a unified worker pool when:
- 5+ assets to process OR mixed workload (CSS + other assets)
- Parallel mode enabled (default)
- Worker pool available
Optimization (2025-11): CSS bundling and static asset processing (images, JS) now run concurrently in the same thread pool. This eliminates the "hang" where the build would wait for CSS to finish before starting image optimization.
Measured speedup: 2-3x for 10+ assets
Incremental Builds
Only changed assets are reprocessed:
- File content hash comparison
- Dependency tracking for imports
- Cache invalidation on changes
Measured speedup: 15-30x for single asset changes
Optimization Trade-offs
Image optimization is slowest operation (~100-500ms per image). Can be disabled for dev builds:
1 2 | |
Integration Points
With Discovery
- AssetDiscovery finds assets
- AssetOrchestrator processes them
- Asset objects created and tracked
With Incremental Builds
- BuildCache tracks asset file hashes
- AssetDependencyMap tracks imports
- Only changed assets reprocessed
With Templates
asset_url()function resolves asset paths- Fingerprinted paths handled automatically
- Theme asset resolution
With Themes
- Theme assets discovered automatically
- Theme assets override site assets
- Fallback chain: site → theme → default
Health Validation
AssetValidator checks:
- All referenced assets exist
- Minification completed (if enabled)
- Optimization completed (if enabled)
- File sizes reasonable
- No broken asset references
1 2 3 | |
Future Enhancements
- Responsive Images: Generate multiple sizes automatically
- Modern Format Support: AVIF, WebP with fallbacks
- CSS Purging: Remove unused CSS automatically
- Sprite Generation: Combine small images into sprites
- CDN Integration: Upload assets to CDN automatically
- Source Maps: Generate source maps for minified files
- Preprocessor Support: Built-in SCSS/Less compilation
Testing
Asset pipeline testing:
- Unit tests:
tests/unit/test_asset.py - Integration tests:
tests/integration/test_asset_pipeline.py - Performance tests:
tests/performance/test_asset_processing.py
Coverage: ~75% for asset processing