CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-webassets

Media asset management for Python, with glue code for various web frameworks

Overview
Eval results
Files

framework-integration.mddocs/

Framework Integration

Extensions and adapters for integrating WebAssets with popular Python web frameworks, enabling seamless asset management within existing applications.

Capabilities

Jinja2 Integration

Native integration with Jinja2 templating engine for asset management in templates.

class AssetsExtension:
    def __init__(self, environment):
        """
        Jinja2 template extension for assets.
        
        Parameters:
        - environment: Jinja2 Environment instance
        """
    
    def parse(self, parser):
        """Parse {% assets %} template tags."""
    
    def call_method(self, method, kwargs):
        """Handle method calls from templates."""

class Jinja2Loader:
    def __init__(self, environment):
        """
        Load bundles from Jinja2 templates.
        
        Parameters:
        - environment: Jinja2 Environment instance
        """
    
    def load_bundles(self):
        """Load bundles defined in templates."""

def assets(*args, **kwargs):
    """
    Template function for asset handling.
    
    Parameters:  
    - *args: Asset arguments
    - **kwargs: Asset options
    
    Returns:
    Asset URLs for template rendering
    """

Jinja2 Template Usage

{# Load assets extension #}
{% extends "base.html" %}

{# Define and use assets in templates #}
{% assets "css_all" %}
    <link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}" />
{% endassets %}

{% assets "js_all" %}
    <script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}

{# Inline asset definition #}
{% assets filters="jsmin", output="gen/inline.js" %}
    <script type="text/javascript" src="{{ ASSET_URL }}"></script>
{% endassets %}

{# Multiple files #}
{% assets "js/app.js", "js/utils.js", filters="uglifyjs", output="gen/combined.js" %}
    <script src="{{ ASSET_URL }}"></script>
{% endassets %}

Framework Integration Examples

Flask Integration

from flask import Flask
from webassets import Environment, Bundle
from webassets.ext.jinja2 import AssetsExtension

app = Flask(__name__)

# Configure assets
assets = Environment(app)
assets.url = app.static_url_path
assets.directory = app.static_folder

# Add Jinja2 extension
assets.init_app(app)
app.jinja_env.add_extension(AssetsExtension)
app.jinja_env.assets_environment = assets

# Define bundles
js_bundle = Bundle(
    'js/jquery.js',
    'js/app.js',
    filters='jsmin',
    output='gen/packed.js'
)

css_bundle = Bundle(
    'css/common.css',
    'css/forms.css',
    filters='cssmin',
    output='gen/packed.css'
)

assets.register('js_all', js_bundle)
assets.register('css_all', css_bundle)

@app.route('/')
def index():
    return render_template('index.html')

Flask template usage:

<!DOCTYPE html>
<html>
<head>
    {% assets "css_all" %}
        <link rel="stylesheet" href="{{ ASSET_URL }}" />
    {% endassets %}
</head>
<body>
    <h1>My Flask App</h1>
    
    {% assets "js_all" %}
        <script src="{{ ASSET_URL }}"></script>
    {% endassets %}
</body>
</html>

Django Integration

# settings.py
import os
from webassets import Environment, Bundle

# WebAssets configuration
ASSETS_ROOT = os.path.join(BASE_DIR, 'static')
ASSETS_URL = '/static/'

# Create assets environment
assets_env = Environment(ASSETS_ROOT, ASSETS_URL)

# Configure for production
if not DEBUG:
    assets_env.cache = True
    assets_env.versions = 'hash'
    assets_env.manifest = 'json:manifest.json'

# Define bundles
js_bundle = Bundle(
    'js/app.js',
    'js/utils.js',
    filters='jsmin',
    output='gen/app.js'
)

css_bundle = Bundle(
    'scss/main.scss',
    filters=['libsass', 'cssmin'],
    output='gen/app.css'
)

assets_env.register('js_app', js_bundle)
assets_env.register('css_app', css_bundle)

# Template context processor
def assets_context(request):
    return {'assets_env': assets_env}

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'myapp.context_processors.assets_context',
            ],
        },
    },
]

Django template usage:

<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
    {% for url in assets_env.css_app.urls %}
        <link rel="stylesheet" href="{{ url }}">
    {% endfor %}
</head>
<body>
    {% block content %}{% endblock %}
    
    {% for url in assets_env.js_app.urls %}
        <script src="{{ url }}"></script>
    {% endfor %}
</body>
</html>

Bottle Integration

from bottle import Bottle, static_file, jinja2_template
from webassets import Environment, Bundle
from webassets.ext.jinja2 import AssetsExtension
import jinja2

