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

caching-versioning.mddocs/

0

# Caching and Versioning

1

2

Advanced caching and versioning system for optimizing build performance and managing asset updates, including cache invalidation, version generation, and manifest management.

3

4

## Capabilities

5

6

### Cache Implementation

7

8

Cache systems for storing processed assets and improving build performance.

9

10

```python { .api }

11

class FilesystemCache:

12

def __init__(self, directory):

13

"""

14

File-based cache implementation.

15

16

Parameters:

17

- directory: Cache directory path

18

"""

19

20

def get(self, key):

21

"""Get cached value by key."""

22

23

def set(self, key, value):

24

"""Set cached value."""

25

26

def has(self, key):

27

"""Check if key exists in cache."""

28

29

def delete(self, key):

30

"""Delete cached value."""

31

32

def clear(self):

33

"""Clear all cached values."""

34

35

class MemoryCache:

36

def __init__(self, max_size=1000):

37

"""

38

In-memory cache implementation.

39

40

Parameters:

41

- max_size: Maximum number of cached items

42

"""

43

44

def get(self, key):

45

"""Get cached value by key."""

46

47

def set(self, key, value):

48

"""Set cached value."""

49

50

def has(self, key):

51

"""Check if key exists in cache."""

52

53

def delete(self, key):

54

"""Delete cached value."""

55

56

def clear(self):

57

"""Clear all cached values."""

58

59

def get_cache(cache_option, env=None):

60

"""

61

Create cache instance from configuration.

62

63

Parameters:

64

- cache_option: Cache configuration (str/bool/Cache instance)

65

- env: Environment for context

66

67

Returns:

68

Cache instance or None

69

"""

70

```

71

72

Example usage:

73

```python

74

from webassets.cache import FilesystemCache, MemoryCache, get_cache

75

76

# Filesystem cache

77

fs_cache = FilesystemCache('./.webassets-cache')

78

fs_cache.set('bundle_123', compiled_content)

79

cached = fs_cache.get('bundle_123')

80

81

# Memory cache

82

mem_cache = MemoryCache(max_size=500)

83

mem_cache.set('filter_abc', processed_data)

84

85

# Get cache from configuration

86

cache = get_cache('filesystem') # Uses default directory

87

cache = get_cache(True) # Uses default cache

88

cache = get_cache(False) # No caching

89

cache = get_cache('memory') # Memory cache

90

```

91

92

### Version Generation

93

94

Version calculation strategies for cache busting and asset update detection.

95

96

```python { .api }

97

class Version:

98

def determine_version(self, bundle, ctx, hunk=None):

99

"""

100

Calculate version string for bundle.

101

102

Parameters:

103

- bundle: Bundle instance

104

- ctx: Version context

105

- hunk: Optional content hunk

106

107

Returns:

108

Version string

109

"""

110

111

class TimestampVersion(Version):

112

def determine_version(self, bundle, ctx, hunk=None):

113

"""Generate version based on file timestamps."""

114

115

class HashVersion(Version):

116

def determine_version(self, bundle, ctx, hunk=None):

117

"""Generate version based on content hash."""

118

119

def get_versioner(versioner_option):

120

"""

121

Create versioner from configuration.

122

123

Parameters:

124

- versioner_option: Versioner specification

125

126

Returns:

127

Version instance

128

"""

129

```

130

131

Example usage:

132

```python

133

from webassets.version import HashVersion, TimestampVersion, get_versioner

134

135

# Hash-based versioning

136

hash_versioner = HashVersion()

137

version = hash_versioner.determine_version(bundle, ctx)

138

139

# Timestamp-based versioning

140

timestamp_versioner = TimestampVersion()

141

version = timestamp_versioner.determine_version(bundle, ctx)

142

143

# Get versioner from config

144

versioner = get_versioner('hash') # Hash versioning

145

versioner = get_versioner('timestamp') # Timestamp versioning

146

versioner = get_versioner(False) # No versioning

147

```

148

149

### Manifest Management

150

151

Manifest systems for tracking generated assets and their versions.

152

153

```python { .api }

154

class Manifest:

155

def remember(self, bundle, ctx, version, output_files):

156

"""

157

Store bundle information in manifest.

158

159

Parameters:

160

- bundle: Bundle instance

161

- ctx: Context

162

- version: Version string

163

- output_files: Generated output file paths

164

"""

165

166

def query(self, bundle, ctx):

167

"""

168

Query manifest for bundle information.

169

170

Parameters:

171

- bundle: Bundle instance

172

- ctx: Context

173

174

Returns:

175

Stored manifest information or None

176

"""

177

178

class FileManifest(Manifest):

179

def __init__(self, filename, format='json'):

180

"""

181

File-based manifest storage.

182

183

Parameters:

184

- filename: Manifest file path

185

- format: Storage format ('json', 'yaml')

186

"""

187

188

def get_manifest(manifest_option, env=None):

189

"""

190

Create manifest from configuration.

191

192

Parameters:

193

- manifest_option: Manifest specification

194

- env: Environment for context

195

196

Returns:

197

Manifest instance or None

198

"""

199

```

