102 lines
3.2 KiB
JavaScript
102 lines
3.2 KiB
JavaScript
import { join, sep } from 'path';
|
|
import { access, writeFile, readFile } from 'fs/promises';
|
|
import { log } from '../lib/logger.js';
|
|
|
|
export default async (CDP, evaluate, { browserType, dataPath }) => {
|
|
if (browserType !== 'chromium') { // current implementation is for chromium-based only
|
|
const warning = () => log(`Warning: V8 Cache API is only for Chromium (running on ${browserType})`);
|
|
|
|
return {
|
|
build: () => {},
|
|
load: () => false,
|
|
exists: () => false
|
|
};
|
|
}
|
|
|
|
await CDP.send('Page.enable');
|
|
|
|
const getDefaultPath = () => join(dataPath, 'v8Cache.json');
|
|
const getScriptUrls = async (includePreload = true) => (await evaluate(`[...document.querySelectorAll('script[src]${includePreload ? ', link[as=script]' : ''}')].map(x => x.src ?? x.href).join(';')`)).split(';');
|
|
|
|
const build = async ({ path = getDefaultPath(), eager = true, urls = [], reload = true, includePreload = true, finishOnLoad = true } = {}) => {
|
|
const startTime = performance.now();
|
|
|
|
log('v8Cache: beginning cache build...');
|
|
urls ??= await getScriptUrls(includePreload);
|
|
|
|
log(`v8Cache: found ${urls.length} scripts`);
|
|
|
|
const cache = await new Promise(async resolve => {
|
|
let produced = [], done = false;
|
|
|
|
const unhook = CDP.on('Page.compilationCacheProduced', ({ params: { url, data }}) => {
|
|
// console.log('produced', url);
|
|
produced.push({ url, data });
|
|
|
|
process.stdout.write(`v8Cache: caching... (${produced.length}/${urls.length})\r`);
|
|
|
|
if (produced.length >= urls.length) {
|
|
done = true;
|
|
unhook();
|
|
resolve(produced);
|
|
}
|
|
});
|
|
|
|
await CDP.send('Page.produceCompilationCache', {
|
|
scripts: urls.map(url => ({ url, eager }))
|
|
});
|
|
|
|
if (reload) {
|
|
if (finishOnLoad) CDP.on('Page.frameStoppedLoading', async () => {
|
|
// console.log('loaded');
|
|
await new Promise(res => setTimeout(res, 2000));
|
|
if (done) return;
|
|
|
|
log('v8Cache: forcing caching to end early as loading is done');
|
|
|
|
unhook();
|
|
resolve(produced);
|
|
}, true);
|
|
|
|
log('v8Cache: reloading to force script loads...');
|
|
await CDP.send('Page.reload');
|
|
}
|
|
|
|
process.stdout.write(`v8Cache: starting cache...\r`);
|
|
});
|
|
|
|
log(`v8Cache: cached ${cache.length}/${urls.length} scripts in ${(performance.now() - startTime).toFixed(2)}ms`);
|
|
|
|
const raw = JSON.stringify(cache, null, 2);
|
|
await writeFile(path, raw);
|
|
|
|
log(`v8Cache: saved to .../${path.split(sep).slice(-3).join('/')} (${(Buffer.byteLength(raw, 'utf8') / 1024 / 1024).toFixed(2)}MB)`);
|
|
};
|
|
|
|
const exists = (path = getDefaultPath()) => access(path).then(() => true).catch(() => false);
|
|
|
|
const load = async (path = getDefaultPath()) => {
|
|
if (!await exists(path)) return false;
|
|
const startTime = performance.now();
|
|
|
|
const cache = JSON.parse(await readFile(path, 'utf8'));
|
|
|
|
for (const entry of cache) {
|
|
// console.log('loaded', entry);
|
|
CDP.send('Page.addCompilationCache', entry);
|
|
}
|
|
|
|
log(`v8Cache: loaded ${cache.length} scripts in ${(performance.now() - startTime).toFixed(2)}ms`);
|
|
|
|
return true;
|
|
};
|
|
|
|
// try to load default ASAP in background
|
|
load();
|
|
|
|
return {
|
|
build,
|
|
load,
|
|
exists
|
|
};
|
|
}; |