app = Bottle()

# Setup Jinja2 with assets
jinja_env = jinja2.Environment(
    loader=jinja2.FileSystemLoader('templates')
)
jinja_env.add_extension(AssetsExtension)

# Configure assets
assets = Environment('./static', '/static')
jinja_env.assets_environment = assets

# Define bundles
js_bundle = Bundle(
    'js/app.js',
    'js/lib.js',
    filters='jsmin',
    output='gen/app.js'
)

assets.register('js_all', js_bundle)

@app.route('/')
def index():
    template = jinja_env.get_template('index.html')
    return template.render()

@app.route('/static/<filename:path>')
def static(filename):
    return static_file(filename, root='./static')

if __name__ == '__main__':
    app.run(host='localhost', port=8080, debug=True)

FastAPI Integration

from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from webassets import Environment, Bundle
from webassets.ext.jinja2 import AssetsExtension

app = FastAPI()

# Mount static files
app.mount("/static", StaticFiles(directory="static"), name="static")

# Setup templates with assets
templates = Jinja2Templates(directory="templates")
templates.env.add_extension(AssetsExtension)

# Configure assets
assets = Environment('./static', '/static')
templates.env.assets_environment = assets

# Define bundles
css_bundle = Bundle(
    'css/bootstrap.css',
    'css/app.css',
    filters='cssmin',
    output='gen/app.css'
)

js_bundle = Bundle(
    'js/vue.js',
    'js/app.js',
    filters='jsmin',
    output='gen/app.js'
)

assets.register('css_all', css_bundle)
assets.register('js_all', js_bundle)