200

201

Example usage:

202

```python

203

from webassets.version import FileManifest, get_manifest

204

205

# JSON manifest

206

manifest = FileManifest('manifest.json', format='json')

207

manifest.remember(bundle, ctx, version, ['gen/app-abc123.js'])

208

info = manifest.query(bundle, ctx)

209

210

# Get manifest from config

211

manifest = get_manifest('json:assets.json') # JSON file

212

manifest = get_manifest('yaml:assets.yaml') # YAML file

213

manifest = get_manifest(False) # No manifest

214

```

215

216

### Version Exceptions

217

218

Exception handling for version-related errors.

219

220

```python { .api }

221

class VersionIndeterminableError(Exception):

222

"""Raised when version cannot be determined."""

223

```

224

225

## Advanced Caching and Versioning Examples

226

227

### Environment Configuration

228

229

```python

230

from webassets import Environment

231

232

# Basic caching configuration

233

env = Environment(

234

'./static',

235

'/static',

236

cache=True, # Use default filesystem cache

237

versions='hash' # Hash-based versioning

238

)

239

240

# Advanced caching configuration

241

env = Environment(

242

'./static',

243

'/static',

244

cache='filesystem:./.cache', # Custom cache directory

245

versions='timestamp', # Timestamp versioning

246

manifest='json:manifest.json' # JSON manifest file

247

)

248

249

# Production configuration

250

prod_env = Environment(

251

'./static',

252

'/static',

253

debug=False,

254

cache='filesystem',

255

versions='hash',

256

manifest='json:public/assets.json',

257

auto_build=False

258

)

259

260

# Development configuration

261

dev_env = Environment(

262

'./static',

263

'/static',

264

debug=True,

265

cache=False, # No caching in development

266

versions=False, # No versioning in development

267

auto_build=True

268

)

269

```

270

271

### Custom Cache Implementation

272

273

```python

274

from webassets.cache import Cache

275

import redis

276

277

class RedisCache(Cache):

278

"""Redis-based cache implementation."""

279

280

def __init__(self, host='localhost', port=6379, db=0, prefix='webassets:'):

281

self.redis = redis.Redis(host=host, port=port, db=db)

282

self.prefix = prefix

283

284

def _key(self, key):

285

return f"{self.prefix}{key}"

286

287

def get(self, key):

288

value = self.redis.get(self._key(key))

289

return value.decode('utf-8') if value else None

290

291

def set(self, key, value):

292

self.redis.set(self._key(key), value.encode('utf-8'))

293

294

def has(self, key):

295

return self.redis.exists(self._key(key))

296

297

def delete(self, key):

298

self.redis.delete(self._key(key))

299

300

def clear(self):

301

keys = self.redis.keys(f"{self.prefix}*")

302

if keys:

303

self.redis.delete(*keys)

304

305

# Usage

306

redis_cache = RedisCache(host='localhost', port=6379)

307

env = Environment('./static', '/static', cache=redis_cache)

308

```

309

310

### Custom Version Strategy

311

312

```python

313

from webassets.version import Version

314

import hashlib

315

import os

316

317

class GitHashVersion(Version):

318

"""Version based on git commit hash."""

319

320

def determine_version(self, bundle, ctx, hunk=None):

321

import subprocess

322

323

try:

324

# Get current git commit hash

325

result = subprocess.run(

326

['git', 'rev-parse', '--short', 'HEAD'],

327

capture_output=True,

328

text=True,

329

cwd=ctx.env.directory

330

)

331

332

if result.returncode == 0:

333

git_hash = result.stdout.strip()

334

335

# Combine with bundle content hash for uniqueness

336

if hunk:

337

content_hash = hashlib.md5(hunk.data().encode()).hexdigest()[:8]

338

return f"{git_hash}-{content_hash}"

339

else:

340

return git_hash

341

342

except Exception:

343

pass

344

345

# Fallback to timestamp

346

from webassets.version import TimestampVersion

347

return TimestampVersion().determine_version(bundle, ctx, hunk)

348

349

# Usage

350

env = Environment('./static', '/static', versions=GitHashVersion())

351

```

352

353

### Advanced Manifest Configuration

354

355

