小程序增量图片处理

背景

目前在本地编译时,需要开启一个本地 Server 来托管图片,然后使用自定义插件来替换代码内所有引用相对路径的图片,把相对地址改成本地server路径。

例如:

'/static/index/startWelfare.png' -> 'http://10.70.xxx.xxx:xxxx/index/startWelfare/btn.png'

现在目标是取消采用本地 Server,通过工程化方式把图片全替换成 CDN 地址,提高本地开发效率。

  • 对于之前已经发布上线的图片,图片已经上传到CDN,可以直接替换掉。
  • 新增的图片,通过脚本上传到团队 CDN,然后代码里自动替换成 CDN 地址。

设计

对于已有图片,维护一个映射文件 (本地图片 -> CDN地址)

这里分2个脚本来实现:

  1. 增量图片上传CDN
  2. 扫描components、pages和commonStyle目录,替换图片地址(可以通过映射文件中的记录查找,提高效率)

流程图

image.png

如何获取新增图片?
既然需要将新增的图片上传到CDN,首先就需要找出项目中新增的图片。
这里,我是通过 git status 去获取,然后用正则匹配出图片。

但是很快就遇到了问题:新文件夹下新文件 git status 识别不出来

解决方法是在 git status 命令加上 --untracked-files

const { exec } = require('child_process')
const util = require('util')
const execPromise = util.promisify(exec)

exec('git status --untracked-files', (err, std) => {
  if (err) {
    console.error(`error for exec git status ${err.message}`)
  }

  const newImgs = std.match(/src\/.*\.(png|jpg|jpeg)/g)
  console.log(newImgs)
})

举个例子,假如本次新增了2张图片:gift-logo.pngmain-header.png ,执行上述脚本后得到newImgs

image.png

如果没有新增图片,结束。
如果有新增图片,则读取缓存文件,判断新增图片是否已有缓存记录,如果都有缓存记录,说明这些图片已经上传过了,结束。

 if (!newImgs?.length) {
    return
  }

  const tempJson = readTempFile()
  const needUploadImgs = []

  for (const img of newImgs) {
    if (!tempJson[img]) {
      needUploadImgs.push(img)
    }
  }

  if (!needUploadImgs.length) {
    return
  }

通过命令上传图片到团队CDN。

上传返回结果里有图片的CDN地址,通过字符串操作获取,最终得到了 uploadMap (映射记录表),然后更新缓存文件。

  // ....上传

  // ...获取uploadMap
  
   // 筛选出本次新增的图片
  if (tempJson) {
    for (const img in uploadMap) {
      tempJson[img] = uploadMap[img]
    }
    // 写入缓存文件
    writeTempFile(tempJson)
  }

脚本执行后在项目根目录出现一个图片映射文件:


image.png

扫描源码,替换图片

首先读取缓存文件到内存,然后读取对应目录:

  const tempImgJson = readTempFile();  // tempImgJson 就是上图所示的json文件

  function readDir(dir) {
    fs.readdir(dir, function (err, files) {
      if (err) {
        console.error(err)
      }
      files.forEach(function (file) {
        replaceFile(path.resolve(dir, file))
      })
    })
  }

对于每个文件或目录,如果是文件则找出文件内符合正则的图片地址,替换成缓存记录中CDN地址。
如果是目录,则递归读取替换。

function replaceFile(filePath) {
  
  if (/*是文件*/) {
    fs.readFile(filePath, function (err, data) {
      // ......
      // 替换src和url中符合
      const newData = data
        .replace(/:?src="(.*?)"/g, ($0, $1) => {
          if ($1.includes('/static/')) {/*...*/}
        })
        .replace(/(url\((.*?)\))+/g, ($0, _, $2) => {
          if ($2.includes('@/static/')) {/*...*/}
        })

      if (/*发生变动*/) {
         // 写入文件
      }
    })
  } else if (/*是目录*/) {
    // 递归读目录下的文件
    readDir(filePath)
  }
}

通过分析代码,其中需要替换的代码集中在 .vue 和 .less 中。
而这两种文件又集中在 src/components 和 src/pages、src/commonStyle ,所以最终只需要替换这三个目录下的文件。


  // 替换components目录
  const componentsAbsolutePath = path.resolve(__dirname, '../src/components')
  readDir(componentsAbsolutePath)
  
  // 替换pages目录
  const pagesAbsolutePath = path.resolve(__dirname, '../src/pages')
  readDir(pagesAbsolutePath)

  // 替换commonStyle目录
  const commonStyleAbsolutePath = path.resolve(__dirname, '../src/commonStyle')
  readDir(commonStyleAbsolutePath)

脚本执行时机

在 package.json 中新增命令:

  "scripts" : {
        // ...
        "upload": "node ./script/upload"
   }

由研发自行判断是否需要上传,在合适阶段调用命令执行图片上传CDN及替换。

总结

新方案除了开发提效(6.6s -> 5.9s,编译时长大致提升10%)。

因为是用的Uniapp,需要先把源码编译成小程序代码,所以时间比直接使用原生小程序开发来说较长。

基于小程序的限制,目前只能发布一个小程序测试版本到小程序开发者平台。

假如有两个需求并行测试,那么其中一个需求只能由前端生成一个本地二维码,测试同学扫码测试。
这种做法结合之前本地Server托管图片的方案,就有一个存在的问题,就是前端必须时刻开启本地Server。
假如研发关掉本地Server或者切换分支(切换后分支的图片目录缺少了测试中分支的图片),那么二维码扫码之后小程序将无法访问到那些图片。

而采用新方案后,舍弃了本地Server,图片全部换成CDN,不管开发阶段还是生产阶段,保证了图片的一致性,一定程度上,也方便了测试。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容