A flexible and powerful thumbnail and screenshot generator for web pages and CMS content blocks. Perfect for generating preview images for your website's pages and components.
- 🎯 Block-level screenshots: Capture individual content blocks from CMS-driven pages
- 📄 Full page screenshots: Generate complete page thumbnails
- 🔧 Highly configurable: Customize viewport, selectors, output formats, and more
- 🏗️ CMS integration: Built-in support for Sanity CMS
- 📦 Multiple formats: PNG and JPEG output with quality control
- 🖥️ CLI interface: Easy command-line usage
- 📚 TypeScript support: Full type safety and IntelliSense
- 🎨 Custom naming: Flexible filename generation strategies
npm install @surajsuthar/thumbnail-generatorIf you want enhanced logging, install the optional peer dependency:
npm install @workspace/logger# Basic usage with environment variables
thumbnail-generator
# Specify a page slug
thumbnail-generator /about
# Custom configuration
thumbnail-generator --base-url https://mywebsite.com --output-dir ./thumbnails /products
# With Sanity CMS integration
thumbnail-generator --sanity-project-id abc123 --sanity-dataset production
# With custom script and pagebuilder
thumbnail-generator --pagebuilder sanity --script ./example-script.js /aboutimport { ThumbnailGenerator, createSanityAdapter } from '@surajsuthar/thumbnail-generator';
const generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com',
outputDir: './thumbnails'
});
const result = await generator.generateThumbnails({
slug: '/about',
overwrite: true
});
console.log(result);
// {
// fullPagePath: './thumbnails/fullpage_about.png',
// blockPreviewPaths: ['./thumbnails/preview-hero.jpg', './thumbnails/preview-content.jpg']
// }import { ThumbnailGenerator, createSanityAdapter } from '@surajsuthar/thumbnail-generator';
const sanityAdapter = createSanityAdapter({
projectId: 'your-project-id',
dataset: 'production',
token: 'your-api-token'
});
const generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com',
outputDir: './thumbnails'
}, sanityAdapter);
await generator.generateThumbnails({ slug: '/about' });interface ThumbnailGeneratorConfig {
// Required
baseUrl: string;
// Optional
outputDir?: string; // Default: "static/thumbnails"
viewport?: ViewportConfig; // Default: { width: 1920, height: 1080 }
blockSelectors?: BlockSelectors; // Default: { element: "[data-block-type]", typeAttribute: "data-block-type" }
navigationOptions?: NavigationOptions; // Default: { waitUntil: "networkidle2", timeout: 30000 }
blockScreenshotOptions?: ScreenshotOptions; // Default: { type: "jpeg", quality: 90 }
pageScreenshotOptions?: ScreenshotOptions; // Default: { type: "png", fullPage: true }
blockSelectorTimeout?: number; // Default: 10000ms
logger?: LoggerInterface; // Default: Console logger
interactive?: boolean; // Default: true
customScript?: string; // Path to custom JS file to execute on page
filenameGenerators?: {
block?: (blockType: string) => string;
page?: (slug: string, prefix?: string) => string;
};
}You can execute custom JavaScript on the page before taking screenshots. This is useful for:
- Hiding cookie banners or overlays
- Waiting for specific elements to load
- Scrolling to load lazy-loaded images
- Applying custom styles or modifications
const generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com',
customScript: './example-script.js'
});
await generator.generateThumbnails({
slug: '/about',
pagebuilder: 'sanity' // Optional: specify your pagebuilder
});Example script (example-script.js):
// This script runs in the browser context
(async () => {
// Hide cookie banners
const banner = document.querySelector('.cookie-banner');
if (banner) banner.style.display = 'none';
// Wait for lazy images to load
window.scrollTo(0, document.body.scrollHeight);
await new Promise(resolve => setTimeout(resolve, 1000));
window.scrollTo(0, 0);
})();CLI usage:
thumbnail-generator --pagebuilder sanity --script ./example-script.js /aboutconst generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com',
blockSelectors: {
element: '.cms-block',
typeAttribute: 'data-component'
}
});const generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com',
filenameGenerators: {
block: (blockType) => `block-${blockType.toLowerCase()}.png`,
page: (slug, prefix) => `${prefix}_${slug.replace('/', '')}.jpg`
}
});const generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com',
viewport: { width: 1280, height: 720 },
blockScreenshotOptions: {
type: 'png',
// quality not applicable for PNG
},
pageScreenshotOptions: {
type: 'jpeg',
quality: 80,
fullPage: false // Only visible area
}
});| Variable | Description | CLI Alternative |
|---|---|---|
SANITY_STUDIO_PRESENTATION_URL |
Base URL for website | --base-url |
SANITY_STUDIO_PROJECT_ID |
Sanity project ID | --sanity-project-id |
SANITY_STUDIO_DATASET |
Sanity dataset | --sanity-dataset |
SANITY_API_TOKEN |
Sanity API token | --sanity-token |
Usage:
thumbnail-generator [options] [slug]
Options:
-s, --slug <slug> Page slug to capture (default: "/")
-u, --base-url <url> Base URL for the website
-o, --output-dir <dir> Output directory for thumbnails
--overwrite Overwrite existing files without prompting
-y, --non-interactive Run in non-interactive mode
-p, --pagebuilder <name> Pagebuilder name (e.g., sanity, wordpress, etc.)
--script <path> Path to custom JavaScript file to execute on the page
--sanity-project-id <id> Sanity project ID
--sanity-dataset <dataset> Sanity dataset
--sanity-token <token> Sanity API token
-h, --help Show help message
new ThumbnailGenerator(config: ThumbnailGeneratorConfig, cmsAdapter?: CMSAdapter)generateThumbnails(options?: ThumbnailGeneratorOptions): Promise<ScreenshotResult | null>import {
ensureDirectory,
generateBlockPreviewFilename,
generateScreenshotFilename
} from '@surajsuthar/thumbnail-generator';# .github/workflows/thumbnails.yml
name: Generate Thumbnails
on: [push, pull_request]
jobs:
thumbnails:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npm run build
- run: npx thumbnail-generator --non-interactive --overwrite
env:
SANITY_STUDIO_PRESENTATION_URL: ${{ secrets.PRESENTATION_URL }}
SANITY_API_TOKEN: ${{ secrets.SANITY_TOKEN }}import { ThumbnailGenerator } from '@surajsuthar/thumbnail-generator';
import type { CMSAdapter } from '@surajsuthar/thumbnail-generator';
class CustomCMSAdapter implements CMSAdapter {
async getBlockTypes(slug: string): Promise<string[]> {
// Your custom logic to fetch block types
const response = await fetch(`https://api.mycms.com/pages/${slug}`);
const data = await response.json();
return data.blocks.map((block: any) => block.type);
}
}
const generator = new ThumbnailGenerator({
baseUrl: 'https://mywebsite.com'
}, new CustomCMSAdapter());The project includes a comprehensive test suite with 46 tests covering all core functionality:
# Run all tests
pnpm test
# Run tests in watch mode for development
pnpm test:watch
# Generate test coverage report
pnpm test:coveragetests/util.test.ts- Utility function tests (100% coverage)tests/index.test.ts- Core functionality teststests/example.test.ts- Integration-style usage pattern tests
See tests/README.md for detailed information about the test suite.
# Build TypeScript to dist/
pnpm build
# Watch mode for development
pnpm dev- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
pnpm test) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT © Suraj Suthar
- Initial release
- Support for Sanity CMS
- CLI interface
- TypeScript support
- Configurable screenshot options
- Custom filename generation