0
# Framework Integration
1
2
Extensions and adapters for integrating WebAssets with popular Python web frameworks, enabling seamless asset management within existing applications.
3
4
## Capabilities
5
6
### Jinja2 Integration
7
8
Native integration with Jinja2 templating engine for asset management in templates.
9
10
```python { .api }
11
class AssetsExtension:
12
def __init__(self, environment):
13
"""
14
Jinja2 template extension for assets.
15
16
Parameters:
17
- environment: Jinja2 Environment instance
18
"""
19
20
def parse(self, parser):
21
"""Parse {% assets %} template tags."""
22
23
def call_method(self, method, kwargs):
24
"""Handle method calls from templates."""
25
26
class Jinja2Loader:
27
def __init__(self, environment):
28
"""
29
Load bundles from Jinja2 templates.
30
31
Parameters:
32
- environment: Jinja2 Environment instance
33
"""
34
35
def load_bundles(self):
36
"""Load bundles defined in templates."""
37
38
def assets(*args, **kwargs):
39
"""
40
Template function for asset handling.
41
42
Parameters:
43
- *args: Asset arguments
44
- **kwargs: Asset options
45
46
Returns:
47
Asset URLs for template rendering
48
"""
49
```
50
51
### Jinja2 Template Usage
52
53
```jinja2
54
{# Load assets extension #}
55
{% extends "base.html" %}
56
57
{# Define and use assets in templates #}
58
{% assets "css_all" %}
59
<link rel="stylesheet" type="text/css" href="{{ ASSET_URL }}" />
60
{% endassets %}
61
62
{% assets "js_all" %}
63
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
64
{% endassets %}
65
66
{# Inline asset definition #}
67
{% assets filters="jsmin", output="gen/inline.js" %}
68
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
69
{% endassets %}
70
71
{# Multiple files #}
72
{% assets "js/app.js", "js/utils.js", filters="uglifyjs", output="gen/combined.js" %}
73
<script src="{{ ASSET_URL }}"></script>
74
{% endassets %}
75
```
76
77
## Framework Integration Examples
78
79
### Flask Integration
80
81
```python
82
from flask import Flask
83
from webassets import Environment, Bundle
84
from webassets.ext.jinja2 import AssetsExtension
85
86
app = Flask(__name__)
87
88
# Configure assets
89
assets = Environment(app)
90
assets.url = app.static_url_path
91
assets.directory = app.static_folder
92
93
# Add Jinja2 extension
94
assets.init_app(app)
95
app.jinja_env.add_extension(AssetsExtension)
96
app.jinja_env.assets_environment = assets
97
98
# Define bundles
99
js_bundle = Bundle(
100
'js/jquery.js',
101
'js/app.js',
102
filters='jsmin',
103
output='gen/packed.js'
104
)
105
106
css_bundle = Bundle(
107
'css/common.css',
108
'css/forms.css',
109
filters='cssmin',
110
output='gen/packed.css'
111
)
112
113
assets.register('js_all', js_bundle)
114
assets.register('css_all', css_bundle)
115
116
@app.route('/')
117
def index():
118
return render_template('index.html')
119
```
120
121
Flask template usage:
122
```jinja2
123
<!DOCTYPE html>
124
<html>
125
<head>
126
{% assets "css_all" %}
127
<link rel="stylesheet" href="{{ ASSET_URL }}" />
128
{% endassets %}
129
</head>
130
<body>
131
<h1>My Flask App</h1>
132
133
{% assets "js_all" %}
134
<script src="{{ ASSET_URL }}"></script>
135
{% endassets %}
136
</body>
137
</html>
138
```
139
140
### Django Integration
141
142
```python
143
# settings.py
144
import os
145
from webassets import Environment, Bundle
146
147
# WebAssets configuration
148
ASSETS_ROOT = os.path.join(BASE_DIR, 'static')
149
ASSETS_URL = '/static/'
150
151
# Create assets environment
152
assets_env = Environment(ASSETS_ROOT, ASSETS_URL)
153
154
# Configure for production
155
if not DEBUG:
156
assets_env.cache = True
157
assets_env.versions = 'hash'
158
assets_env.manifest = 'json:manifest.json'
159
160
# Define bundles
161
js_bundle = Bundle(
162
'js/app.js',
163
'js/utils.js',
164
filters='jsmin',
165
output='gen/app.js'
166
)
167
168
css_bundle = Bundle(
169
'scss/main.scss',
170
filters=['libsass', 'cssmin'],
171
output='gen/app.css'
172
)
173
174
assets_env.register('js_app', js_bundle)
175
assets_env.register('css_app', css_bundle)
176
177
# Template context processor
178
def assets_context(request):
179
return {'assets_env': assets_env}
180
181
TEMPLATES = [
182
{
183
'BACKEND': 'django.template.backends.django.DjangoTemplates',
184
'DIRS': [os.path.join(BASE_DIR, 'templates')],
185
'APP_DIRS': True,
186
'OPTIONS': {
187
'context_processors': [
188
'django.template.context_processors.debug',
189
'django.template.context_processors.request',
190
'django.contrib.auth.context_processors.auth',
191
'django.contrib.messages.context_processors.messages',
192
'myapp.context_processors.assets_context',
193
],
194
},
195
},
196
]
197
```
198
199
Django template usage:
200
```django
201
<!-- base.html -->
202
<!DOCTYPE html>
203
<html>
204
<head>
205
{% for url in assets_env.css_app.urls %}
206
<link rel="stylesheet" href="{{ url }}">
207
{% endfor %}
208
</head>
209
<body>
210
{% block content %}{% endblock %}
211
212
{% for url in assets_env.js_app.urls %}
213
<script src="{{ url }}"></script>
214
{% endfor %}
215
</body>
216
</html>
217
```
218
219
### Bottle Integration
220
221
```python
222
from bottle import Bottle, static_file, jinja2_template
223
from webassets import Environment, Bundle
224
from webassets.ext.jinja2 import AssetsExtension
225
import jinja2
226
227
app = Bottle()
228
229
# Setup Jinja2 with assets
230
jinja_env = jinja2.Environment(
231
loader=jinja2.FileSystemLoader('templates')
232
)
233
jinja_env.add_extension(AssetsExtension)
234
235
# Configure assets
236
assets = Environment('./static', '/static')
237
jinja_env.assets_environment = assets
238
239
# Define bundles
240
js_bundle = Bundle(
241
'js/app.js',
242
'js/lib.js',
243
filters='jsmin',
244
output='gen/app.js'
245
)
246
247
assets.register('js_all', js_bundle)
248
249
@app.route('/')
250
def index():
251
template = jinja_env.get_template('index.html')
252
return template.render()
253
254
@app.route('/static/<filename:path>')
255
def static(filename):
256
return static_file(filename, root='./static')
257
258
if __name__ == '__main__':
259
app.run(host='localhost', port=8080, debug=True)
260
```
261
262
### FastAPI Integration
263
264
```python
265
from fastapi import FastAPI, Request
266
from fastapi.templating import Jinja2Templates
267
from fastapi.staticfiles import StaticFiles
268
from webassets import Environment, Bundle
269
from webassets.ext.jinja2 import AssetsExtension
270
271
app = FastAPI()
272
273
# Mount static files
274
app.mount("/static", StaticFiles(directory="static"), name="static")
275
276
# Setup templates with assets
277
templates = Jinja2Templates(directory="templates")
278
templates.env.add_extension(AssetsExtension)
279
280
# Configure assets
281
assets = Environment('./static', '/static')
282
templates.env.assets_environment = assets
283
284
# Define bundles
285
css_bundle = Bundle(
286
'css/bootstrap.css',
287
'css/app.css',
288
filters='cssmin',
289
output='gen/app.css'
290
)
291
292
js_bundle = Bundle(
293
'js/vue.js',
294
'js/app.js',
295
filters='jsmin',
296
output='gen/app.js'
297
)
298
299
assets.register('css_all', css_bundle)
300
assets.register('js_all', js_bundle)
301
302
@app.get("/")
303
async def read_root(request: Request):
304
return templates.TemplateResponse("index.html", {"request": request})
305
```
306
307
### Pyramid Integration
308
309
```python
310
from pyramid.config import Configurator
311
from pyramid.response import Response
312
from webassets import Environment, Bundle
313
314
def assets_tween_factory(handler, registry):
315
"""Tween to add assets to request."""
316
def assets_tween(request):
317
# Add assets to request
318
request.assets = registry.settings['assets_env']
319
return handler(request)
320
return assets_tween
321
322
def main(global_config, **settings):
323
config = Configurator(settings=settings)
324
325
# Configure assets
326
assets = Environment('./static', '/static')
327
328
# Define bundles
329
js_bundle = Bundle(
330
'js/app.js',
331
filters='jsmin',
332
output='gen/app.js'
333
)
334
335
assets.register('js_all', js_bundle)
336
337
# Store in settings
338
config.registry.settings['assets_env'] = assets
339
340
# Add assets tween
341
config.add_tween('myapp.assets_tween_factory')
342
343
# Add routes
344
config.add_route('home', '/')
345
config.add_view(home_view, route_name='home', renderer='templates/home.pt')
346
347
# Add static view
348
config.add_static_view('static', './static')
349
350
return config.make_wsgi_app()
351
352
def home_view(request):
353
return {'assets': request.assets}
354
```
355
356
## Advanced Framework Integration
357
358
### Custom Environment Adapter
359
360
```python
361
from webassets import Environment
362
363
class FlaskAssetsEnvironment(Environment):
364
"""Flask-specific assets environment."""
365
366
def __init__(self, app=None):
367
self.app = app
368
super().__init__()
369
370
if app:
371
self.init_app(app)
372
373
def init_app(self, app):
374
"""Initialize with Flask app."""
375
self.app = app
376
377
# Configure from Flask settings
378
self.directory = app.static_folder or './static'
379
self.url = app.static_url_path or '/static'
380
self.debug = app.debug
381
382
# Use Flask's instance folder for cache
383
if hasattr(app, 'instance_path'):
384
self.cache = f"filesystem:{app.instance_path}/.webassets-cache"
385
386
# Add to app extensions
387
if not hasattr(app, 'extensions'):
388
app.extensions = {}
389
app.extensions['webassets'] = self
390
391
# Add template globals
392
app.jinja_env.globals['assets'] = self
393
394
# Add CLI commands
395
self._add_cli_commands(app)
396
397
def _add_cli_commands(self, app):
398
"""Add Flask CLI commands."""
399
@app.cli.command()
400
def build_assets():
401
"""Build all asset bundles."""
402
from webassets.script import CommandLineEnvironment
403
cmdline = CommandLineEnvironment(self)
404
cmdline.build()
405
print("Assets built successfully!")
406
407
@app.cli.command()
408
def clean_assets():
409
"""Clean built assets."""
410
from webassets.script import CommandLineEnvironment
411
cmdline = CommandLineEnvironment(self)
412
cmdline.clean()
413
print("Assets cleaned successfully!")
414
415
# Usage
416
from flask import Flask
417
418
app = Flask(__name__)
419
assets = FlaskAssetsEnvironment(app)
420
421
# Define bundles
422
assets.register('js_all',
423
'js/app.js',
424
'js/utils.js',
425
filters='jsmin',
426
output='gen/app.js'
427
)
428
```
429
430
### Middleware Integration
431
432
```python
433
class WebAssetsMiddleware:
434
"""WSGI middleware for WebAssets."""
435
436
def __init__(self, app, assets_env):
437
self.app = app
438
self.assets_env = assets_env
439
440
def __call__(self, environ, start_response):
441
# Add assets to environ
442
environ['webassets.env'] = self.assets_env
443
444
# Auto-build in debug mode
445
if self.assets_env.debug:
446
self._auto_build()
447
448
return self.app(environ, start_response)
449
450
def _auto_build(self):
451
"""Auto-build assets in debug mode."""
452
from webassets.script import CommandLineEnvironment
453
cmdline = CommandLineEnvironment(self.assets_env)
454
455
try:
456
cmdline.build()
457
except Exception as e:
458
print(f"Asset build failed: {e}")
459
460
# Usage with any WSGI app
461
from webassets import Environment, Bundle
462
463
assets = Environment('./static', '/static', debug=True)
464
assets.register('js_all', 'app.js', filters='jsmin', output='gen/app.js')
465
466
# Wrap WSGI app
467
app = WebAssetsMiddleware(wsgi_app, assets)
468
```
469
470
### Template Helper Functions
471
472
```python
473
def create_asset_helpers(assets_env):
474
"""Create template helper functions."""
475
476
def asset_url(bundle_name):
477
"""Get single asset URL."""
478
bundle = assets_env[bundle_name]
479
urls = bundle.urls()
480
return urls[0] if urls else ''
481
482
def asset_urls(bundle_name):
483
"""Get all asset URLs."""
484
bundle = assets_env[bundle_name]
485
return bundle.urls()
486
487
def inline_asset(bundle_name):
488
"""Get asset content for inlining."""
489
bundle = assets_env[bundle_name]
490
bundle.build()
491
492
output_path = bundle.resolve_output()
493
full_path = os.path.join(assets_env.directory, output_path)
494
495
try:
496
with open(full_path, 'r') as f:
497
return f.read()
498
except IOError:
499
return ''
500
501
def asset_tag(bundle_name, tag_type='auto'):
502
"""Generate HTML tag for asset."""
503
urls = asset_urls(bundle_name)
504
tags = []
505
506
for url in urls:
507
if tag_type == 'auto':
508
if url.endswith('.css'):
509
tags.append(f'<link rel="stylesheet" href="{url}">')
510
elif url.endswith('.js'):
511
tags.append(f'<script src="{url}"></script>')
512
elif tag_type == 'css':
513
tags.append(f'<link rel="stylesheet" href="{url}">')
514
elif tag_type == 'js':
515
tags.append(f'<script src="{url}"></script>')
516
517
return '\n'.join(tags)
518
519
return {
520
'asset_url': asset_url,
521
'asset_urls': asset_urls,
522
'inline_asset': inline_asset,
523
'asset_tag': asset_tag
524
}
525
526
# Flask usage
527
app.jinja_env.globals.update(create_asset_helpers(assets))
528
529
# Template usage
530
# {{ asset_tag('css_all') }}
531
# {{ asset_tag('js_all') }}
532
# <style>{{ inline_asset('critical_css') }}</style>
533
```
534
535
### Configuration Management
536
537
```python
538
class FrameworkConfig:
539
"""Framework-specific configuration management."""
540
541
def __init__(self, framework='flask'):
542
self.framework = framework
543
self.bundles = {}
544
self.settings = {}
545
546
def configure_for_framework(self, app):
547
"""Configure assets for specific framework."""
548
549
if self.framework == 'flask':
550
return self._configure_flask(app)
551
elif self.framework == 'django':
552
return self._configure_django(app)
553
elif self.framework == 'fastapi':
554
return self._configure_fastapi(app)
555
556
def _configure_flask(self, app):
557
from webassets import Environment
558
559
assets = Environment(
560
directory=app.static_folder,
561
url=app.static_url_path,
562
debug=app.debug
563
)
564
565
# Framework-specific settings
566
if not app.debug:
567
assets.cache = f"filesystem:{app.instance_path}/.webassets-cache"
568
assets.versions = 'hash'
569
570
return assets
571
572
def _configure_django(self, settings):
573
from webassets import Environment
574
575
assets = Environment(
576
directory=settings.STATIC_ROOT,
577
url=settings.STATIC_URL,
578
debug=settings.DEBUG
579
)
580
581
if not settings.DEBUG:
582
assets.cache = 'filesystem'
583
assets.versions = 'hash'
584
assets.manifest = 'json:manifest.json'
585
586
return assets
587
588
def _configure_fastapi(self, app):
589
from webassets import Environment
590
591
assets = Environment(
592
directory='./static',
593
url='/static',
594
debug=True # Determine from app config
595
)
596
597
return assets
598
599
# Usage
600
config = FrameworkConfig('flask')
601
assets = config.configure_for_framework(app)
602
```