Skip to content

Instantly share code, notes, and snippets.

@websmithcode
Created August 11, 2024 00:53
Show Gist options
  • Save websmithcode/f3894590b8e6cdb28230fc30c8cdfd6b to your computer and use it in GitHub Desktop.
Save websmithcode/f3894590b8e6cdb28230fc30c8cdfd6b to your computer and use it in GitHub Desktop.
managed request caching system for playwright with typescript
import type { Page, Response } from "playwright";
import fs from 'fs';
export class PWCache {
private readonly cacheDir = './.cache';
statistics: {
totalRequests: number;
totalCached: number;
totalNotCached: number;
};
constructor(
public page: Page
) {
this.statistics = new Proxy({
totalRequests: 0,
totalCached: 0,
totalNotCached: 0,
}
, {
set: (target, key, value) => {
// @ts-ignore
target[key] = value;
console.log(`Statistics: ${JSON.stringify(target)}`);
return true;
},
});
}
async run() {
if (!fs.existsSync(this.cacheDir)) {
fs.mkdirSync(this.cacheDir);
}
await this.page.route('**/*', async route => {
this.statistics.totalRequests++;
const request = route.request();
const url = request.url();
if (PWCache._isUrlForCaching(url)) {
console.log(`Response Cache: ${url}`);
const cachedFile = `${this.cacheDir}/${encodeURIComponent(url)}`;
if (fs.existsSync(cachedFile)) {
this.statistics.totalCached++;
const body = fs.readFileSync(cachedFile);
await route.fulfill({
body: body,
headers: { 'content-type': PWCache._getContentType(url) },
});
return;
}
} else {
this.statistics.totalNotCached++;
}
route.continue();
});
this.page.on('response', async (response: Response) => {
const request = response.request();
const url = request.url();
const cachedFile = `${this.cacheDir}/${encodeURIComponent(url)}`;
console.log(`Response: ${url}`);
try {
if (PWCache._isUrlForCaching(url)) {
if (url.includes('.mp4')) {
const file = await response.finished().then(() => response.body());
fs.writeFileSync(cachedFile, file);
} else {
const file = await response.body();
fs.writeFileSync(cachedFile, file);
}
}
} catch (error) {
console.error(`Error Response with cached: ${url}`);
console.info(error);
}
});
}
static _isUrlForCaching(url: string): boolean {
const fileExtensions = [
'.css',
'.js',
'.png',
'.jpg',
'.woff',
'.woff2',
'.ogg',
'.ttf',
'.mp4'
];
switch (true) {
case fileExtensions.some(ext => url.split('?')[0].endsWith(ext)):
return true;
default:
return false;
}
}
static _getContentType(url: string): string {
const types: { [key: string]: string } = {
'.css': 'text/css',
'.js': 'application/javascript',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.ogg': 'audio/ogg',
'.ttf': 'font/ttf',
}
const ext = url.split('?')[0].split('.').pop();
if (`.${ext}` in types) {
return types[`.${ext}`];
}
return 'application/octet-stream';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment