UNPKG

@twocaretcat/astro-snapshot

Version:

An Astro integration for generating screenshots of your pages automatically at build time. Perfect for creating social images, content previews, dynamic icons, and more!

147 lines (146 loc) 6.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = snapshot; /** * Astro integration for generating automated page snapshots using Puppeteer. * * This module provides an integration that runs after the build process, * starts a local preview server, and captures screenshots for configured * routes using a headless browser. * * @module */ const node_util_1 = require("node:util"); const astro_1 = require("astro"); const puppeteer_1 = require("puppeteer"); const node_url_1 = require("node:url"); const promises_1 = require("node:fs/promises"); const node_path_1 = require("node:path"); const utils_js_1 = require("./utils.js"); /** * Creates an Astro integration that captures screenshots of specified pages * during the `astro:build:done` lifecycle event. * * @param config - Integration configuration, including page mappings, defaults, * and Puppeteer settings. * @returns The configured Astro integration. */ function snapshot(config) { // Resolved config options const pages = config.pages; const defaults = { ...config.defaults, }; const launchOptions = { headless: true, ...config.launchOptions, }; const port = config.port ?? 4322; let astroConfig; let rootDir; /** * Merges per-page configuration with defaults and resolves * the final screenshot configuration. * * @param pageConfig - Configuration for a specific page. * @returns Fully resolved configuration for Puppeteer. */ const resolveScreenshotConfig = (pageConfig) => { const outputPath = pageConfig.outputPath; return { // Or operator is used to ignore 0 width: pageConfig.width || defaults.width || 1200, height: pageConfig.height || defaults.height || 630, overwrite: pageConfig.overwrite ?? defaults.overwrite ?? false, goToOptions: { waitUntil: 'networkidle2', ...defaults.gotoOptions, ...pageConfig.gotoOptions, }, outputPath, screenshotOptions: { path: outputPath, type: (0, utils_js_1.getFormat)(outputPath), fullPage: false, ...defaults.screenshotOptions, ...pageConfig.screenshotOptions, }, setViewportOptions: { ...defaults.setViewportOptions, ...pageConfig.setViewportOptions, }, }; }; /** * Handles the `astro:config:done` lifecycle event. * Stores the Astro configuration and root directory for later use. * * @param param0 - Object containing the resolved Astro config. */ const handleConfigDone = ({ config }) => { astroConfig = config; rootDir = (0, node_url_1.fileURLToPath)(astroConfig.root); }; /** * Handles the `astro:build:done` lifecycle event. * Launches a local preview server and uses Puppeteer to generate * screenshots for all configured pages. * * @param param0 - Object containing the Astro logger instance. */ const handleBuildDone = async ({ logger }) => { const startTime = performance.now(); logger.info('🔭 Integration loaded.'); const pageEntries = Object.entries(pages); if (pageEntries.length === 0) { logger.warn('No pages configured for screenshot generation. Skipping...'); return; } // Start local server to render pages const previewServer = await (0, astro_1.preview)({ root: rootDir, server: { port }, }); // Launch Puppeteer const browser = await (0, puppeteer_1.launch)(launchOptions); logger.info('🔭 Generating screenshots...'); logger.label = ''; try { for (const [pagePath, screenshotConfigs] of pageEntries) { const normalizedPagePath = pagePath.startsWith('/') ? pagePath : `/${pagePath}`; const pageUrl = `http://localhost:${port}${normalizedPagePath}`; for (const screenshotConfig of screenshotConfigs) { const { width, height, overwrite, goToOptions, outputPath, screenshotOptions, setViewportOptions } = resolveScreenshotConfig(screenshotConfig); const absoluteOutputPath = (0, node_path_1.resolve)(rootDir, outputPath); const relativePath = (0, node_path_1.relative)(rootDir, absoluteOutputPath); const doesFileExist = await (0, utils_js_1.fileExists)(absoluteOutputPath); if (doesFileExist && !overwrite) { (0, utils_js_1.logStatus)(logger, normalizedPagePath, relativePath, 'skipped'); continue; } // Ensure output directory exists await (0, promises_1.mkdir)((0, node_path_1.dirname)(absoluteOutputPath), { recursive: true }); // Create page and take screenshot const page = await browser.newPage(); await page.setViewport({ width, height, ...setViewportOptions }); await page.goto(pageUrl, goToOptions); await page.screenshot(screenshotOptions); await page.close(); (0, utils_js_1.logStatus)(logger, normalizedPagePath, relativePath, doesFileExist && overwrite ? 'overwritten' : undefined); } } } finally { await browser.close(); await previewServer.stop(); } logger.info((0, node_util_1.styleText)('green', `✓ Completed in ${(0, utils_js_1.formatDuration)(performance.now() - startTime)}.`)); }; return { name: 'astro-snapshot', hooks: { 'astro:config:done': handleConfigDone, 'astro:build:done': handleBuildDone, }, }; }