
Onlook 服務端圖片壓縮指南基于 Sharp 的 onlook/image-server 實踐與源碼解析【免費下載鏈接】onlookThe Cursor for Designers ? An Open-Source AI-First Design tool ? Visually build, style, and edit your React App with AI項目地址: https://gitcode.com/GitHub_Trending/on/onlook本篇技術指南圍繞 Onlook 開源倉庫中的packages/image-server包展開它是一套僅限服務端運行的圖片壓縮工具集底層基于 Sharp^0.33.5實現。文章會完整覆蓋該包的安裝方式、兩個核心 APIcompressImageServer與batchCompressImagesServer的調用方法、全部壓縮參數與默認值、格式支持/跳過規則、內置壓縮預設并結合 compress.ts 源碼、image.test.ts 測試用例以及 image.ts 中的真實 tRPC 集成示例說明它在 Onlook 實際項目里的落地方式。讀完本文你將能獨立在任意 Node.js 服務API 路由、服務端函數、批處理腳本中完成圖片壓縮、格式轉換、縮放與批量處理并理解其設計邊界。一、包定位與使用紅線只能在服務端使用onlook/image-server在package.json中的描述是 Server-side image processing utilities for Onlook其唯一運行時依賴是sharp^0.33.5并要求node 18.0.0。Sharp 是典型的 Node.js 原生模塊依賴 libvips 原生庫因此該包絕對不能在瀏覽器或 Electron preload 腳本中導入?安全使用場景Node.js 服務器、API 路由如 Next.js Route Handlers / Server Actions、服務端函數、批處理腳本?禁止使用場景瀏覽器端代碼、Electron preload 腳本、客戶端組件這一約束不僅寫在 README 開頭也以注釋形式固化在包的入口文件packages/image-server/src/index.ts第一行// ?? WARNING: This package contains Node.js-only dependencies (Sharp). Do not use in a browser environment. export * from ./compress; export * from ./types;從源碼結構看入口只做兩件事導出壓縮實現compress.ts與共享類型types.ts。這意味著你在任何import { compressImageServer } from onlook/image-server的地方都應先確認該模塊運行在服務端進程內。二、安裝方式該包是 Onlook monorepo使用 Bun 管理內部包需要服務端圖片處理能力的其他包直接在dependencies中聲明即可{ dependencies: { onlook/image-server: * } }安裝后可從包入口獲得以下導出compressImageServer單張圖片壓縮batchCompressImagesServer批量壓縮CompressionOptions/CompressionResult/SupportedFormat類型定義詳見后文三、快速上手兩個核心 API3.1 單圖壓縮compressImageServer(input, outputPath?, options?)簽名compress.tsexport async function compressImageServer( input: string | Buffer, outputPath?: string, options: CompressionOptions {}, ): PromiseCompressionResultinputstring | Buffer—— 文件路徑或圖片 BufferBuffer 輸入在服務端接收上傳、tRPC 傳參等場景下非常實用outputPath可選。提供則壓縮結果寫入該文件不提供則返回內存 Bufferoptions可選壓縮配置完整參數見第四節典型用法一壓縮并保存為 WebP 文件。import { compressImageServer } from onlook/image-server; // Compress and save to file const result await compressImageServer(input.jpg, output.webp, { quality: 80, format: webp, });典型用法二壓縮到內存 Buffer適合后續上傳、入庫或經接口返回。// Compress to buffer const result await compressImageServer(input.jpg, undefined, { quality: 70 });當outputPath缺省時實現走toBuffer({ resolveWithObject: true })分支result.buffer即為壓縮后的數據見 compress.ts。3.2 批量壓縮batchCompressImagesServer(inputPaths, outputDir, options?)簽名compress.tsexport async function batchCompressImagesServer( inputPaths: string[], outputDir: string, options: CompressionOptions {}, ): PromiseCompressionResult[]import { batchCompressImagesServer } from onlook/image-server; const results await batchCompressImagesServer( [image1.jpg, image2.png], ./output-directory, { format: webp, quality: 85 }, );實現細節可從源碼確認先fs.mkdir(outputDir, { recursive: true })確保輸出目錄存在過濾掉.ico/.svg路徑并為每個被跳過的文件在結果數組中插入一條success: false的跳過記錄保證返回結果數量與輸入數量一一對應剩余文件通過Promise.all并行調用compressImageServer輸出文件名為原名去擴展名.輸出格式例如photo.jpg→photo.webp見 compress.ts。注意批量模式下若format缺省或為auto統一按webp輸出compress.ts與單圖壓縮的“自動推導原格式”策略不同這是批量場景為了統一輸出格式而做的取舍。四、完整參數表與默認值CompressionOptions定義在 types.tscompressImageServer的解構默認值位于 compress.ts兩者合并后如下參數類型默認值說明qualitynumber80有損格式質量JPEG/WebP/AVIF 適用0–100widthnumber未設置縮放目標寬度與height至少提供一個才觸發縮放heightnumber未設置縮放目標高度formatSupportedFormat \| autoauto輸出格式jpeg/png/webp/avifauto按輸入自動推導progressivebooleantrue漸進式編碼JPEG/PNG 適用mozjpegbooleantrue是否使用 mozjpeg 編碼器JPEG 適用effortnumber4編碼努力程度WebP/AVIF 適用越高壓縮率越好、耗時越長compressionLevelnumber6PNG 壓縮級別0–9keepAspectRatiobooleantrue縮放時是否保持寬高比。true用sharp.fit.insidefalse用sharp.fit.fill可能拉伸變形withoutEnlargementbooleantrue原圖小于目標尺寸時不做放大SupportedFormat僅包含四種輸出格式types.tsexport type SupportedFormat jpeg | png | webp | avif;4.1 縮放邏輯當width或height存在時源碼會構造 resize 參數const resizeOptions { width, height, fit: keepAspectRatio ? sharp.fit.inside : sharp.fit.fill, withoutEnlargement, }; sharpInstance sharpInstance.resize(resizeOptions);keepAspectRatio: truefit: inside等比縮放結果不會超過目標矩形適合縮略圖場景keepAspectRatio: falsefit: fill強制填滿目標尺寸可能改變寬高比。4.2 按格式分派的壓縮參數applyFormatCompressioncompress.ts把統一選項映射到各格式的 Sharp 編碼參數輸出格式使用的 Sharp 選項生效參數jpeg.jpeg({ quality, progressive, mozjpeg })質量、漸進式、mozjpegpng.png({ compressionLevel, progressive })壓縮級別、漸進式webp.webp({ quality, effort })質量、努力程度avif.avif({ quality, effort })質量、努力程度兜底.webp({ quality, effort })同 WebP4.3auto格式的推導規則determineOptimalFormatcompress.ts根據輸入圖片的元數據格式而非僅憑擴展名決定輸出格式輸入格式輸出格式理由jpeg/jpgjpeg保持照片格式pngpng保留透明通道與無損特性gifwebp動圖轉靜圖壓縮率更好tiff/tifjpeg高保真源轉常見格式其他 / 未知webp默認選擇現代高壓縮格式五、支持與跳過的格式5.1 支持的輸入格式?JPEG/JPG有損壓縮適合照片PNG無損壓縮支持透明WebP現代格式壓縮率與畫質均衡TIFF/TIF高質量圖像GIF動圖/靜態圖會被轉為靜態幀BMP位圖5.2 自動跳過的格式??以下格式會被自動跳過并返回失敗結果而不是嘗試壓縮ICO圖標文件本身已針對 favicon、應用圖標場景優化直接使用原文件即可SVG矢量圖形應保持可縮放不應柵格化// These will return { success: false, error: Skipping ICO/SVG file... } await compressImageServer(favicon.ico, output.webp); // ? Skipped await compressImageServer(logo.svg, output.png); // ? Skipped源碼中這一判斷有兩道防線compress.ts 與 compress.ts擴展名檢查輸入為字符串路徑時path.extname(input).toLowerCase()命中.ico/.svg直接返回錯誤錯誤信息形如Skipping .ICO file - format not supported for compression. Use original file instead.元數據檢查即使輸入是 Buffer無擴展名也會調用sharpInstance.metadata()檢查真實格式若元數據為svg同樣返回Skipping SVG format - not supported for compression。這一設計保證“偽裝成其他擴展名/以 Buffer 傳入的 SVG”也不會被誤壓縮測試用例SVG buffer input專門驗證了這條路徑。為什么跳過ICO 已針對 favicon/應用圖標場景優化SVG 是矢量圖壓縮會破壞可縮放性。正確做法是直接使用原文件。六、返回結果結構CompressionResulttypes.tsexport interface CompressionResult { success: boolean; originalSize?: number; // 原始大小字節 compressedSize?: number; // 壓縮后大小字節 compressionRatio?: number; // 壓縮率百分比(originalSize - compressedSize) / originalSize * 100 outputPath?: string; // 寫入文件時的輸出路徑 buffer?: Buffer; // 未指定 outputPath 時的壓縮結果數據 error?: string; // 失敗時的錯誤信息 }原始大小文件路徑輸入時取fs.stat的sizeBuffer 輸入時取input.lengthcompress.ts。compressionRatio為負數說明壓縮后反而更大例如 PNG 轉 PNG 無損場景這是正常現象需要調用方按業務判斷。七、使用內置壓縮預設Onlook 在packages/constants/src/files.ts中預置了 4 組常用壓縮配置可直接與compressImageServer組合使用避免每次手寫參數import { compressImageServer } from onlook/image-server; import { COMPRESSION_IMAGE_PRESETS } from onlook/constants; // Use predefined presets const result await compressImageServer(input.jpg, output.webp, COMPRESSION_IMAGE_PRESETS.web);各預設的完整定義與 README 描述一一對應并可從源碼確認精確值預設用途具體參數源碼值webWeb 交付優化WebPquality 80progressiveeffort 4thumbnail小縮略圖300×300WebPquality 70keepAspectRatiohighQuality高質量輸出JPEGquality 95progressivemozjpeglowFileSize極致壓縮體積WebPquality 60effort 6注意thumbnail預設的 300×300 配合keepAspectRatio: true意味著“等比縮放到 300×300 矩形內”不會拉伸變形。八、錯誤處理與健壯性設計該包采取“函數永不拋出錯誤一律折疊進結果對象”的策略compress.ts} catch (error) { return { success: false, error: error instanceof Error ? error.message : Unknown error occurred, }; }調用方只需檢查result.successconst result await compressImageServer(input.jpg); if (!result.success) { console.error(Compression failed:, result.error); // Common error cases: // - Skipping .ICO file - format not supported for compression. Use original file instead. // - Skipping SVG format - not supported for compression. Use original file instead. // - File not found, permission errors, corrupted files, etc. }批量接口batchCompressImagesServer同樣把整體異常收斂為單個失敗結果數組compress.ts。測試覆蓋了哪些錯誤場景image.test.ts 中的Input Validation與Error Handling兩組用例驗證了不存在的文件 →success: false空字符串輸入 →success: false損壞的圖片文件寫入非圖片內容的假.jpg→success: false權限錯誤輸出到/root/impossible-path.jpg→success: false偽造的.ico/.svg文件 →success: false真實 ICO / SVG 文件 → 正確跳過且不產生輸出文件測試斷言輸出文件不存在九、Onlook 中的真實集成tRPC 壓縮接口在 Onlook 的 Web 應用中該包被 image.ts 包裝為受保護的 tRPC mutationimage.compress是“服務端壓縮”的教科書式用法import { compressImageServer, type CompressionOptions, type CompressionResult } from onlook/image-server; import { z } from zod; import { createTRPCRouter, protectedProcedure } from ../trpc;核心流程image.ts客戶端上傳base64 編碼的圖片數據服務端Buffer.from(input.imageData, base64)還原為 Buffer以 Buffer 形式調用compressImageServer(buffer, undefined, options)不寫磁盤由于未指定outputPath返回結果中的buffer字段攜帶壓縮后數據服務端將其再轉為 base64bufferData字段傳回客戶端——因為 tRPC 結果序列化不直接支持 Buffer。同時 project.ts 也在項目相關邏輯中導入了compressImageServer用于服務端圖片落盤前的壓縮。這兩個真實調用點可以印證Buffer 輸入 不落盤 結果折疊的組合是該包在 API 服務中的主流用法。十、測試體系與驗證方式包內測試位于packages/image-server/test/image.test.ts使用bun:test運行測試樣本圖片存放在test/images/input含favicon.ico、jpg.jpg、png.png、svg.svg、webp.webp。測試維度包括輸入校驗不存在的文件、空輸入真實圖片壓縮JPEG、PNG 壓縮到 WebP校驗originalSize 0、compressedSize 0、compressionRatio 0且輸出文件真實存在auto 格式推導不指定格式時的自動輸出縮放指定width/height后正確輸出Buffer 輸出result.buffer為合法 Buffer 且長度與compressedSize一致ICO / SVG 跳過單圖與批量兩條路徑均驗證success: false、錯誤信息包含Skipping .ICO file/Skipping .SVG file、且輸出文件未被創建Buffer 形式的 SVG 也正確跳過混合格式批量結果數量與輸入一致成功項有輸出文件被跳過項錯誤信息正確質量對比[95, 80, 65, 50]多檔質量壓縮全部成功異常處理損壞文件、權限錯誤、偽造的 ICO/SVG十一、小結與最佳實踐onlook/image-server是一個聚焦且健壯的服務端圖片壓縮模塊圍繞 Sharp 封裝了格式推導、格式專屬壓縮參數、縮放、批量處理與 ICO/SVG 防御性跳過并把所有錯誤折疊進結果對象。在實際項目中使用時建議遵循以下實踐嚴守服務端邊界只在 Node.js 進程API 路由、服務端函數、腳本中導入勿在瀏覽器或 Electron preload 中使用優先用預設Web 交付用COMPRESSION_IMAGE_PRESETS.web縮略圖用thumbnail追求畫質用highQuality追求體積用lowFileSize善用 Buffer 模式處理上傳流或需要返回壓縮結果的接口時省略outputPath從result.buffer取數據始終檢查success該包不拋異常跳過與失敗都以success: falseerror表達調用方務必顯式處理ICO/SVG 直接透傳它們會被跳過是設計行為請直接使用原文件。許可證Apache-2.0。【免費下載鏈接】onlookThe Cursor for Designers ? An Open-Source AI-First Design tool ? Visually build, style, and edit your React App with AI項目地址: https://gitcode.com/GitHub_Trending/on/onlook創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考