or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-controller.mdindex.mdplugins-cleanup.mdroute-strategy.mdsimple-setup.mdutilities.md

plugins-cleanup.mddocs/

0

# Plugins and Cleanup

1

2

Plugin system for extending functionality and cleanup utilities for cache maintenance. These tools help customize precaching behavior and maintain cache hygiene.

3

4

## Capabilities

5

6

### Plugin Management

7

8

Function for adding plugins to the default precaching strategy.

9

10

```typescript { .api }

11

/**

12

* Adds plugins to the precaching strategy.

13

* Plugins added via this method will be used by all precaching operations using the default controller.

14

* @param plugins - Array of Workbox plugins to add to the precaching strategy

15

*/

16

function addPlugins(plugins: WorkboxPlugin[]): void;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import { addPlugins, precacheAndRoute } from "workbox-precaching";

23

24

// Add custom plugins before setting up precaching

25

addPlugins([

26

{

27

cacheKeyWillBeUsed: async ({ request, mode }) => {

28

// Add custom cache key logic

29

const url = new URL(request.url);

30

url.searchParams.set('sw-version', '1.0');

31

return url.href;

32

},

33

34

cacheWillUpdate: async ({ request, response }) => {

35

// Only cache successful responses

36

return response.status === 200 ? response : null;

37

},

38

39

cacheDidUpdate: async ({ cacheName, request, oldResponse, newResponse }) => {

40

// Log cache updates

41

console.log(`Cache updated: ${request.url}`);

42

43

// Notify clients about updates

44

const clients = await self.clients.matchAll();

45

clients.forEach(client => {

46

client.postMessage({

47

type: 'CACHE_UPDATED',

48

url: request.url

49

});

50

});

51

}

52

}

53

]);

54

55

// Now set up precaching with plugins applied

56

precacheAndRoute([

57

{ url: "/index.html", revision: "v1.0" },

58

{ url: "/app.js", revision: "v2.1" }

59

]);

60

```

61

62

### Cache Cleanup

63

64

Function for cleaning up outdated caches from previous Workbox versions.

65

66

```typescript { .api }

67

/**

68

* Adds an activate event listener which cleans up incompatible precaches

69

* created by older versions of Workbox.

70

* This is important when updating Workbox versions to prevent cache bloat.

71

*/

72

function cleanupOutdatedCaches(): void;

73

```

74

75

**Usage Examples:**

76

77

```typescript

78

import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching";

79

80

// Clean up old caches when service worker activates

81

cleanupOutdatedCaches();

82

83

// Set up current precaching

84

precacheAndRoute([

85

{ url: "/index.html", revision: "v2.0" },

86

{ url: "/styles.css", revision: "v2.1" }

87

]);

88

89

// The cleanup will automatically run during service worker activation

90

// and remove caches from older Workbox versions

91

```

92

93

### Fallback Plugin

94

95

Plugin class that provides offline fallback responses from the precache.

96

97

```typescript { .api }

98

/**

99

* Plugin that provides offline fallback responses from precache.

100

* Implements WorkboxPlugin interface.

101

*/

102

class PrecacheFallbackPlugin implements WorkboxPlugin {

103

/**

104

* Create a new PrecacheFallbackPlugin instance

105

* @param options - Configuration options

106

*/

107

constructor(options: {

108

/** Precached URL to use as fallback */

109

fallbackURL: string;

110

/** PrecacheController instance (defaults to singleton) */

111

precacheController?: PrecacheController;

112

});

113

114

/**

115

* Plugin callback that returns precached fallback response when handler fails

116

* @returns Promise resolving to fallback response or undefined

117

*/

118

handlerDidError(): Promise<Response | undefined>;

119

}

120

```

121

122

**Usage Examples:**

123

124

