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!

660 lines (513 loc) โ€ข 18.3 kB
<!-- Project Header --> <div align="center"> <img class="projectLogo" src="docs/icon.svg" alt="Project logo" title="Project logo" width="256"> <h1 class="projectName">Astro Snapshot</h1> <p class="projectBadges"> <img src="https://johng.io/badges/category/Plugin.svg" alt="Project category" title="Project category"> <img src="https://img.shields.io/github/languages/top/twocaretcat/astro-snapshot.svg" alt="Language" title="Language"> <img src="https://img.shields.io/github/repo-size/twocaretcat/astro-snapshot.svg" alt="Repository size" title="Repository size"> <a href="LICENSE"><img src="https://img.shields.io/github/license/twocaretcat/astro-snapshot.svg" alt="Project license" title="Project license"/></a> <a href="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/semantic--release-conventionalcommits-e10079?logo=semantic-release" alt="Semantic Release" title="Semantic Release"/></a> </p> <p class="projectBadges status"> <a href="https://github.com/twocaretcat/astro-snapshot/releases/latest"><img src="https://img.shields.io/github/v/release/twocaretcat/astro-snapshot.svg" alt="Latest release" title="Latest release"/></a> <a href="https://jsr.io/@twocaretcat/astro-snapshot"><img src="https://jsr.io/badges/@twocaretcat/astro-snapshot" alt="View package on JSR" title="View package on JSR" /></a> <a href="https://jsr.io/@twocaretcat/astro-snapshot"><img src="https://jsr.io/badges/@twocaretcat/astro-snapshot/score" alt="View package on JSR" title="View package on JSR" /></a> <a href="https://www.npmjs.com/package/@twocaretcat/astro-snapshot"><img src="https://img.shields.io/npm/v/@twocaretcat/astro-snapshot" alt="View package on npmjs" title="View package on npmjs"/></a> </p> <p class="projectDesc"> An Astro integration for generating screenshots of your pages automatically at build time </p> <br/> </div> ## ๐Ÿ‘‹ About Generate screenshots of your [Astro] pages automatically at build time with **Astro Snapshot**. Perfect for creating social images, content previews, dynamic icons, and more!. This integration was inspired by a similar plugin I wrote for [Gatsby] called [Gatsby Plugin: Component to Image] and [astro-selfie]. Compared to astro-selfie, this integration exposes a lot more configuration options that allow you to completely customize how images are generated. ### Features - **๐Ÿš€ Works with any page** : Generate one or more images from any valid Astro page - Not limited by presets or available integration options like other solutions - Not limited by types of JSX elements or CSS properties supported by [Satori] - Use whatever front-end framework you want - **๐Ÿ“ท Configurable output filetypes**: Generate PNG, JPEG, or WebP images with arbitrary dimensions - Formats are automatically detected from the file extension - Pass though options to [Puppeteer] for precise control of image quality, encoding speed, and more - **๐Ÿ“‚ Customizable output paths**: Full control over paths of the generated images - Save images to the `public` directory to include them in the build, unprocessed - Save images to the `dist` directory if you don't want to include theme in source control - Save them in the `src` dir for further compression or importing into components* - Or save them somewhere else, your choice - **๐ŸŽ›๏ธ Default options**: Reuse the same options for multiple images - Provide defaults for all options and override them on a per-image basis - ๐Ÿ”ง **TypeScript support**: Full type safety for all options and functions - No need to worry about typos or incorrect config values ### Use cases - **๐Ÿž๏ธ Social images**: Use your existing front-end components to generate [Open Graph] images and/or Twitter cards for your blog posts or other content - **๐Ÿ“ฐ Content previews**: Generate screenshots of your website for use in documentation, marketing materials - **๐Ÿ–ผ๏ธ Favicons**: Dynamically generate favicons for your website ### How it works > [!IMPORTANT] > Note that, because this plugin runs _**after**_ the build completes, you will not be able to import the generated > images into your components or perform any further operations with them in the same build cycle. > > You can, however, use them in the next build, provided they are not overwritten. If you do this, make sure to account > for the images not existing the first time you perform a build (i.e. use a placeholder image or catch errors from > `import` statements). After the Astro build completes, this plugin uses [Puppeteer] to render the pages in a headless browser and save screenshots of the rendered content as images ## ๐Ÿ“ฆ Installation > [!TIP] > If you see any warnings like `Cannot find package 'puppeteer'` after adding the integration, your package manager may > not have installed peer dependencies for you. If this happens, install Puppeteer manually like so: > > ```bash > npm install puppeteer > ``` This package is available on both [JSR](https://jsr.io/@twocaretcat/astro-snapshot) and [npm](https://www.npmjs.com/package/@twocaretcat/astro-snapshot). It's also support the `astro add` command to update your `astro.config.js` automatically. ### Automatic (w/ `astro add`) > [!NOTE] > This grabs the package from npm. If you want to use the JSR version, you will need to install it manually. We can use the Astro CLI to install the integration automatically using your preferred package manager: <details> <summary>๐Ÿฆ• Deno</summary> ```bash deno run -A astro add astro-snapshot ``` </details> <details> <summary>๐Ÿฅ– Bun</summary> ```bash bunx astro add astro-snapshot ``` </details> <details> <summary>๐ŸŸข npm</summary> ```bash npx astro add astro-snapshot ``` </details> <details> <summary>๐ŸŸง pnpm</summary> ```bash pnpm astro add astro-snapshot ``` </details> <details> <summary>๐Ÿงถ yarn</summary> ```bash yarn astro add astro-snapshot ``` </details> <details> <summary>๐Ÿ–‡ vlt</summary> ```bash vlt astro add astro-snapshot ``` </details> If you run into any issues, try the manual installation steps below. ### Manual > [!TIP] > JSR has some advantages if you're using TypeScript or Deno: > > - It ships typed, modern ESM code by default > - No need for separate type declarations > - Faster, leaner installs without extraneous files > > You can use JSR with your favorite package manager. First, install it using your preferred package manager: <details> <summary>๐Ÿฆ• Deno</summary> ```bash deno add jsr:@twocaretcat/astro-snapshot # JSR (recommended) ``` ```bash deno add npm:@twocaretcat/astro-snapshot # npm ``` </details> <details> <summary>๐Ÿฅ– Bun</summary> ```bash bunx jsr add @twocaretcat/astro-snapshot # JSR ``` ```bash bun add @twocaretcat/astro-snapshot # npm ``` </details> <details> <summary>๐ŸŸข npm</summary> ```bash npx jsr add @twocaretcat/astro-snapshot # JSR ``` ```bash npm install @twocaretcat/astro-snapshot # npm ``` </details> <details> <summary>๐ŸŸง pnpm</summary> ```bash pnpm i jsr:@twocaretcat/astro-snapshot # JSR ``` ```bash pnpm add @twocaretcat/astro-snapshot # npm ``` </details> <details> <summary>๐Ÿงถ yarn</summary> ```bash yarn add jsr:@twocaretcat/astro-snapshot # JSR ``` ```bash yarn add @twocaretcat/astro-snapshot # npm ``` </details> <details> <summary>๐Ÿ–‡ vlt</summary> ```bash vlt install jsr:@twocaretcat/astro-snapshot # JSR ``` ```bash vlt install @twocaretcat/astro-snapshot # npm ``` </details> Then, apply the integration to your `astro.config.*` file using the integrations property: ```diff // astro.config.mjs import { defineConfig } from 'astro/config'; +import snapshot from 'astro-snapshot'; export default defineConfig({ // ... - integrations: [], + integrations: [snapshot()], }); ``` ## ๐Ÿ•น๏ธ Usage ### Configure the Integration Add the integration to your `astro.config.mjs` or `astro.config.ts` file and configure it like so: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import snapshot from 'astro-snapshot'; export default defineConfig({ integrations: [ snapshot({ pages: { // Single screenshot for homepage '/': [ { outputPath: 'public/og/home.png', }, ], // Multiple screenshots for about page (different sizes) '/about': [ { outputPath: 'public/og/about-og.png', width: 1200, height: 630, }, { outputPath: 'public/og/about-square.jpg', width: 1080, height: 1080, }, { outputPath: 'public/og/about-twitter.png', width: 1200, height: 675, }, ], }, }), ], }); ``` ## ๐Ÿค– Advanced Usage ### Kitchen Sink Here's an example with all available configuration options: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import snapshot from 'astro-snapshot'; export default defineConfig({ integrations: [ snapshot({ // Pages to screenshot (required) pages: { '/': [ { outputPath: 'public/og/home.png', width: 1200, // Viewport width (default: 1200) height: 630, // Viewport height (default: 630) overwrite: true, // Overwrite existing screenshots (default: false) // Puppeteer page.goto() options gotoOptions: { waitUntil: 'networkidle0', timeout: 30000, }, // Puppeteer page.screenshot() options screenshotOptions: { quality: 95, // For jpeg only fullPage: false, clip: { // Capture specific region x: 0, y: 0, width: 1200, height: 630, }, }, // Puppeteer page.setViewport() options setViewportOptions: { deviceScaleFactor: 2, // Higher resolution screenshots isMobile: false, hasTouch: false, isLandscape: true, }, }, ], }, // Default config for all screenshots (optional) defaults: { width: 1200, height: 630, overwrite: true, gotoOptions: { waitUntil: 'networkidle2', }, setViewportOptions: { deviceScaleFactor: 2, }, }, // Port for preview server (default: 4322) port: 4322, // Puppeteer launch options launchOptions: { headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }, }), ], }); ``` ### Multiple Formats for Social Media > [!TIP] > If you need to reference output paths in your pages, define the config in a common place and import it into your pages > as needed. The integration doesn't provide any methods for getting the output paths, so you'll need to manage that > yourself. Generate optimized images for different platforms: ```js // astro.config.mjs const socialMediaSizes = { og: { width: 1200, height: 630 }, // OpenGraph twitter: { width: 1200, height: 600 }, // Twitter linkedin: { width: 1200, height: 627 }, // LinkedIn instagram: { width: 1080, height: 1080 }, // Instagram }; export default defineConfig({ integrations: [ snapshot({ pages: { '/': Object.entries(socialMediaSizes).map(([platform, dims]) => ({ outputPath: `public/social/${platform}.png`, ...dims, })), }, }), ], }); ``` ### Dynamic Blog Post Screenshots Generate screenshots for all blog posts: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import snapshot from 'astro-snapshot'; // Get all blog post slugs (implement based on your setup) const blogPosts = await getBlogPostSlugs(); // Create config for each blog post const blogPages = Object.fromEntries( blogPosts.map((slug) => [ `/blog/${slug}`, [ { outputPath: `public/og/blog/${slug}.png`, width: 1200, height: 630, }, { outputPath: `public/og/blog/${slug}-square.jpg`, width: 1080, height: 1080, }, ], ]), ); export default defineConfig({ integrations: [ snapshot({ pages: { '/': [{ outputPath: 'public/og/home.png' }], '/about': [{ outputPath: 'public/og/about.png' }], ...blogPages, }, }), ], }); ``` ### Conditional Screenshot Generation > [!TIP] > Optimize build performance by conditionally generating screenshots based on environment variables or build mode. Control when screenshots are generated: ```js // astro.config.mjs const isDevelopment = process.env.NODE_ENV === 'development'; const shouldGenerateScreenshots = process.env.GENERATE_SCREENSHOTS === 'true'; export default defineConfig({ integrations: [ // Only add integration when needed ...(shouldGenerateScreenshots || !isDevelopment ? [ snapshot({ pages: { '/': [{ outputPath: 'public/og/home.png' }], }, }), ] : []), ], }); ``` ### Custom Viewport Configurations Different viewports for different purposes: ```js // astro.config.mjs const viewports = { desktop: { width: 1920, height: 1080 }, tablet: { width: 768, height: 1024 }, mobile: { width: 375, height: 667 }, }; export default defineConfig({ integrations: [ snapshot({ pages: { '/': Object.entries(viewports).map(([device, dims]) => ({ outputPath: `public/previews/${device}.png`, ...dims, })), }, }), ], }); ``` ### Waiting for Dynamic Content Handle pages with animations or lazy-loaded content: ```js // astro.config.mjs export default defineConfig({ integrations: [ snapshot({ pages: { '/dashboard': [ { outputPath: 'public/og/dashboard.png', gotoOptions: { waitUntil: 'networkidle0', // Wait for all network requests timeout: 60000, // Increase timeout }, }, ], }, }), ], }); ``` ## ๐Ÿ“š API Reference ### `SnapshotIntegrationConfig` | Property | Type | Required | Default | Description | | --------------- | ------------------------------------ | -------- | -------------------- | --------------------------------------- | | `pages` | `Record<string, ScreenshotConfig[]>` | โœ… | - | Map of page paths to screenshot configs | | `defaults` | `Partial<ScreenshotConfig>` | โŒ | `{}` | Default config for all screenshots | | `launchOptions` | `PuppeteerLaunchOptions` | โŒ | `{ headless: true }` | Puppeteer launch options | | `port` | `number` | โŒ | `4322` | Preview server port | ### `ScreenshotConfig` | Property | Type | Required | Default | Description | | ------------------- | ------------------- | -------- | ------------------------------- | --------------------------------- | | `outputPath` | `string` | โœ… | - | Output path with format extension | | `width` | `number` | โŒ | `1200` | Viewport width in pixels | | `height` | `number` | โŒ | `630` | Viewport height in pixels | | `gotoOptions` | `GoToOptions` | โŒ | `{ waitUntil: 'networkidle2' }` | Puppeteer goto options | | `screenshotOptions` | `ScreenshotOptions` | โŒ | `{}` | Puppeteer screenshot options | ### Supported Formats The format is automatically detected from the file extension in `outputPath`: - `.png` - PNG format - `.jpg` / `.jpeg` - JPEG format - `.webp` - WebP format ## โ“ FAQ ### Screenshots not generating 1. Check that pages are correctly specified in config 2. Ensure Puppeteer dependencies are installed 3. Verify the build completes without errors 4. Check console output for screenshot generation logs ### Permission errors On some systems, Puppeteer may need additional configuration: ```js launchOptions: { args: ['--no-sandbox', '--disable-setuid-sandbox']; } ``` ### Memory issues with many screenshots Process pages in batches or increase Node memory: ```bash NODE_OPTIONS="--max-old-space-size=4096" npm run build ``` ### Docker deployment Add these args for containerized environments: ```js launchOptions: { args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', ]; } ``` ## ๐Ÿค Contributing Pull requests, bug reports, feature requests, and other kinds of contributions are welcome. See the [contribution guide](docs/CONTRIBUTING.md) for more details. ## ๐Ÿงพ License Copyright ยฉ 2025 [John Goodliff](https://johng.io/r/astro-snapshot) ([@twocaretcat](https://github.com/twocaretcat)). This project is licensed under the MIT license. See the [license](LICENSE) for more details. We are not affiliated with or endorsed by Astro. ## ๐Ÿ–‡๏ธ Related ### Recommended Other projects you might like: - **๐Ÿ‘ค [Gatsby Plugin: Component to Image]**: A similar image generation plugin for the Gatsby framework. ### Used By Notable projects that depend on this one: - **๐Ÿ‘ค [Tally]**: A free online tool to count the number of characters, words, paragraphs, and lines in your text. **Tally** uses this integration to generate social images. ### Alternatives Similar projects you might want to use instead: - **๐ŸŒ [astro-selfie]**: A similar integration that automatically generates images for every page. ## ๐Ÿ’• Funding Find this project useful? [Sponsoring me](https://johng.io/funding) will help me cover costs and **_commit_** more time to open-source. If you can't donate but still want to contribute, don't worry. There are many other ways to help out, like: - ๐Ÿ“ข reporting (submitting feature requests & bug reports) - ๐Ÿ‘จโ€๐Ÿ’ป coding (implementing features & fixing bugs) - ๐Ÿ“ writing (documenting & translating) - ๐Ÿ’ฌ spreading the word - โญ starring the project I appreciate the support! [Astro]: https://astro.build/ [Gatsby]: https://www.gatsbyjs.com/ [astro-selfie]: https://github.com/vadimdemedes/astro-selfie [Open Graph]: https://ogp.me/ [Satori]: https://github.com/vercel/satori [Puppeteer]: https://pptr.dev/ [Gatsby Plugin: Component to Image]: https://github.com/twocaretcat/gatsby-plugin-component-to-image [Tally]: https://tally.johng.io/r/astro-snapshot