静态站点资源体积审计与图片自动压缩流水线

举报
yd_282816122 发表于 2026/11/04 15:21:07 2026/11/04
【摘要】 背景 校园景点介绍页面以大图、轮播图为主,经常遇到几个问题: 1. 设计师/运营直接上传原图,单张图片几MB,页面加载慢;2. 压缩标准不统一:有的用WebP、有的JPG,分辨率参差不齐;3. 无法提前感知本次打包后资源总大小,等到上线才发现首屏体积超标;4. 压缩动作靠手动,容易漏处理新增图片,增量发布时无法自动识别哪些图片需要重压缩。 前面我们已经实现了资源路径校验、环境隔离、manif...


背景

 

校园景点介绍页面以大图、轮播图为主,经常遇到几个问题:

 

1. 设计师/运营直接上传原图,单张图片几MB,页面加载慢;

2. 压缩标准不统一:有的用WebP、有的JPG,分辨率参差不齐;

3. 无法提前感知本次打包后资源总大小,等到上线才发现首屏体积超标;

4. 压缩动作靠手动,容易漏处理新增图片,增量发布时无法自动识别哪些图片需要重压缩。

 

前面我们已经实现了资源路径校验、环境隔离、manifest增量比对,现在把资源体积审计 + 图片自动压缩前置到构建阶段,作为CI卡点。

 

核心思路

 

整体分为两个阶段:

 

1. 审计阶段:扫描资源目录,统计各类型文件大小,输出体积报表,超过阈值给出告警;

2. 压缩阶段:对图片进行无损/有损压缩,自动生成WebP兼容格式,保留原图用于归档;

 

约束:只处理图片资源,js/css不做混淆压缩(简单站点场景);审计结果写入报告,可作为CI流水线产物。

 

依赖包: sharp (高性能图片处理)、 filesize (友好大小格式化)

 

bash

npm install sharp filesize --save-dev

 

 

实现脚本

 

1. 资源审计脚本  audit-assets.js 

 

javascript

const fs = require('fs');

const path = require('path');

const filesize = require('filesize');


const distDir = path.resolve(__dirname, './dist');

const LIMITS = {

  total: 8 * 1024 * 1024, // 全站静态资源上限 8MB

  singleImage: 500 * 1024 // 单张图片上限 500KB

};


const imageExt = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];

let totalSize = 0;

const oversizedList = [];

const report = [];


function scan(dir) {

  const entries = fs.readdirSync(dir);

  for (const entry of entries) {

    const full = path.join(dir, entry);

    const stat = fs.statSync(full);

    if (stat.isDirectory()) {

      scan(full);

      continue;

    }

    const ext = path.extname(full).toLowerCase();

    totalSize += stat.size;

    report.push({ path: full, size: stat.size });

    if (imageExt.includes(ext) && stat.size > LIMITS.singleImage) {

      oversizedList.push({ path: full, size: stat.size });

    }

  }

}


scan(distDir);

const totalOk = totalSize < LIMITS.total;

const singleOk = oversizedList.length === 0;


console.log(`📊 资源总大小:${filesize(totalSize)}`);

if (!totalOk) console.warn('❌ 警告:全站资源超出总阈值!');

if (oversizedList.length > 0) {

  console.warn(`❌ 发现 ${oversizedList.length} 张超大图片:`);

  oversizedList.forEach(item => console.warn(` ${item.path} ${filesize(item.size)}`));

}


// 输出审计报告

fs.writeFileSync('./dist/asset-audit.json', JSON.stringify({

  totalSize,

  totalLimit: LIMITS.total,

  pass: totalOk && singleOk,

  oversizedList,

  report

}, null, 2));


// CI 阻断:不通过直接退出非0码

if (!totalOk || !singleOk) {

  process.exit(1);

}

 

 

2. 图片自动压缩脚本  compress-images.js 

 

javascript

const fs = require('fs');

const path = require('path');

const sharp = require('sharp');


const srcDir = path.resolve(__dirname, './src/images');

const outDir = path.resolve(__dirname, './dist/images');

if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });


const imageExt = ['.jpg', '.jpeg', '.png'];

const quality = 75;


async function compressImage(file) {

  const ext = path.extname(file).toLowerCase();

  const baseName = path.basename(file, ext);

  const inputPath = path.join(srcDir, file);

  const outputJpg = path.join(outDir, `${baseName}.jpg`);

  const outputWebp = path.join(outDir, `${baseName}.webp`);


  await sharp(inputPath)

    .resize({ width: 1600, withoutEnlargement: true })

    .jpeg({ quality })

    .toFile(outputJpg);


  await sharp(inputPath)

    .resize({ width: 1600, withoutEnlargement: true })

    .webp({ quality })

    .toFile(outputWebp);

  console.log(`✅ 已处理:${file}`);

}


async function run() {

  const files = fs.readdirSync(srcDir);

  for (const f of files) {

    const ext = path.extname(f).toLowerCase();

    if (imageExt.includes(ext)) {

      await compressImage(f);

    }

  }

  console.log('🎉 图片压缩全部完成');

}

run().catch(e => {

  console.error('压缩失败:', e);

  process.exit(1);

});

 

 

流水线编排顺序(CI Job)

 

plaintext

1. 资源路径白名单校验脚本

2. 图片自动压缩脚本

3. HTML/CSS/JS打包复制

4. 资源审计脚本(卡点,失败直接阻断发布)

5. 生成manifest清单

6. manifest差异比对,生成增量上传列表

7. 增量上传静态资源

 

 

页面中使用 picture 标签做WebP降级,兼容老旧浏览器:

 

html

<picture>

  <source srcset="images/scene.webp" type="image/webp">

  <img src="images/scene.jpg" alt="校园景点">

</picture>

 

 

工程权衡

 

✅ 收益

 

- 新增图片自动压缩,避免运营上传原图拖慢页面;

- 审计卡点提前拦截超大体量资源,上线前发现问题;

- 同时输出WebP,大幅降低图片流量,对手机端访问友好;

- 审计报告和manifest清单可以一起归档,每次发布可追溯资源体积变化。

 

⚠️ 风险与取舍

 

- sharp 依赖原生模块,部分CI环境需要预装依赖;

- 有损压缩质量75是折中值,重要实景照片可以单独调高质量;

- 已经手动优化好的图片,可增加  .skip-compress  标记跳过处理;

- 审计阈值可区分测试环境、公网环境,测试环境阈值放宽。

 

和之前模块联动

 

- 和manifest增量脚本:压缩后图片hash会变更,自动纳入增量上传列表;

- 和资源白名单校验:压缩输出目录同样经过路径规则校验;

- 和环境变量隔离:不同环境可配置不同的图片压缩质量、体积阈值。

 

后续演进方向

 

1. 接入图片内容简单检测:识别超大空白图、重复图片;

2. 增加LCP指标模拟预估,不只是看文件大小;

3. 支持图片懒加载属性自动注入,不用手动改HTML;

4. 把审计报告输出成Markdown,直接作为CI评论推送到仓库。

 

 

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。