or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bundle-management.mdcaching-versioning.mdcommand-line.mdconfiguration-loading.mdenvironment-configuration.mdfilter-system.mdframework-integration.mdindex.mdmerge-system.mdupdater-system.mdutilities.md

framework-integration.mddocs/

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

```