```typescript

125

import {

126

PrecacheFallbackPlugin,

127

precacheAndRoute

128

} from "workbox-precaching";

129

import { registerRoute } from "workbox-routing";

130

import { NetworkFirst } from "workbox-strategies";

131

132

// Precache fallback pages

133

precacheAndRoute([

134

{ url: "/offline.html", revision: "v1.0" },

135

{ url: "/error.html", revision: "v1.0" }

136

]);

137

138

// Create fallback plugins

139

const offlineFallback = new PrecacheFallbackPlugin({

140

fallbackURL: "/offline.html"

141

});

142

143

const errorFallback = new PrecacheFallbackPlugin({

144

fallbackURL: "/error.html"

145

});

146

147

// Use with strategies

148

const networkFirstStrategy = new NetworkFirst({

149

cacheName: "pages",

150

plugins: [offlineFallback]

151

});

152

153

// Register routes with fallback

154

registerRoute(

155

({ request }) => request.mode === 'navigate',

156

networkFirstStrategy

157

);

158

159

// Use different fallbacks for different content types

160

registerRoute(

161

({ request }) => request.destination === 'document',

162

new NetworkFirst({

163

cacheName: "documents",

164

plugins: [errorFallback]

165

})

166

);

167

```

168

169

## Advanced Plugin Patterns

170

171

### Comprehensive Logging Plugin

172

173

```typescript

174

import { addPlugins } from "workbox-precaching";

175

176

const loggingPlugin = {

177

cacheKeyWillBeUsed: async ({ request, mode, params }) => {

178

const cacheKey = params?.cacheKey || request.url;

179

console.log(`Cache key for ${request.url}: ${cacheKey}`);

180

return cacheKey;

181

},

182

183

cacheWillUpdate: async ({ request, response, event }) => {

184

console.log(`Caching ${request.url}:`, {

185

status: response.status,

186

statusText: response.statusText,

187

headers: Object.fromEntries(response.headers.entries())

188

});

189

return response;

190

},

191

192

cacheDidUpdate: async ({ cacheName, request, oldResponse, newResponse, event }) => {

193

console.log(`Cache updated in ${cacheName}:`, {

194

url: request.url,

195

oldStatus: oldResponse?.status,

196

newStatus: newResponse?.status

197

});

198

},

199

200

cachedResponseWillBeUsed: async ({ cacheName, request, cachedResponse, event }) => {

201

console.log(`Serving from cache ${cacheName}: ${request.url}`);

202

return cachedResponse;

203

}

204

};

205

206

addPlugins([loggingPlugin]);

207

```

208

209

### Security Plugin

210

211

```typescript

212

import { addPlugins } from "workbox-precaching";

213

214

const securityPlugin = {

215

cacheWillUpdate: async ({ request, response }) => {

216

// Only cache HTTPS responses

217

if (!request.url.startsWith('https://')) {

218

console.warn(`Refusing to cache non-HTTPS resource: ${request.url}`);

219

return null;

220

}

221

222

// Check response headers for security

223

const contentType = response.headers.get('content-type');

224

if (contentType && contentType.includes('application/javascript')) {

225

const csp = response.headers.get('content-security-policy');

226

if (!csp) {

227

console.warn(`JavaScript resource without CSP: ${request.url}`);

228

}

229

}

230

231

return response;

232

},

233

234

cachedResponseWillBeUsed: async ({ cachedResponse, request }) => {

235

// Add security headers to cached responses

236

if (cachedResponse) {

237

const secureResponse = new Response(cachedResponse.body, {

238

status: cachedResponse.status,

239

statusText: cachedResponse.statusText,

240

headers: {

241

...cachedResponse.headers,

242

'X-Content-Type-Options': 'nosniff',

243

'X-Frame-Options': 'DENY',

244

'X-Served-From': 'sw-cache'

245

}

246

});

247

return secureResponse;

248

}

249

return cachedResponse;

250

}

251

};

252

253

addPlugins([securityPlugin]);

254

```

255

256

### Performance Monitoring Plugin

257

258