@app.get("/")
async def read_root(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

Pyramid Integration

from pyramid.config import Configurator
from pyramid.response import Response
from webassets import Environment, Bundle

def assets_tween_factory(handler, registry):
    """Tween to add assets to request."""
    def assets_tween(request):
        # Add assets to request
        request.assets = registry.settings['assets_env']
        return handler(request)
    return assets_tween

def main(global_config, **settings):
    config = Configurator(settings=settings)
    
    # Configure assets
    assets = Environment('./static', '/static')
    
    # Define bundles
    js_bundle = Bundle(
        'js/app.js',
        filters='jsmin',
        output='gen/app.js'
    )
    
    assets.register('js_all', js_bundle)
    
    # Store in settings
    config.registry.settings['assets_env'] = assets
    
    # Add assets tween
    config.add_tween('myapp.assets_tween_factory')
    
    # Add routes
    config.add_route('home', '/')
    config.add_view(home_view, route_name='home', renderer='templates/home.pt')
    
    # Add static view
    config.add_static_view('static', './static')
    
    return config.make_wsgi_app()

def home_view(request):
    return {'assets': request.assets}

Advanced Framework Integration

Custom Environment Adapter

from webassets import Environment

class FlaskAssetsEnvironment(Environment):
    """Flask-specific assets environment."""
    
    def __init__(self, app=None):
        self.app = app
        super().__init__()
        
        if app:
            self.init_app(app)
    
    def init_app(self, app):
        """Initialize with Flask app."""
        self.app = app
        
        # Configure from Flask settings
        self.directory = app.static_folder or './static'
        self.url = app.static_url_path or '/static'
        self.debug = app.debug
        
        # Use Flask's instance folder for cache
        if hasattr(app, 'instance_path'):
            self.cache = f"filesystem:{app.instance_path}/.webassets-cache"
        
        # Add to app extensions
        if not hasattr(app, 'extensions'):
            app.extensions = {}
        app.extensions['webassets'] = self
        
        # Add template globals
        app.jinja_env.globals['assets'] = self
        
        # Add CLI commands
        self._add_cli_commands(app)
    
    def _add_cli_commands(self, app):
        """Add Flask CLI commands."""
        @app.cli.command()
        def build_assets():
            """Build all asset bundles."""
            from webassets.script import CommandLineEnvironment
            cmdline = CommandLineEnvironment(self)
            cmdline.build()
            print("Assets built successfully!")
        
        @app.cli.command()
        def clean_assets():
            """Clean built assets."""
            from webassets.script import CommandLineEnvironment
            cmdline = CommandLineEnvironment(self)
            cmdline.clean()
            print("Assets cleaned successfully!")

# Usage
from flask import Flask

app = Flask(__name__)
assets = FlaskAssetsEnvironment(app)

# Define bundles
assets.register('js_all', 
    'js/app.js', 
    'js/utils.js',
    filters='jsmin',
    output='gen/app.js'
)

Middleware Integration

class WebAssetsMiddleware:
    """WSGI middleware for WebAssets."""
    
    def __init__(self, app, assets_env):
        self.app = app
        self.assets_env = assets_env
    
    def __call__(self, environ, start_response):
        # Add assets to environ
        environ['webassets.env'] = self.assets_env
        
        # Auto-build in debug mode
        if self.assets_env.debug:
            self._auto_build()
        
        return self.app(environ, start_response)
    
    def _auto_build(self):
        """Auto-build assets in debug mode."""
        from webassets.script import CommandLineEnvironment
        cmdline = CommandLineEnvironment(self.assets_env)
        
        try:
            cmdline.build()
        except Exception as e:
            print(f"Asset build failed: {e}")

# Usage with any WSGI app
from webassets import Environment, Bundle

assets = Environment('./static', '/static', debug=True)
assets.register('js_all', 'app.js', filters='jsmin', output='gen/app.js')

# Wrap WSGI app
app = WebAssetsMiddleware(wsgi_app, assets)

Template Helper Functions

def create_asset_helpers(assets_env):
    """Create template helper functions."""
    
    def asset_url(bundle_name):
        """Get single asset URL."""
        bundle = assets_env[bundle_name]
        urls = bundle.urls()
        return urls[0] if urls else ''
    
    def asset_urls(bundle_name):
        """Get all asset URLs."""
        bundle = assets_env[bundle_name]
        return bundle.urls()
    
    def inline_asset(bundle_name):
        """Get asset content for inlining."""
        bundle = assets_env[bundle_name]
        bundle.build()
        
        output_path = bundle.resolve_output()
        full_path = os.path.join(assets_env.directory, output_path)
        
        try:
            with open(full_path, 'r') as f:
                return f.read()
        except IOError:
            return ''
    
    def asset_tag(bundle_name, tag_type='auto'):
        """Generate HTML tag for asset."""
        urls = asset_urls(bundle_name)
        tags = []
        
        for url in urls:
            if tag_type == 'auto':
                if url.endswith('.css'):
                    tags.append(f'<link rel="stylesheet" href="{url}">')
                elif url.endswith('.js'):
                    tags.append(f'<script src="{url}"></script>')
            elif tag_type == 'css':
                tags.append(f'<link rel="stylesheet" href="{url}">')
            elif tag_type == 'js':
                tags.append(f'<script src="{url}"></script>')
        
        return '\n'.join(tags)
    
    return {
        'asset_url': asset_url,
        'asset_urls': asset_urls,
        'inline_asset': inline_asset,
        'asset_tag': asset_tag
    }

# Flask usage
app.jinja_env.globals.update(create_asset_helpers(assets))

# Template usage
# {{ asset_tag('css_all') }}
# {{ asset_tag('js_all') }}
# <style>{{ inline_asset('critical_css') }}</style>

Configuration Management

class FrameworkConfig:
    """Framework-specific configuration management."""
    
    def __init__(self, framework='flask'):
        self.framework = framework
        self.bundles = {}
        self.settings = {}
    
    def configure_for_framework(self, app):
        """Configure assets for specific framework."""
        
        if self.framework == 'flask':
            return self._configure_flask(app)
        elif self.framework == 'django':
            return self._configure_django(app)
        elif self.framework == 'fastapi':
            return self._configure_fastapi(app)
    
    def _configure_flask(self, app):
        from webassets import Environment
        
        assets = Environment(
            directory=app.static_folder,
            url=app.static_url_path,
            debug=app.debug
        )
        
        # Framework-specific settings
        if not app.debug:
            assets.cache = f"filesystem:{app.instance_path}/.webassets-cache"
            assets.versions = 'hash'
        
        return assets
    
    def _configure_django(self, settings):
        from webassets import Environment
        
        assets = Environment(
            directory=settings.STATIC_ROOT,
            url=settings.STATIC_URL,
            debug=settings.DEBUG
        )
        
        if not settings.DEBUG:
            assets.cache = 'filesystem'
            assets.versions = 'hash'
            assets.manifest = 'json:manifest.json'
        
        return assets
    
    def _configure_fastapi(self, app):
        from webassets import Environment
        
        assets = Environment(
            directory='./static',
            url='/static',
            debug=True  # Determine from app config
        )
        
        return assets

# Usage
config = FrameworkConfig('flask')
assets = config.configure_for_framework(app)

Install with Tessl CLI

npx tessl i tessl/pypi-webassets

docs

bundle-management.md

caching-versioning.md

command-line.md

configuration-loading.md

environment-configuration.md

filter-system.md

framework-integration.md

index.md

merge-system.md

updater-system.md

utilities.md

tile.json