感兴趣的大佬可以一起交流一下,共同学习共同进步(⊙o⊙)…
此工具的出生起因:
项目需要对接很多渠道意味着包体在不断变大,而且对应渠道的SDK文件在对应渠道中才有用,相当于说包体里会有很多无用的代码。
缺点:
需要手动将SDK目录下不是SDK的文件存到工具里以便打包的时候跳过这些文件。
/**不需要参与修改的文件夹名称需要往后加 */
var delectArr = [
"ISDK.ts",
"SDK.ts",
"SDKSource.ts"
];
如果修改模板文件(往模板文件里加方法)需要在工具中的模板文件里加一下。
//所有SDK需要实现的方法接口 方便统一管理
interface ISDK {
init(isAgain: boolean): void
testFun?(isAgain: boolean): void
}
//上文提到的SDK模板文件需要和接口文件保持一致避免报错
//还有就是可以方便写入非本渠道的SDK文件
implements ISDK {
init(isAgain: boolean): void {}
testFun?(isAgain: boolean): void{}
}
整个工具的目录结构
backUpSDK----SDK最开始备份防止工具出错
buildFile----------剔除不需要的渠道后编译好的文件按渠道区分
creatSDKFiles--不参与打包渠道的空方法文件
Tools--------------js和配置文件存放目录
delete.cmd------先清空之前的文件重新开始编译
Tool.cmd---------直接编译
清空上次编译保存的文件及渠道记录
删除buildFile目录下所有文件夹及文件
清空上次存储哪些渠道打包完成了
const fs = require('fs');
const path = require('path');
var handleName = "./Tools/buildName.txt";//已经处理完的渠道名称
var rmdirSync = (function () {
function iterator(url, dirs) {
var stat = fs.statSync(url);
if (stat.isDirectory()) {
dirs.unshift(url);//收集目录
inner(url, dirs);
} else if (stat.isFile()) {
fs.unlinkSync(url);//直接删除文件
}
}
function inner(path, dirs) {
var arr = fs.readdirSync(path);
for (var i = 0, el; el = arr[i++];) {
iterator(path + "/" + el, dirs);
}
}
return function (dir, cb) {
cb = cb || function () { };
var dirs = [];
try {
iterator(dir, dirs);
for (var i = 0, el; el = dirs[i++];) {
fs.rmdirSync(el);//一次性删除所有收集到的目录
}
cb()
} catch (e) {//如果文件或目录本来就不存在,fs.statSync会报错,不过我们还是当成没有异常发生
e.code === "ENOENT" ? cb() : cb(e);
}
}
})();
let fileDir = path.resolve(__dirname, '../buildFile/')
// 异步读取目录内容
fs.readdir(fileDir, { encoding: 'utf8' }, (err, files) => {
if (err) throw err;
console.log('读取的目录内容:', files);
for (let i in files) {
rmdirSync(fileDir + "/" + files[i] + "/", function (e) {
console.log("删除目录以及子目录成功")
})
}
})
var writeFile = function () {
//创建文件并写入
fs.writeFile(handleName, "", function (err) {
if (err) throw err;
console.log("文件", handleName, "写入完成");
});
}
writeFile();
该工具大致思路主要分为7步来完成
首先创建一些全局变量
var content = "";//模板文件的内容
var backUpRoute = "";//需要备份到的路径
var targetBackUpRoute = "";//SDK的路径
var channelRoute = "./Tools/channelName.txt";//本次选择的渠道名称
var handleName = "./Tools/buildName.txt";//已经处理完的渠道名称
/**所有参与处理SDK渠道文件名 */
var creatNameArr = [];
/**已经处理完的渠道名称 */
var buildName = [];
/**待处理的所有渠道文件名 */
var waitbuildName = [];
var modelRoute = "./Tools/SDKModel.txt";//模板文件路径
var creatRoute = "./creatSDKFiles/";//新创建的SDK文件路径
var buildRoute = "./buildFile/";//编译完文件在工具里的移动目录
var fileName = "";//检测编译是否完成的文件名
var moveFileName = "";//需要移动的编译文件名称
var moveRoute = "";//编译好的文件在项目里的目录
1.先将SDK文件夹做好备份并删除上次创建的SDK文件
通过读取指定目录下的文件来复制到备份目录
读取到上次创建的空方法SDK文件并删除执行完毕后执行第2步。
fs.readdir(targetBackUpRoute, function (err, files) {
console.log(targetBackUpRoute);
(function iterator(i) {
if (i == files.length) return;
fs.stat(path.join(targetBackUpRoute, files[i]), function (err, data) {
if (data.isFile()) {
copyFile(files[i], i == files.length - 1);
}
iterator(i + 1);
});
})(0);
});
var copyFile = function (list, isOver) {
fs.copyFile(targetBackUpRoute + list, backUpRoute + list, function (err) {
if (err) console.log('something wrong was happened: ', err)
// else console.log('文件' + list + '复制成功');
if (isOver) {
// console.log("SDK所有文件备份完成");
console.log("SDK所有文件备份完成,开始删除上次创建的SDK文件");
delcetConfig(creatRoute);
}
})
}
2.读取到需要修改的SDK文件并新建只有空方法的对应文件(根据模板文件写入)
/**开始将新建的SDK文件替换项目中的文件 */
var creatConfig = function () {
console.log("上次创建的SDK文件删除成功,开始将新建的SDK文件替换项目中的文件");
var modelRead = false;
var buildRead = false;
fs.readFile(modelRoute, 'utf-8', function (err, data) {
if (err) throw err;
content = data;
modelRead = true;
if (modelRead && buildRead) readdir();
});
//读取已经编译完成的渠道名称
fs.readFile(handleName, 'utf-8', function (err, data) {
if (err) throw err;
var name = (data + "").split("&");
buildName = name;
buildRead = true;
console.log("已经编译完成的渠道名称", buildName);
if (modelRead && buildRead) readdir();
});
var readdir = function () {
//先读取到需要屏蔽的SDK文件
fs.readdir(targetBackUpRoute, function (err, files) {
(function iterator(i) {
if (i == files.length) {
question(creatNameArr);
return;
}
fs.stat(path.join(targetBackUpRoute, files[i]), function (err, data) {
if (data.isFile() && delectArr.indexOf(files[i]) == -1) {
creatNameArr.push(files[i]);
}
iterator(i + 1);
});
})(0);
});
}
}
/**
* 请求用户输入
*/
var question = function () {
let selectStr = "未处理的SDK渠道ID:\n";
for (let i = 0; i < creatNameArr.length; ++i) {
if (buildName.indexOf(creatNameArr[i]) == -1) {
selectStr += "[" + (i + 1) + "] " + creatNameArr[i] + "\n";
waitbuildName.push(creatNameArr[i]);
}
}
console.log(selectStr);
if (waitbuildName.length <= 0) {
console.log("\033[46;31mERROR\033[40;31m 未获取到待处理的渠道请检查是否已经处理完成\033[0m");
return;
}
console.log('本次处理的渠道为\033[40;32m', waitbuildName[0] + '\033[0m');
for (let i = 0; i < creatNameArr.length; ++i) {
var fileName = creatNameArr[i].split(".")[0];
var _data = "class " + fileName + " " + content;
if (waitbuildName[0] == creatNameArr[i]) {
console.log('跳过用户输入的渠道文件', '\033[40;32m', creatNameArr[i], "\033[0m");
writeFile(channelRoute, "", fileName, false);
appendFile(creatNameArr[i] + "&", i == creatNameArr.length - 1);
continue;
}
writeFile(creatRoute, creatNameArr[i], _data, i == creatNameArr.length - 1);
}
}
/**
* 创建并写入新的SDK文件
* @param {*} list 文件名字
* @param {*} tipFile 用户选择的渠道名字 不需要处理
*/
var writeFile = function (path, list, _data, isOver) {
//创建文件并写入
fs.writeFile(path + list, _data, function (err) {
if (err) throw err;
// var name = list;
// if (list == '') name = path;
// console.log("文件", name, "写入完成");
if (isOver) copyConfig();
});
}
/**向文件追加内容
* @param {*} _data 写入的内容
* @param {*} isOver 是否结束
*/
var appendFile = function (_data, isOver) {
fs.appendFile(handleName, _data, (error) => {
if (error) return console.log("追加文件失败" + error.message);
// console.log("处理渠道追加成功");
if (isOver) copyConfig();
});
}
3.新文件替换旧文件并删除项目里的编译文件方便以后检测编译是否完成。
/**将新建的SDK文件复制到项目中SDK目录下 */
var copyConfig = function () {
console.log("开始将新建的SDK文件复制到项目中SDK目录下");
fs.readdir(creatRoute, function (err, files) {
(function iterator(i) {
if (i == files.length) return;
fs.stat(path.join(creatRoute, files[i]), function (err, data) {
if (data.isFile()) {
copyFile(files[i], i == files.length - 1);
}
iterator(i + 1);
});
})(0);
});
//复制需要屏蔽的SDK文件
var copyFile = function (list, isOver) {
fs.copyFile(creatRoute + list, targetBackUpRoute + list, function (err) {
if (err) console.log('something wrong was happened: ', err)
// else console.log('文件' + list + '复制成功');
if (isOver) {
console.log('文件复制完成----执行删除Core.js文件');
delcetConfig(moveRoute);
}
})
}
}
4.使用计时器检测需要的文件是否编译完成,完成后压缩文件
/**
* 将编译好的文件压缩
*/
var compressConfig = function (type) {
//首先检测文件是否编译完成
var timmerCore = function () {
var timmerCore = setInterval(() => {
console.log("开始检测Core.js文件是否编译完成");
readdir(fileName, timmerCore, "Core.js");
}, 1000);
}
var timmerCoreMain = function () {
var timmerCoreMain = setInterval(() => {
console.log("开始检测Core.main.js文件是否压缩完成");
readdir(moveFileName, timmerCoreMain, "Core.main.js");
}, 500);
}
if (type == "build") timmerCore();
else timmerCoreMain();
}
/**
* 检测文件是否存在
* @param {*} name 文件名
* @param {*} timmer 计时器索引
*/
var readdir = function (name, timmer, logName) {
fs.readdir(moveRoute, function (err, files) {
(function iterator(i) {
if (i == files.length) return;
fs.stat(path.join(moveRoute, files[i]), function (err, data) {
if (data.isFile() && files[i] == name) {
clearInterval(timmer);
console.log("\033[40;32" + logName + "文件编译完成\033[0m");
if (name == moveFileName) moveConfig();
}
iterator(i + 1);
});
})(0);
});
}
5.将编译好的文件压缩并按渠道移动到对应文件夹中
/**
* 将编译好的文件移动到对应位置
*/
var moveConfig = function () {
console.log("开始将编译好的文件移动到对应位置");
fs.access(channelRoute, (err) => {
if (err) return console.log("\033[46;31mERROR\033[40;31m 本次处理的SDK渠道不存在不继续执行\033[0m");
else readFile();
});
var readFile = function () {
fs.readFile(channelRoute, 'utf-8', function (err, data) {
if (err) throw err;
delectFile(channelRoute, "");//删除上次储存的渠道文件
console.log("本次处理的SDK渠道为:\033[40;32m", data, "\033[0m");
if (!data) return console.log("\033[46;31mERROR\033[40;31m 本次处理的SDK渠道不存在不继续执行\033[0m");
mkdirFun(data);//新建对应渠道的文件夹
});
}
var mkdirFun = function (data) {
let route = buildRoute + data + "/";
if (!fs.existsSync(route)) {
fs.mkdir(route, function (err) {
if (err) return console.error(err);
console.log("目录创建成功。", route);
readdir(route);
});
} else {
console.log("目录", route, "存在不重新创建");
readdir(route);
}
}
var readdir = function (route) {
//读取build好的文件
fs.readdir(moveRoute, function (err, files) {
(function iterator(i) {
if (i == files.length) {
console.log("\033[46;31mERROR SATR");
console.log("\033[46;31mERROR \033[40;31m libs目录下没有找到目标文件");
console.log("\033[46;31mERROR \033[40;31m 读取build好的屏蔽文件可能出现错误请检查");
console.log("\033[46;31mERROR OVER", "\033[0m");
return;
}
fs.stat(path.join(moveRoute, files[i]), function (err, data) {
if (data.isFile() && files[i] == moveFileName) {
copyFile(files[i], route, i == files.length - 1);
return;
}
iterator(i + 1);
});
})(0);
});
}
//复制build好的屏蔽文件
var copyFile = function (list, route, isOver) {
fs.copyFile(moveRoute + list, route + list, function (err) {
// if (!err) console.log('文件' + list + '复制成功');
// else console.log('移动编译文件发生错误请检查: ', err);
if (err) console.log('移动编译文件发生错误请检查: ', err);
if (isOver) moveBackUp();
})
}
}
6.将备份的SDK文件移动到SDK目录下
/**将备份的文件复制到项目中 */
var moveBackUp = function () {
console.log("开始将备份的文件复制到项目中");
fs.readdir(backUpRoute, function (err, files) {
(function iterator(i) {
if (i == files.length) return;
fs.stat(path.join(backUpRoute, files[i]), function (err, data) {
if (data.isFile()) copyFile(files[i], i == files.length - 1);
iterator(i + 1);
});
})(0);
});
var copyFile = function (list, isOver) {
fs.copyFile(backUpRoute + list, targetBackUpRoute + list, function (err) {
// if (!err) console.log('文件' + list + '复制成功');
// else console.log('移动备份文件发生错误请检查: ', err);
if (err) console.log('移动备份文件发生错误请检查: ', err);
if (isOver) execFile();
})
}
}
7.判断是否有未处理的渠道,有的话再次执行该工具
/**检测是否可以继续执行 */
var execFile = function () {
var modelRead = false;
var buildRead = false;
fs.readFile(modelRoute, 'utf-8', function (err, data) {
if (err) throw err;
content = data;
modelRead = true;
if (modelRead && buildRead) readdir();
});
//读取已经编译完成的渠道名称
fs.readFile(handleName, 'utf-8', function (err, data) {
if (err) throw err;
var name = (data + "").split("&");
buildName = name;
buildRead = true;
console.log("已经编译完成的渠道名称", buildName);
if (modelRead && buildRead) readdir();
});
var readdir = function () {
//先读取到需要屏蔽的SDK文件
fs.readdir(targetBackUpRoute, function (err, files) {
(function iterator(i) {
if (i == files.length) {
question(creatNameArr);
return;
}
fs.stat(path.join(targetBackUpRoute, files[i]), function (err, data) {
if (data.isFile() && delectArr.indexOf(files[i]) == -1) {
creatNameArr.push(files[i]);
}
iterator(i + 1);
});
})(0);
});
}
var question = function () {
for (let i = 0; i < creatNameArr.length; ++i) {
if (buildName.indexOf(creatNameArr[i]) == -1) {
waitbuildName.push(creatNameArr[i]);
}
}
if (waitbuildName.length <= 0) {
console.log("\033[40;32m所有渠道已经处理完成\033[0m");
return;
}
console.log("\033[40;32m检测到还有未处理的渠道继续执行该工具\033[0m");
child_process();
}
var child_process = function () {
var child_process = require("child_process");
child_process.execFile("E:/LayaProject/publish/handleSDK/Tools/loop.cmd", function (error, stdout, stderr) {
if (error !== null) console.log("exec error" + error);
})
}
}