```typescript

259

import { addPlugins } from "workbox-precaching";

260

261

const performancePlugin = {

262

requestWillFetch: async ({ request, event }) => {

263

// Mark start time

264

(request as any).__startTime = performance.now();

265

return request;

266

},

267

268

fetchDidSucceed: async ({ request, response }) => {

269

const startTime = (request as any).__startTime;

270

if (startTime) {

271

const duration = performance.now() - startTime;

272

console.log(`Network fetch for ${request.url}: ${duration.toFixed(2)}ms`);

273

274

// Report to analytics

275

if ('gtag' in self) {

276

(self as any).gtag('event', 'sw_fetch_duration', {

277

url: request.url,

278

duration: Math.round(duration)

279

});

280

}

281

}

282

return response;

283

},

284

285

cacheDidUpdate: async ({ request, cacheName }) => {

286

// Track cache updates

287

console.log(`Cache update: ${request.url} in ${cacheName}`);

288

289

if ('gtag' in self) {

290

(self as any).gtag('event', 'sw_cache_update', {

291

url: request.url,

292

cache_name: cacheName

293

});

294

}

295

}

296

};

297

298

addPlugins([performancePlugin]);

299

```

300

301

## Complete Setup Examples

302

303

### Production Setup with All Features

304

305

```typescript

306

import {

307

precacheAndRoute,

308

cleanupOutdatedCaches,

309

addPlugins,

310

PrecacheFallbackPlugin

311

} from "workbox-precaching";

312

import { registerRoute } from "workbox-routing";

313

import { NetworkFirst, StaleWhileRevalidate } from "workbox-strategies";

314

315

// 1. Clean up old caches

316

cleanupOutdatedCaches();

317

318

// 2. Add global plugins

319

addPlugins([

320

// Production logging

321

{

322

cacheDidUpdate: async ({ request, cacheName }) => {

323

console.log(`Updated ${request.url} in ${cacheName}`);

324

325

// Notify app about updates

326

const clients = await self.clients.matchAll();

327

clients.forEach(client => {

328

client.postMessage({

329

type: 'SW_CACHE_UPDATED',

330

url: request.url

331

});

332

});

333

}

334

},

335

336

// Error handling

337

{

338

fetchDidFail: async ({ originalRequest, error }) => {

339

console.error(`Fetch failed for ${originalRequest.url}:`, error);

340

}

341

}

342

]);

343

344

// 3. Set up precaching with fallbacks

345

precacheAndRoute([

346

{ url: "/", revision: "v1.0.0" },

347

{ url: "/offline.html", revision: "v1.0.0" },

348

{ url: "/error.html", revision: "v1.0.0" },

349

...self.__WB_MANIFEST // Generated manifest

350

]);

351

352

// 4. Create fallback plugins

353

const navigationFallback = new PrecacheFallbackPlugin({

354

fallbackURL: "/offline.html"

355

});

356

357

const documentFallback = new PrecacheFallbackPlugin({

358

fallbackURL: "/error.html"

359

});

360

361

// 5. Set up runtime caching with fallbacks

362

registerRoute(

363

({ request }) => request.mode === 'navigate',

364

new NetworkFirst({

365

cacheName: "pages",

366

plugins: [navigationFallback]

367

})

368

);

369

370

registerRoute(

371

({ request }) => request.destination === 'document',

372

new StaleWhileRevalidate({

373

cacheName: "documents",

374

plugins: [documentFallback]

375

})

376

);

377

```

378

379

### Development Setup with Debug Features

380

381

```typescript

382

import {

383

precacheAndRoute,

384

addPlugins,

385

cleanupOutdatedCaches

386

} from "workbox-precaching";

387

388

// Enable detailed logging for development

389

const debugPlugin = {

390

cacheKeyWillBeUsed: async ({ request, mode }) => {

391

console.log(`[DEBUG] Cache key for ${request.url} (${mode})`);

392

return request.url;

393

},

394

395

cacheWillUpdate: async ({ request, response }) => {

396

console.log(`[DEBUG] Caching ${request.url}:`, {

397

status: response.status,

398

headers: Array.from(response.headers.entries())

399

});

400

return response;

401

},

402

403

cachedResponseWillBeUsed: async ({ request, cachedResponse }) => {

404

console.log(`[DEBUG] Serving cached ${request.url}`);

405

return cachedResponse;

406

}

407

};

408

409

// Add debug plugin

410

addPlugins([debugPlugin]);

411

412

// Clean up during development

413

cleanupOutdatedCaches();

414

415

// Precache development assets

416

precacheAndRoute([

417

{ url: "/", revision: Date.now().toString() }, // Always update in dev

418

{ url: "/dev-tools.html", revision: "dev" }

419

]);

420

```