最近有个优化是为了减少app的bundle包大小,写了个node脚本用于图片cdn化,有这方面需求的小伙伴阔以康康
以下举例的开发语言为react-native cdn是七牛 小伙伴根据自己的情况自行摘取 图片为.webp格式
需求:本地大量图片导致app的bundleSize过大 以至于想把本地的图片都上传到cdn,并且把对应上传cdn的资源路径替换掉本地require的引用方式
需求直观demo:
本地代码引用块:
source={require('../../xx/images/xx/xx.webp')}
替换后的代码块:
source={{uri: 'https://xx.come/xx.webp'}}
以上就直观展示了需要实现的功能
各位看官 那我就开始划水了~ 啊忒 您就看我细听分说
那我们就来说道说道这 配置篇
话说我用cdn是七牛 既然要上传 各位客官不妨把配置搞一搞
当然 npm install qiniu --save这一步骤可少不了
这是在下列的配置清单 各位客官自行摘取(搬运~我们都是代码的搬运工)
const qiniu = require('qiniu')
// 七牛配置
let config = {}
config.accessKey = 'xxx';
config.secretKey = 'xxx';
config.bucket = 'xxx'; //存储空间的名字
config.url = 'xxx'; //配置的域名
// 获取七牛上传token)
const putPolicy = new qiniu.rs.PutPolicy({ scope: config.bucket });
const mac = new qiniu.auth.digest.Mac(config.accessKey, config.secretKey);
const uploadToken=putPolicy.uploadToken(mac);
// 上传配置
const newConfig = new qiniu.conf.Config();
newConfig.zone = qiniu.zone.Zone_z2
const localFile = xxxx // 本地文件路径
const formUploader = new qiniu.form_up.FormUploader(newConfig) // 生成表单上传的类
const putExtra = new qiniu.form_up.PutExtra() // 生成表单提交额外参数
const key ='按自己需求或者规则来命名 尤其是批量 要考虑防止命名污染' // 重命名文件
关于这个newConfig.zone我可得好好说道说道
关于这个区域 各位看官根据自己条件配置
具体内容各位看官可以挪步:https://developer.qiniu.com/kodo/manual/1671/region-endpoint
看完以上配置以后是不是就差一个重要的配置项key 也就是获取到要上传的图片路径我们就可以上菜了 刚把得
路径篇 各位看官一定要用同步读取写入 不要用异步 防止后续写入的坑
当然 为了读取文件/目录 node提供的fs模块 不得不说 方便的一逼啊
// 获取要上传的图片路径
getImagePath = src => {
const files = fs.readdirSync(src)
files.forEach((file) => {
const _src = `${src}/${file}`
fs.stat(_src, (err,stats)=> {
if (err) {
throw err
}
// 判断为文件
if (stats.isFile()) {
// 读取.webp后缀文件
if (file.includes('.webp')) {
uploadImg(_src,file)
}
} else if (stats.isDirectory()){
getImagePath(_src)
}
})
})
}
我jio得就不要用过于介绍这个了把 相关api方法随便搜一下Node方法 脱裤子都比我快
其实就是给到该方法一个你要去操作的路径 该方法递归查询每个目录下的每个文件 确保找到.webp格式的图片路径
拿到对应的webp格式图片的路径 我们要干嘛 对 刚它
// 图片上传
formUploader.putFile(uploadToken, key, localFile, putExtra, (respErr, respBody, respInfo) => {
if (respErr) {
console.log('上传失败----' + respErr)
throw respErr
}
// 上传成功
if (respInfo.statusCode == 200) {
console.log('上传成功---' + fileName)
xxFunction(fileName, pathName)
} else {
console.log('上传失败----')
console.log(respInfo.statusCode)
console.log(respBody)
}
})
你看这个方法它又大又圆 就像这个面它又长又宽
~~~言归正传 这个方法的入参 从上到下我们是不是就齐活了 对于你传入一个你想上传的路径 啥事你都不要管 就等命令行的 上传成功
到这里 就算再不舍 我也得说再见 ~~~~~ 哎?不对 你说好的替换呢
来了来了
// 获取 .tsx || .ts 文件中需要替换的require地址
getFileImageUrl = (fileName,callBackUrl) => {
const replacePath = callBackUrl || fileReplacePatch // 指定替换的目录
// 读取目录/文件
var files = fs.readdirSync(replacePath)
files.forEach((file) => {
const _src = `${replacePath}/${file}`
fs.stat(_src, (err,stats)=> {
if (err) {
throw err
}
// 判断为文件
if (stats.isFile()) {
// 读取.tsx .ts后缀文件
if (file.includes('.tsx') || file.includes('.ts')) {
// 读取文件信息
var data = fs.readFileSync(_src)
data = data.toString()
const reg = /(?<=require).*?(?=(.webp|$))/g
const arr = data.match(reg)
if (arr) {
try {
arr.forEach((f) => {
let requestUrl = `require${f}.webp')`
let replaceUrl = `{uri: 'xxxx'}`
if (data.indexOf(fileName)> 0) {
if (requestUrl.indexOf(fileName) > 0) {
// 替换的url地址
data = data.replace(requestUrl,replaceUrl)
// 写入文件
fs.writeFileSync(_src, data)
}
}
})
} catch(err) {
console.log(err)
}
}
}
} else if (stats.isDirectory()){
// 获取目录里面文件
getFileImageUrl(fileName,_src)
}
})
})
}
同理 一样逻辑 给到一个你想指定去替换的路径 遍历对应这个路径下所以符合你规则的文件,这里我去替换的文件是.tsx || .ts为后缀的文件 然后按客官你自己的业务规则去匹配你需要替换的内容,我这边匹配规则:
上传cdn成功的图片url去匹配文件中相同命名引用的内容以后替换掉
命令行运行你的脚本吧
到这里 是真的就真的完工了
各位看官 欲知后事如何 请听下回分解