```python

356

from webassets.version import FileManifest

357

import json

358

import os

359

360

class CustomManifest(FileManifest):

361

"""Enhanced manifest with additional metadata."""

362

363

def remember(self, bundle, ctx, version, output_files):

364

# Call parent implementation

365

super().remember(bundle, ctx, version, output_files)

366

367

# Add custom metadata

368

manifest_data = self._load_manifest()

369

370

bundle_key = bundle.resolve_output(ctx)

371

if bundle_key in manifest_data:

372

manifest_data[bundle_key].update({

373

'build_time': datetime.utcnow().isoformat(),

374

'bundle_id': bundle.id,

375

'input_files': list(bundle.resolve_contents(ctx)),

376

'filters': [f.id() for f in bundle.filters],

377

'file_sizes': {

378

f: os.path.getsize(os.path.join(ctx.env.directory, f))

379

for f in output_files

380

}

381

})

382

383

self._save_manifest(manifest_data)

384

385

def _load_manifest(self):

386

try:

387

with open(self.filename, 'r') as f:

388

return json.load(f)

389

except (FileNotFoundError, json.JSONDecodeError):

390

return {}

391

392

def _save_manifest(self, data):

393

with open(self.filename, 'w') as f:

394

json.dump(data, f, indent=2, sort_keys=True)

395

396

# Usage

397

custom_manifest = CustomManifest('detailed-manifest.json')

398

env = Environment('./static', '/static', manifest=custom_manifest)

399

```

400

401

### Cache Optimization Strategies

402

403

```python

404

from webassets import Environment, Bundle

405

from webassets.cache import FilesystemCache

406

407

# Hierarchical caching

408

class HierarchicalCache:

409

"""Multi-level cache with memory and filesystem tiers."""

410

411

def __init__(self, memory_size=100, fs_directory='.cache'):

412

from webassets.cache import MemoryCache, FilesystemCache

413

self.memory = MemoryCache(max_size=memory_size)

414

self.filesystem = FilesystemCache(fs_directory)

415

416

def get(self, key):

417

# Try memory first

418

value = self.memory.get(key)

419

if value is not None:

420

return value

421

422

# Fall back to filesystem

423

value = self.filesystem.get(key)

424

if value is not None:

425

# Promote to memory

426

self.memory.set(key, value)

427

428

return value

429

430

def set(self, key, value):

431

# Store in both tiers

432

self.memory.set(key, value)

433

self.filesystem.set(key, value)

434

435

def has(self, key):

436

return self.memory.has(key) or self.filesystem.has(key)

437

438

def delete(self, key):

439

self.memory.delete(key)

440

self.filesystem.delete(key)

441

442

def clear(self):

443

self.memory.clear()

444

self.filesystem.clear()

445

446

# Usage

447

hierarchical_cache = HierarchicalCache(memory_size=200)

448

env = Environment('./static', '/static', cache=hierarchical_cache)

449

```

450

451

### Conditional Versioning

452

453

```python

454

def setup_assets_environment(mode='development'):

455

"""Setup environment with mode-specific caching and versioning."""

456

457

if mode == 'development':

458

return Environment(

459

'./src/assets',

460

'/assets',

461

debug=True,

462

cache=False, # No caching in dev

463

versions=False, # No versioning in dev

464

auto_build=True

465

)

466

467

elif mode == 'staging':

468

return Environment(

469

'./build/assets',

470

'/assets',

471

debug=False,

472

cache='memory', # Fast memory cache

473

versions='timestamp', # Simple versioning

474

auto_build=False

475

)

476

477

elif mode == 'production':

478

return Environment(

479

'./dist/assets',

480

'/assets',

481

debug=False,

482

cache='filesystem:.cache', # Persistent cache

483

versions='hash', # Content-based versioning

484

manifest='json:public/assets.json',

485

auto_build=False

486

)

487

488

# Usage based on environment

489

import os

490

mode = os.environ.get('NODE_ENV', 'development')

491

env = setup_assets_environment(mode)

492

```

493

494

### Bundle-Specific Versioning

495

496

```python

497

from webassets import Bundle

498

499

# Vendor bundle with stable versioning

500

vendor_bundle = Bundle(

501

'vendor/jquery.js',

502

'vendor/bootstrap.js',

503

filters='jsmin',

504

output='gen/vendor-stable.js',

505

version='vendor-v1.0' # Fixed version for stable vendor code

506

)

507

508

# App bundle with dynamic versioning

509

app_bundle = Bundle(

510

'src/app.js',

511

'src/utils.js',

512

filters=['babel', 'uglifyjs'],

513

output='gen/app-%(version)s.js' # Dynamic version placeholder

514

)

515

516

# CSS with hash versioning

517

css_bundle = Bundle(

518

'scss/main.scss',

519

filters=['libsass', 'autoprefixer', 'cssmin'],

520

output='gen/app-%(version)s.css'

521

)

522

523

env.register('vendor_js', vendor_bundle)

524

env.register('app_js', app_bundle)

525

env.register('app_css', css_bundle)

526

```