import { readFile, writeFile } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import path from 'node:path'; import { randomUUID } from "node:crypto"; /** * @typedef {{ * assetCachePrefix?: string, * assetCacheVersionID?: string, * path: string, * }} ServiceWorkerConfig * @typedef {import('astro').AstroIntegration} AstroIntegration */ /** * Accepts configuration options with service worker path * and injects needed variables such as `assets` generated by Astro * @param {ServiceWorkerConfig} config * @returns {AstroIntegration} */ export default function serviceWorker(config) { let { assetCachePrefix, assetCacheVersionID = randomUUID(), path: serviceWorkerPath } = config; /** * @type {Array} */ let assets = []; return { 'name': 'astro-sw', 'hooks': { 'astro:build:ssr': ({ manifest }) => { assets = manifest.assets.filter(ass => !ass.includes('sw.js')) }, 'astro:build:done': async ({ dir }) => { const outFile = fileURLToPath(new URL('./sw.js', dir)); let originalScript; try { const __dirname = path.resolve(path.dirname('.')); const swPath = path.join(__dirname, serviceWorkerPath ?? ''); console.log('[astro-sw] Using service worker:', swPath); originalScript = await readFile(swPath); } catch { throw Error('[astro-sw] ERROR: service worker script not found!') } const assetsDeclaration = `const __assets = ${JSON.stringify(assets)};\n`; const versionDeclaration = `const __version = ${JSON.stringify(assetCacheVersionID)};\n`; const prefixDeclaration = `const __prefix = ${JSON.stringify(assetCachePrefix)};\n`; await writeFile( outFile, assetsDeclaration + versionDeclaration + prefixDeclaration + originalScript ); } } } };