UNPKG

snipify

Version:

A production-ready tool for capturing and processing web screenshots with Puppeteer and Sharp.

1 lines 4.21 kB
import{mkdir as e,writeFile as t}from"fs/promises";import{dirname as i,join as a}from"path";import{launch as o}from"puppeteer";import r from"sharp";import{fileURLToPath as n}from"url";var s={desktop:{viewport:{width:1920,height:1080},userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64)...Chrome/121.0.0.0 Safari/537.36"},laptop:{viewport:{width:1366,height:768},userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64)...Chrome/121.0.0.0 Safari/537.36"},tablet:{viewport:{width:768,height:1024},userAgent:"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X)...Safari/604.1"},mobile:{viewport:{width:375,height:667},userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...Safari/604.1"},"mobile-large":{viewport:{width:414,height:896},userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...Safari/604.1"}},l={thumbnail:{width:300,height:200},card:{width:400,height:300},"social-media":{width:1200,height:630},"instagram-post":{width:1080,height:1080},"instagram-story":{width:1080,height:1920},"youtube-thumbnail":{width:1280,height:720},"blog-header":{width:800,height:400},"email-banner":{width:600,height:200},"preview-small":{width:200,height:150},"preview-medium":{width:400,height:300},"preview-large":{width:800,height:600}},h=i(n(import.meta.url));async function u({url:e,device:t="desktop",options:i={}}){const{outputPath:a,format:r,quality:n,fullPage:l,waitForSelector:h,delay:u,headless:c,blockResources:p,clip:g,fixedSize:f}=function(e={}){const{outputPath:t,format:i="png",quality:a=90,fullPage:o=!0,waitForSelector:r,delay:n=0,headless:s=!0,blockResources:l=!1,clip:h=null,fixedSize:u=null}=e;return{outputPath:t,format:i,quality:a,fullPage:o,waitForSelector:r,delay:n,headless:s,blockResources:l,clip:h,fixedSize:u}}(i);if(!s[t])throw new Error(`Unknown device preset: ${t}. Available: ${Object.keys(s).join(", ")}`);const m=await o({headless:c,args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-web-security","--disable-features=VizDisplayCompositor"]});let y=null;try{y=await m.newPage();const{viewport:i,userAgent:o}=s[t];await y.setViewport(i),await y.setUserAgent(o),p&&(await y.setRequestInterception(!0),y.on("request",(e=>{try{const t=e.resourceType(),i=e.url();"media"===t||"image"===t&&(i.includes(".mp4")||i.includes(".webm"))||"websocket"===t||i.includes("analytics")||i.includes("tracking")?e.abort():e.continue()}catch{e.continue()}}))),await y.goto(e,{waitUntil:"networkidle0",timeout:3e4}),h&&await y.waitForSelector(h,{timeout:1e4}),u>0&&await new Promise((e=>setTimeout(e,u)));const c={fullPage:!g&&l,type:r,..."jpeg"===r&&{quality:n},...g&&{clip:g}};let b=await y.screenshot(c);return f&&(b=await d(Buffer.from(b),f,r,n)),a&&await w(Buffer.from(b),a),b}finally{y&&await y.close(),await m.close()}}async function c({url:e,device:t="desktop",sizes:i=["thumbnail","card","social-media"],options:o={}}){const{outputDir:r=a(h,"screenshots"),format:n="png",quality:s=90}=o,c=[],g=await u({url:e,device:t,options:{...o,outputPath:void 0,fullPage:!0}});for(const o of i)try{const i=l[o];if(!i.width||!i.height)continue;const h=await d(Buffer.from(g),i,n,s),u=await p(e,t,n,o),f=a(r,u);await w(h,f),c.push({size:o,dimensions:i,buffer:h,path:f,fileSize:`${(h.length/1024).toFixed(2)} KB`})}catch(e){}return c}async function w(a,o){try{const r=i(o);await e(r,{recursive:!0}),await t(o,a)}catch(e){throw new Error(`Failed to save screenshot: ${e.message}`)}}async function d(e,t,i="png",a=100){try{let o=r(e).resize(t.width,t.height,{fit:"cover",position:"top"});return"jpeg"===i?o=o.jpeg({quality:a}):"png"===i&&(o=o.png({compressionLevel:9})),await o.toBuffer()}catch(e){throw new Error(`Failed to resize image: ${e.message}`)}}async function p(e,t,i="png",a){const o=new URL(e).hostname.replace(/\./g,"-"),r=(new Date).toISOString().replace(/[:.]/g,"-").split("T")[0];let n="";return a&&("string"==typeof a?n=`-${a}`:a.width&&a.height&&(n=`-${a.width}x${a.height}`)),`screenshot-${o}-${t}${n}-${r}.${i}`}if("undefined"!=typeof window)throw new Error("Snipify can only be used in Node.js environments.");export{s as DEVICE_PRESETS,l as PRODUCTION_SIZES,c as captureProductionScreenshots,u as captureScreenshot,p as generateFilename};