Node sharp 插件压缩整个image文件

安装 sharp

npm install sharp
或
yarn add sharp

使用:

  1. 创建一个 compress.js 放到image文件夹里面与图片平级, 完全拷贝进去,什么都不用改
// compress.js

import sharp from 'sharp';
import fs from 'fs';  // node 自带的 无需单独安装
import path from 'path'; // node 自带的 无需单独安装
import { fileURLToPath } from 'url'; // node 自带的 无需单独安装

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 支持的图片格式
const imageExtensions = ['.png', '.jpg', '.jpeg', '.webp'];

// 自动获取目录下所有图片文件
function getAllImageFiles() {
  const files = fs.readdirSync(__dirname);
  return files.filter(file => {
    const ext = path.extname(file).toLowerCase();
    // 排除压缩脚本本身和已压缩的文件
    return imageExtensions.includes(ext) && 
           !file.includes('compress.js') &&
           !file.includes('_compressed');
  });
}

// 获取所有图片文件
const imageFiles = getAllImageFiles();

// 压缩配置
const compressOptions = {
  // PNG 压缩选项
  png: {
    quality: 80, // 质量,0-100,0表示最低质量,100表示最高质量
    compressionLevel: 9 // 压缩等级,0-9,0表示无损压缩,9表示最高压缩比
  },
  // JPEG 压缩选项
  jpeg: {
    quality: 80, // 质量,0-100,0表示最低质量,100表示最高质量
    mozjpeg: true // 是否使用MozJPEG算法
  },
  // WebP 压缩选项
  webp: {
    quality: 80
  }
};

// 批量压缩函数
async function compressImages() {
  if (imageFiles.length === 0) {
    console.log('⚠️  未找到需要压缩的图片文件');
    return;
  }
  
  console.log(`📁 找到 ${imageFiles.length} 个图片文件:`);
  imageFiles.forEach((file, index) => {
    console.log(`   ${index + 1}. ${file}`);
  });
  console.log('');
  
  const results = [];
  
  for (const file of imageFiles) {
    const inputPath = path.join(__dirname, file);
    const ext = path.extname(file).toLowerCase();
    // 使用临时文件,然后替换原文件
    const tempPath = path.join(__dirname, `${file}.tmp`);
    
    // 检查文件是否存在
    if (!fs.existsSync(inputPath)) {
      console.log(`⚠️  文件不存在: ${file}`);
      continue;
    }
    
    try {
      const inputStats = fs.statSync(inputPath);
      const inputSize = inputStats.size;
      
      let sharpInstance = sharp(inputPath);
      
      // 根据文件类型应用不同的压缩选项
      if (ext === '.png') {
        sharpInstance = sharpInstance.png(compressOptions.png);
      } else if (ext === '.jpg' || ext === '.jpeg') {
        sharpInstance = sharpInstance.jpeg(compressOptions.jpeg);
      } else if (ext === '.webp') {
        sharpInstance = sharpInstance.webp(compressOptions.webp);
      }
      
      // 先压缩到临时文件
      await sharpInstance.toFile(tempPath);
      
      // 删除原文件
      fs.unlinkSync(inputPath);
      
      // 将临时文件重命名为原文件名
      fs.renameSync(tempPath, inputPath);
      
      const outputStats = fs.statSync(inputPath);
      const outputSize = outputStats.size;
      const compressionRatio = ((1 - outputSize / inputSize) * 100).toFixed(2);
      
      results.push({
        file,
        originalSize: (inputSize / 1024).toFixed(2) + ' KB',
        compressedSize: (outputSize / 1024).toFixed(2) + ' KB',
        compressionRatio: compressionRatio + '%',
        success: true
      });
      
      console.log(`✅ ${file}: ${(inputSize / 1024).toFixed(2)} KB → ${(outputSize / 1024).toFixed(2)} KB (压缩 ${compressionRatio}%)`);
    } catch (error) {
      // 清理临时文件(如果存在)
      if (fs.existsSync(tempPath)) {
        fs.unlinkSync(tempPath);
      }
      console.error(`❌ 压缩失败 ${file}:`, error.message);
      results.push({
        file,
        success: false,
        error: error.message
      });
    }
  }
  
  // 输出汇总信息
  console.log('\n📊 压缩汇总:');
  console.log('='.repeat(60));
  const successCount = results.filter(r => r.success).length;
  const failCount = results.filter(r => !r.success).length;
  console.log(`成功: ${successCount} 个文件`);
  console.log(`失败: ${failCount} 个文件`);
  
  if (successCount > 0) {
    const totalOriginal = results
      .filter(r => r.success)
      .reduce((sum, r) => {
        const size = parseFloat(r.originalSize);
        return sum + size;
      }, 0);
    const totalCompressed = results
      .filter(r => r.success)
      .reduce((sum, r) => {
        const size = parseFloat(r.compressedSize);
        return sum + size;
      }, 0);
    const totalRatio = ((1 - totalCompressed / totalOriginal) * 100).toFixed(2);
    console.log(`总大小: ${totalOriginal.toFixed(2)} KB → ${totalCompressed.toFixed(2)} KB`);
    console.log(`总压缩率: ${totalRatio}%`);
  }
  
  console.log('\n💡 提示: 压缩后的文件已直接覆盖原文件');
}

// 执行压缩
compressImages().catch(console.error);


  1. cd 进入image文件目录,终端执行 node compress.js
node compress.js
  1. 效果图:


    image.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容