背景:
众所周知,小程序主包&分包大小限制(2M),目前很多开发者都为之抓耳挠腮。
然而目前在现在的开发过程中,一张前端切图动辄十多 K, 几十 K,甚至有些 gif 图片上百 K 都是很常见的。
我们从包大小的角度思考,如果空间都拿来存储图片资源,属实是非常浪费的。
相信每个小程序开发者都对此有过思考,也看到有的项目已经用网络图片来解决此问题。但如果只是拷贝 url 拿过来用,使用起来会比较繁琐,维护起来比较麻烦,怎么更优雅的用,更优雅的维护是我们所追求的。
这里利用腾讯云提供的 对象存储服务(COS)& cos-node-js-sdk,讲一下我对于前端切图素材的解决方案。
思路:
在对象存储上,其实是跟电脑的硬盘一样,是有目录结构的。
如图我们以 ui-material 文件夹为根目录,所有的图片资源都放在这个目录里。
而文件目录本身就是树形结构的,放一张图可能更容易理解
所以就有了思考,想能不能把所有图片以 JSON 的方式存储 ? key=>文件名,value=>图片地址
比如我想访问 HP.jpg 这张图片,我希望是这样的访问 Images.HP
而访问 active/IBM.jpg 我希望是 Images.active.IBM
也就是说把文件的 path 以 json 的方式输出就是不是就 ok 了 ~
下面使用 node 实现 ~
安装依赖:
npm install cos-nodejs-sdk-v5 path-parse ramda lodash --save -dev
1.连接 cos :
// index.js
const COS = require("cos-nodejs-sdk-v5");
const PathParse = require("path-parse");
const Ramda = require("ramda");
const Lodash = require("lodash");
const fs = require("fs");
/** 这里是一些对象存储的配置信息,可以在腾讯云控制台中查看 */
const COS_SECRETID = "xxxx填你自己的";
const COS_SECRETKEY = "xxxx填你自己的";
const COS_BUCKET = "log-1255751956";
const COS_REGION = "ap-hongkong";
const COS_ENCODING_TYPE = "url";
/** 访问地址 */
const COS_ACCESS_DOMAIN = "https://log-1255751956.cos.ap-hongkong.myqcloud.com";
/** UI素材资源目录 */
const UI_MATERIAL_PATH = "ui-material";
/** 获取 cos 实例 */
const cos = new COS({
SecretId: COS_SECRETID,
SecretKey: COS_SECRETKEY,
});
__2.获取 __ ui-material 文件夹下的__文件列表,通过官方提供的 cos-node-js-sdk __
/** 获取 Bucket 信息
* 我们只获取 ui-material 这个文件夹下的文件
* 所以后面后面统一上传素材文件到这个目录下*/
cos.getBucket(
{
/**指定存储桶 */
Bucket: COS_BUCKET,
/**指定地区 */
Region: COS_REGION,
/**指定文件夹 */
Prefix: `${UI_MATERIAL_PATH}/`,
/**指定编码方式 */
EncodingType: COS_ENCODING_TYPE,
},
(err, data) => {
if (!err) {
const { Contents } = data;
console.log('Contents==>',Contents);
} else {
console.log("getBuket err", err);
}
}
);
// 输出结果:
[
{
Key: 'ui-material/',
LastModified: '2021-09-09T06:32:28.000Z',
ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
Size: '0',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
},
{
Key: 'ui-material/HP.png',
LastModified: '2021-09-09T15:43:49.000Z',
ETag: '"4363f2b9df8a0ec2de805ae2938571fb"',
Size: '10990',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
},
{
Key: 'ui-material/active/',
LastModified: '2021-09-09T09:24:18.000Z',
ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
Size: '0',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
},
{
Key: 'ui-material/active/IBM.png',
LastModified: '2021-09-09T15:44:31.000Z',
ETag: '"b5974b615efa779c702a15316490f464"',
Size: '3202',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
},
{
Key: 'ui-material/active/moduleA/',
LastModified: '2021-09-09T15:46:04.000Z',
ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
Size: '0',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
},
{
Key: 'ui-material/active/moduleA/intel.png',
LastModified: '2021-09-09T15:46:12.000Z',
ETag: '"edec5fe92c7d52cb69a40890eaa6a113"',
Size: '5316',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
},
{
Key: 'ui-material/order.png',
LastModified: '2021-09-09T07:18:30.000Z',
ETag: '"dd5cee76f07bc77f1e3b8b5e65e130da"',
Size: '3106',
Owner: { ID: '1255751956', DisplayName: '1255751956' },
StorageClass: 'STANDARD'
}
]
我们可以清晰的看见 List 中的 Key 其实就是我们所需要的文件路径,我们只需要去解析这个 Key 就 ok 了
3.获取图片路径:
const Key = 'ui-material/active/moduleA/intel.png';
const url = `${COS_ACCESS_DOMAIN}/${Key}`
// 结果=====> https://log-1255751956.cos.ap-hongkong.myqcloud.com/ui-material/active/moduleA/intel.png
4.获取图片对应的 objcet props:
const parsePath = PathParse(Key); /** 解析 path 信息 **/
const props = [ ...parsePath.dir.split('/') ,parsePath.name ];
props.shift(); /** 删除数组第一个元素,因为 ui-material 是根目录 ===> [ 'active', 'moduleA', 'intel' ] **/
5.利用 loadsh.set 为对象属性赋值
let obj = {};
Lodash.set(obj, props, url);
console.log(obj)
/** =====>
{
active: {
moduleA: {
intel: 'https://log-1255751956.cos.ap-hongkong.myqcloud.com/ui-material/active/moduleA/intel.png'
}
}
} **/
好了到这里我们以经可以顺利的生成文件的 JSON 了,没错它是一个树形结构。
我们只需要把这个 JSON 给写入 js 文件,后续直接从这个文件拿数据就行了。
6.写入数据到 js 文件
const outputStr = `export default ${Ramda.toString(json)};`;
fs.writeFileSync("./assets/data.js", outputStr);
__7.运行脚本 __
node index.js
会得到这样一个 js 文件
export default {
HP: "https://log-1255751956.cos.ap-hongkong.myqcloud.com/ui-material/HP.png",
active: {
IBM: "https://log-1255751956.cos.ap-hongkong.myqcloud.com/ui-material/active/IBM.png",
moduleA: {
intel:
"https://log-1255751956.cos.ap-hongkong.myqcloud.com/ui-material/active/moduleA/intel.png",
},
},
order:
"https://log-1255751956.cos.ap-hongkong.myqcloud.com/ui-material/order.png",
};
8.在小程序里使用
// assets/index.js
import Images from './data';
export { Images }
在 Page 里使用
import { Images } from '../../assets/index';
Page({
data: {
// 这种方式引用有没有很爽
intelIcon: Images.active.moduleA.intel
}
});
可以结合 npm script 或者 gulp 每次在图片更新时,重新执行脚本,更新 data.js
9.完整代码
const COS = require("cos-nodejs-sdk-v5");
const PathParse = require("path-parse");
const Ramda = require("ramda");
const Lodash = require("lodash");
const fs = require("fs");
/** 这里是一些对象存储的配置信息,可以在腾讯云控制台中查看到 */
const COS_SECRETID = "xxxx填你自己的";
const COS_SECRETKEY = "xxxx填你自己的";
const COS_BUCKET = "log-1255751956";
const COS_REGION = "ap-hongkong";
const COS_ENCODING_TYPE = "url";
/** 访问地址 */
const COS_ACCESS_DOMAIN = "https://log-1255751956.cos.ap-hongkong.myqcloud.com";
/** UI素材资源目录 */
const UI_MATERIAL_PATH = "ui-material";
/** 获取 cos 实例 */
const cos = new COS({
SecretId: COS_SECRETID,
SecretKey: COS_SECRETKEY,
});
/** 获取 Bucket 信息
* 我们只获取 ui-material 这个文件夹下的文件
* 所以后面后面统一上传素材文件到这个目录下*/
cos.getBucket(
{
/**指定存储桶 */
Bucket: COS_BUCKET,
/**指定地区 */
Region: COS_REGION,
/**指定文件夹 */
Prefix: `${UI_MATERIAL_PATH}/`,
/**指定编码方式 */
EncodingType: COS_ENCODING_TYPE,
},
(err, data) => {
if (!err) {
const { Contents } = data;
const effectiveFile = filterEffectiveFile(Contents);
const jsonObj = genJson(effectiveFile);
outJsFile(jsonObj);
} else {
console.log("getBuket err", err);
}
}
);
/** 输出 js 文件*/
function outJsFile(json) {
try {
const outputStr = `export default ${Ramda.toString(json)};`;
fs.writeFileSync("./assets/data.js", outputStr);
} catch (e) {
console.log("writeFile file fail", e);
}
}
/** 过滤出有效的 file */
function filterEffectiveFile(Contents) {
/**过滤出 size > 0 的file */
return Contents.filter((_) => _.Size > 0).map((_) => {
const url = `${COS_ACCESS_DOMAIN}/${_.Key}`;
const parsePath = PathParse(_.Key);
const props = [...parsePath.dir.split("/"), parsePath.name];
props.shift();
return {
url,
props,
};
});
}
/** 生成 json 对象 */
function genJson(fileList) {
let objects = {};
fileList.forEach((file) => {
/** 核心方法 可以看 loadsh 文档中的 set 方法 */
Lodash.set(objects, file.props, file.url);
});
return objects;
}