UNPKG

ldjtool

Version:

**ludingji tool**

551 lines (473 loc) 17.5 kB
/** * Created by swellee on 2016/9/18. */ var packInfo = require("./package.json"); var fs = require("fs"); var os = require("os"); var path = require("path"); var prompt = require("prompt"); var sh = require("child_process"); var fork = sh.fork; var userCfgDir = path.join(os.homedir(), ".ldjtool"); var userCfgPath = path.join(userCfgDir, "cfg.json"); var userUIRulePath; var toolCfg = require("./bin/config"); var ruleCfg = require("./bin/rule.json"); var cfg = toolCfg; const uiwatch = require("watch"); var uiwatching = false; var options = { "-h": showHelp, "-c": modConfig, "-d": depackFl, "-a": createPrjAP, "-u": parseUI, "-ux": addUIClazz, "-uw": watchUIdir, "-m": modPrjConfig, "-x": parseSheet, "-b": buildApp, "-r": resCompress, "-p": publishApp }; //--------------------enter------------------- var cmds; var routes = {}; function main(argv) { //initRoutes routes.ui = path.resolve(__dirname, "./routes/ui.js"); //use as fork routes.util = require("./routes/util"); routes.sheet = require("./routes/sheet"); routes.depack = require("./routes/depack"); routes.compress = require("./routes/compressimg"); //是否需要强制升级配置 routes.util.mkdirs(userCfgDir, function() { var uCfg; //用户参数 try { fs.accessSync(userCfgPath, fs.R_OK); uCfg = require(userCfgPath); var match = true; for (var key in cfg) { if (!uCfg.hasOwnProperty(key)) { match = false; uCfg[key] = cfg[key]; //没有的key,先添加上 } else { cfg[key] = uCfg[key]; } } if (!match || uCfg.ver != packInfo.cfgVer) throw new Error("配置格式升级"); } catch (e) { console.log('需要重新配置工具参数。。。'); modConfig(); return; } //ui规则文件 try { userUIRulePath = path.join(uCfg.clientDir, ".ui_rule.json"); fs.accessSync(userUIRulePath, fs.R_OK); var localUiRule = require(userUIRulePath); if (localUiRule.ver != packInfo.uiRuleVer) { //保留local ui rule里的自定义类及包路径 var newUIRule = require(path.resolve(__dirname, "./bin/rule.json")); for (var key in localUiRule.import) { if (!newUIRule.import[key]) { newUIRule.import[key] = localUiRule.import[key]; } } //替换 fs.writeFileSync(userUIRulePath, JSON.stringify(newUIRule), { flag: "w" }); } } catch (e) { //copy ui rule file fs.writeFileSync(userUIRulePath, fs.readFileSync(path.resolve(__dirname, "./bin/rule.json"))); } cmds = argv; //parse args cmds.shift(); //del node cmds.shift(); //del app.js var cmd = cmds.shift(); //command routeCmd(cmd); }); } function routeCmd(cmd) { if (options[cmd]) { options[cmd](); } else { showHelp(); } } function showHelp() { console.log("当前版本:" + packInfo.version + "\n" + "使用说明:\n\ ldjtool -h : 显示该使用说明;\n\ ldjtool -c : 重新配置工具参数;\n\ ldjtool -d [path_to_class_file]: 对目标类文件进行分包处理;\n\ ldjtool -a [laya_engine_src_path]: 在当前目录生成项目使用的.actionScriptProperties; -a后跟的参数为laya引擎的src代码路径,如果未给,则启用输入模式录入\n\ ldjtool -m : 在项目目录下使用此命令,可更改项目的一些配置(如版本号等)\n\ ldjtool -x [xlsx_in_path][xlsx_out_path]: 将配表转换成程序使用的文件,可选参数xlsx_in_path表示要处理的配表文件夹路径(不传则使用ldjtool -c配置的配表目录),\n\ 可选参数xlsx_out_path表示生成的tpl.json的存放目录(不传则使用ldjtool -c配置的放置目录);\n\n\ ldjtool -u [path or file] : 将指定目录下或指定的某个的mornUI生成的xml文件转换成as代码文件,不传路径则使用配置的baseUiFileDir路径;\n\n\ ldjtool -ux : 添加UI解析时的 类名-包名 规则,以适应生成代码时对自定义类映射的支持;\n\n\ ldjtool -uw : 监控UI文件目录的改动,自动重新生成UI代码;\n\n\ ldjtool -b [projectDir] :编译项目;projectDir为项目路径,不传则使用当前路径(如果当前路径不是客户端目录,则会出错)\n\ ldjtool -r [projectDir] :压缩项目目录下bin/h5/assets 下面的图片资源,projectDir为项目路径,不传则使用当前路径\n\ ldjtool -p [projectDir] [ver]:发布项目,projectDir为项目路径,不传则使用当前路径, 参数ver为版本号,不传则使用老的版本号,如果只传一个参数,则此参数当作版本号处理"); } //只会遍历baseUIFileDir之下的一级目录!!!!! function parseUI() { var loc = path.join(cfg.clientDir, "ui/laya/pages/"); if (cmds.length) { loc = cmds.shift(); } loc = path.relative(process.cwd(), loc); fs.access(loc, fs.R_OK | fs.W_OK, function(err) { if (err) { routes.util.err(err); } var uifliles = []; listUIFiles(loc, uifliles); parseUI2As(uifliles); }); } function addUIClazz() { console.log("添加自定义类到UI解析规则:") var schema = { properties: { class: { message: "类名" }, package: { message: "包名" } } }; prompt.start(); prompt.get(schema, function(err, result) { var rule = require(userUIRulePath); result.class = result.class.replace(/[\s\r\n]+/g, ""); result.package = result.package.replace(/[\s\r\n]+/g, ""); if (rule.import.hasOwnProperty(result.class)) { console.log(`发现已有类名${result.class},其映射的包名为${rule.import[result.class]},是否覆盖?(y/n)`); process.stdin.pause(); process.stdin.resume(); process.stdin.on("data", (input) => { if (input) { input = input.toString().replace(/[\s\r\n]+/g, ""); } if (input == "y" || input == "Y") { rule.import[result.class] = result.package; writeRule(rule); } else { console.log(`取消覆盖,类名-包名映射(${result.class}->${result.package})未添加!!`) process.exit(0); } }) } else { rule.import[result.class] = result.package; writeRule(rule); } }) } function writeRule(rule) { fs.writeFile(userUIRulePath, JSON.stringify(rule), function(err) { if (err) { routes.util.err(err); } else { console.log("ok") process.exit(0); } }) } function watchUIdir() { if (uiwatching) return; uiwatching = true; console.log("开始监控UI目录...") var dir = cmds.length ? cmds.pop() : cfg.baseUiFileDir; uiwatch.createMonitor(dir, function(monitor) { monitor.on("created", function(f, stat) { // Handle new files parseUI2As([f]); console.log("已转换UI文件>>", f); }) monitor.on("changed", function(f, curr, prev) { // Handle file changes parseUI2As([f]); console.log("已转换UI文件>>", f); }) monitor.on("removed", function(f, stat) { // Handle removed files }) // monitor.stop(); // Stop watching }) } function listUIFiles(loc, uifliles) { if (fs.statSync(loc).isDirectory()) { try { var files = fs.readdirSync(loc); for (var i = files.length - 1; i >= 0; i--) { var fl = path.resolve(loc, files[i]); listUIFiles(fl, uifliles); } } catch (e) { routes.util.err(e); } } else { uifliles.push(loc); } } function parseUI2As(uifliles) { if (uifliles.length) { var file = uifliles.pop(); try { var p = fork(routes.ui, [file]); p.on("message", function(m) { //干掉子进程 p.kill(); if (m == "ok") { parseUI2As(uifliles); } else { console.log(m); parseUI2As(uifliles); } }) } catch (e) { routes.util.err(e); } } } function parseSheet() { routes.sheet(cfg, cmds); } function resCompress(prjPath) { prjPath = prjPath || cmds.shift(); //项目目录 routes.compress(prjPath); } function buildApp(cb, ignoreSdk) { var prjPath = process.cwd(); if (cmds.length) { var prjPath = cmds.shift(); //项目目录 } var wineVpath = ""; var platform = os.platform(); if (platform != "win32") { if (cfg.layaCmd.indexOf("wine") != -1) { wineVpath = "z:"; //linux use wine,针对laya1.3版本,需要在 exe程序 的参数路径上加上z:虚拟盘符以指向linux 的 root路径,后续如果升级laya.js.exe再观察 } cfg.layaPara += ";windowshow=false" //非windows,不显示gui } var cmd = cfg.layaCmd + ' "' + path.join(wineVpath + prjPath, ".actionScriptProperties") + cfg.layaPara + '"'; sh.exec(cmd, { maxBuffer: 2560 * 2560 }, function(err, stdout, stderr) { if (err) { console.log(err); } else { console.log(stdout); //给分包的js文件添加可调试标记 var packJsPath = path.join(prjPath, "bin", "h5", "js"); fs.readdir(packJsPath, function(err, files) { if (err) { routes.util.err(err); } for (var i in files) { var file = files[i]; var flPath = path.resolve(packJsPath, file); var flName = path.basename(file); var fl = fs.readFileSync(flPath, "utf8"); fl += "//# sourceURL=" + file; fs.appendFileSync(flPath, fl, { flag: "w" }); } }) if (!ignoreSdk) { routes.util.dust("index", { ver: "0.0.1", debug: true, branch: getCurBranchName() }, function(out) { var htmlfile = path.resolve(prjPath, "bin/h5/index.html"); fs.writeFileSync(htmlfile, out); }) } cb && cb(prjPath); } }) } function publishApp() { var ver = ''; //如果 lu -p 后跟参数,则最后一个参数作为版本号处理 if (cmds.length) { ver = cmds.pop(); } buildApp(function(prjPath) { var cpath = ".prjCfg"; //第一次,生成项目信息 try { fs.accessSync(cpath, fs.R_OK); } catch (err) { var pcfg = { name: "鹿鼎记", version: "0.0.1" }; fs.appendFileSync(cpath, JSON.stringify(pcfg)) } var oldCfg = JSON.parse(fs.readFileSync(cpath, "utf8")); //将版本号写入配置 if (ver) { oldCfg.version = ver; fs.writeFileSync(cpath, JSON.stringify(oldCfg)); } else { ver = oldCfg.version; } console.log("压缩代码"); var minTool = require("uglify-js"); var jsFile = path.resolve(prjPath, "bin/h5/main.max.js"); console.log(jsFile); var result = minTool.minify(jsFile, { mangle: { keep_fnames: true //加上这个,才能在压缩后保留正确的类名 } }); fs.writeFileSync(jsFile, result.code); var depJsDir = path.resolve(prjPath, "bin/h5/js"); var depJsfiles = fs.readdirSync(depJsDir); for (var i in depJsfiles) { var file = depJsfiles[i]; var flilePath = path.resolve(depJsDir, file); console.log(flilePath) result = minTool.minify(flilePath, { mangle: { keep_fnames: true } }); fs.writeFileSync(flilePath, result.code); } resCompress(prjPath); console.log("将版本号更新到index.html"); routes.util.dust("index", { ver: ver, debug: false, branch: getCurBranchName() }, function(out) { var htmlfile = path.resolve(prjPath, "bin/h5/index.html"); fs.writeFileSync(htmlfile, out); console.log("创建资源目录带版本号的软链接"); sh.execSync("cd bin/h5; rm res*; ln -s assets res" + ver); }); }, true); } function getCurBranchName() { try { var brs = sh.execSync("git branch"); return brs.toString().match(/\*\s\w+/)[0].replace(/\*\s+/, ""); } catch (e) { return ""; } } function modConfig() { console.log("请根据指引修改配置信息:") var comments = require("./bin/cfgcmts.json"); var schema = { properties: {} }; for (var key in cfg) { if (comments[key]) { schema.properties[key] = { message: comments[key], default: cfg[key] }; } } prompt.start(); prompt.get(schema, function(err, result) { for (var mk in result) { cfg[mk] = pathSep(result[mk]); } cfg.ver = packInfo.cfgVer; //写入config.json fs.appendFile(userCfgPath, JSON.stringify(cfg), { flag: "w" }, function(err) { if (err) { routes.util.err(err); } else { process.exit(0); } }) }) } function depackFl() { if (!cmds.length) { util.err("参数中必需有要分包的类文件的路径"); return; } routes.depack(cmds.pop()); } function createPrjAP() { var engineSrc = "path/to/laya/engine/src"; if (cmds.length) { engineSrc = cmds.shift(); //如果有第二个参数,直接作为engine_src writeAP(engineSrc); } else { //通过用户输入引擎路径 process.stdin.pause(); console.log('请输入laya引擎库路径(如:path/to/laya/src)'); process.stdin.resume(); process.stdin.on("data", function(chunk) { if (chunk) { engineSrc = chunk.toString(); } writeAP(engineSrc); process.stdin.end(); }); } } function writeAP(engineSrc) { engineSrc = pathSep(engineSrc); if (engineSrc.charAt(engineSrc.length - 1) == "/") { engineSrc = engineSrc.substr(0, engineSrc.length - 1); } routes.util.dust("ap", { engineSrc: engineSrc }, function(out) { fs.appendFileSync(".actionScriptProperties", out, { flag: "w" }); }) } function modPrjConfig() { var cwd = process.cwd(); console.log(`当前路径为${cwd},是否要修改“版本号”“背景”等项目配置,y/n?`); process.stdin.resume(); process.stdin.once("data", function(chunk) { if (chunk) { chunk = pathSep(chunk.toString()); } if (chunk != "y" && chunk != "Y") { console.log("已取消"); process.exit(); } else { doModPrjCfg(); } }); } function doModPrjCfg() { var cpath = ".prjCfg"; //第一次,生成项目信息 try { fs.accessSync(cpath, fs.R_OK); } catch (err) { var pcfg = { version: "test" }; fs.appendFileSync(cpath, JSON.stringify(pcfg)) } var oldCfg = JSON.parse(fs.readFileSync(cpath, "utf8")); var schema = { properties: {} }; for (key in oldCfg) { schema.properties[key] = { message: key, default: oldCfg[key] } } prompt.start(); prompt.get(schema, function(err, result) { for (var mk in result) { oldCfg[mk] = result[mk] } fs.writeFile(cpath, JSON.stringify(oldCfg), function(err) { if (err) { routes.util.err(err); } else { process.exit(0); } }) }) } function pathSep(p) { return p.replace(/\\+/g, "/").replace(/[\r\n\s]+$/, ""); } module.exports = main;