publish.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // v1.6.5
  2. //是否使用IDE自带的node环境和插件,设置false后,则使用自己环境(使用命令行方式执行)
  3. const useIDENode = process.argv[0].indexOf("LayaAir") > -1 ? true : false;
  4. const useCMDNode = process.argv[1].indexOf("layaair2-cmd") > -1 ? true : false;
  5. function useOtherNode(){
  6. return useIDENode||useCMDNode;
  7. }
  8. //获取Node插件和工作路径
  9. let ideModuleDir = useOtherNode() ? process.argv[1].replace("gulp\\bin\\gulp.js", "").replace("gulp/bin/gulp.js", "") : "";
  10. let workSpaceDir = useOtherNode() ? process.argv[2].replace("--gulpfile=", "").replace("\\.laya\\publish.js", "").replace("/.laya/publish.js", "") + "/" : "./../";
  11. //引用插件模块
  12. const gulp = require(ideModuleDir + "gulp");
  13. const fs = require("fs");
  14. const path = require("path");
  15. const uglify = require(ideModuleDir + 'gulp-uglify-es').default;
  16. const jsonminify = require(ideModuleDir + "gulp-jsonminify");
  17. const image = require(ideModuleDir + "gulp-image");
  18. const rev = require(ideModuleDir + "gulp-rev");
  19. const revdel = require(ideModuleDir + "gulp-rev-delete-original");
  20. const revCollector = require(ideModuleDir + 'gulp-rev-collector');
  21. const del = require(ideModuleDir + "del");
  22. const requireDir = require(ideModuleDir + 'require-dir');
  23. const babel = require(ideModuleDir + 'gulp-babel');
  24. global.ideModuleDir = ideModuleDir;
  25. global.workSpaceDir = workSpaceDir;
  26. // 结合compile.js使用
  27. global.publish = true;
  28. const fileList = ["compile.js", "publish_xmgame.js", "publish_oppogame.js", "publish_vivogame.js", "publish_alipaygame.js", "publish_wxgame.js", "publish_bdgame.js", "publish_qqgame.js"];
  29. requireDir('./', {
  30. filter: function (fullPath) {
  31. // 只用到了compile.js和publish.js
  32. if (fileList.includes(path.basename(fullPath))) {
  33. return true;
  34. } else {
  35. return false;
  36. }
  37. }
  38. });
  39. const QUICKGAMELIST = ["xmgame", "oppogame", "vivogame"];
  40. // 清理临时文件夹,加载配置
  41. let config,
  42. releaseDir,
  43. binPath,
  44. platform = "web",
  45. isOpendataProj = false,
  46. platformCopyTask = [],// 平台脚本拷贝任务
  47. platformTask = []; // 平台需要执行的任务
  48. //任务对照列表
  49. const copyTasks = {
  50. "biligame": "copyPlatformFile_Bili",
  51. "Alipaygame": "copyPlatformFile_Alipay",
  52. "vivogame": "copyPlatformFile_VIVO",
  53. "oppogame": "preCreate_OPPO",
  54. "xmgame": "copyPlatformFile_XM",
  55. "bdgame": "copyPlatformFile_BD",
  56. "qqgame": "copyPlatformFile_QQ",
  57. "wxgame": "copyPlatformFile_WX",
  58. "web": "copyLibsJsFile"
  59. }
  60. const tasks = {
  61. "biligame": "buildBiliProj",
  62. "Alipaygame": "buildAlipayProj",
  63. "vivogame": "buildVivoProj",
  64. "oppogame": "buildOPPOProj",
  65. "xmgame": "buildXiaomiProj",
  66. "bdgame": "buildBDProj",
  67. "qqgame": "buildQQProj",
  68. "wxgame": "buildWXProj",
  69. "web": "packfile"
  70. }
  71. if (!useOtherNode() && process.argv.length > 5 && process.argv[4] == "--config") {
  72. platform = process.argv[5].replace(".json", "");
  73. }
  74. if (useOtherNode() && process.argv.length >= 4 && process.argv[3].startsWith("--config") && process.argv[3].endsWith(".json")) {
  75. platform = process.argv[3].match(/(\w+).json/)[1];
  76. platformCopyTask.push(copyTasks[platform]);
  77. platformTask.push(tasks[platform]);
  78. }
  79. gulp.task("loadConfig", function () {
  80. let _path;
  81. if (!useOtherNode()) {
  82. _path = platform + ".json";
  83. releaseDir = "../release/" + platform;
  84. binPath = "../bin/";
  85. }
  86. if (useOtherNode()) {
  87. _path = path.join(workSpaceDir, ".laya", `${platform}.json`);
  88. releaseDir = path.join(workSpaceDir, "release", platform).replace(/\\/g, "/");
  89. binPath = path.join(workSpaceDir, "bin").replace(/\\/g, "/");
  90. }
  91. global.platform = platform;
  92. let file = fs.readFileSync(_path, "utf-8");
  93. if (file) {
  94. if (QUICKGAMELIST.includes(platform)) {
  95. file = file.replace(/\$basePath/g, releaseDir + "/temprelease");
  96. } else {
  97. file = file.replace(/\$basePath/g, releaseDir);
  98. }
  99. config = JSON.parse(file);
  100. global.config = config;
  101. }
  102. // 是否是开放域项目
  103. let projInfoPath = path.join(workSpaceDir, path.basename(workSpaceDir) + ".laya");
  104. let isExist = fs.existsSync(projInfoPath);
  105. if (isExist) {
  106. try {
  107. let projInfo = fs.readFileSync(projInfoPath, "utf8");
  108. projInfo = projInfo && JSON.parse(projInfo);
  109. isOpendataProj = projInfo.layaProType === 12;
  110. } catch (e) {}
  111. }
  112. });
  113. // 清理release文件夹
  114. gulp.task("clearReleaseDir", ["compile"], function (cb) {
  115. if (config.clearReleaseDir) {
  116. let delList = [`${releaseDir}/**`, releaseDir + "_pack"];
  117. if (config.packfileTargetValue) {
  118. delList.push(config.packfileTargetValue);
  119. }
  120. // 小米快游戏,使用即存的项目,删掉Laya工程文件,保留小米环境项目文件
  121. if (platform === "xmgame") {
  122. let xmProjSrc = path.join(releaseDir, config.xmInfo.projName);
  123. // 不要删掉manifest.json/main.js文件
  124. // 这里不是node-glob语法,详见: https://github.com/sindresorhus/del
  125. delList = [`${xmProjSrc}/**`, `!${xmProjSrc}`, `!${xmProjSrc}/node_modules/**`, `!${xmProjSrc}/sign/**`, `!${xmProjSrc}/{babel.config.js,main.js,manifest.json,package.json,package-lock.json}`];
  126. } else if (platform === "oppogame") {
  127. let oppoProjSrc = path.join(releaseDir, config.oppoInfo.projName);
  128. delList = [`${oppoProjSrc}/**`, `!${oppoProjSrc}`, `!${oppoProjSrc}/dist/**`, `!${oppoProjSrc}/{manifest.json}`];
  129. } else if (platform === "vivogame") {
  130. let vvProj = path.join(releaseDir, config.vivoInfo.projName);
  131. let vvProjSrc = path.join(vvProj, "src");
  132. // 不要删掉manifest.json/main.js文件
  133. // 这里不是node-glob语法,详见: https://github.com/sindresorhus/del
  134. delList = [`${vvProjSrc}/**`, `!${vvProjSrc}`, `!${vvProjSrc}/sign/**`, `!${vvProjSrc}/{game.js,manifest.json}`];
  135. delList = delList.concat(`${vvProj}/engine/**`, `${vvProj}/config/**`);
  136. }
  137. // 保留平台配置文件
  138. if (config.keepPlatformFile) {
  139. if (platform === "wxgame" || platform === "qqgame") {
  140. delList = delList.concat(`!${releaseDir}`, `!${releaseDir}/{game.js,game.json,project.config.json,weapp-adapter.js}`);
  141. } else if (platform === "bdgame") {
  142. delList = delList.concat(`!${releaseDir}`, `!${releaseDir}/{game.js,game.json,project.swan.json,swan-game-adapter.js}`);
  143. } else if (platform === "Alipaygame") {
  144. delList = delList.concat(`!${releaseDir}`, `!${releaseDir}/{game.js,game.json,my-adapter.js}`);
  145. }
  146. }
  147. del(delList, { force: true }).then(paths => {
  148. cb();
  149. });
  150. } else cb();
  151. });
  152. // copy bin文件到release文件夹
  153. gulp.task("copyFile", ["clearReleaseDir"], function () {
  154. let baseCopyFilter = [`${workSpaceDir}/bin/**/*.*`, `!${workSpaceDir}/bin/indexmodule.html`, `!${workSpaceDir}/bin/import/*.*`];
  155. // 只拷贝index.js中引用的类库
  156. if (config.onlyIndexJS) {
  157. baseCopyFilter = baseCopyFilter.concat(`!${workSpaceDir}/bin/libs/*.*`);
  158. }
  159. if (platform === "wxgame" && isOpendataProj) { // 开放域项目微信发布,仅拷贝用到的文件
  160. config.copyFilesFilter = [`${workSpaceDir}/bin/js/bundle.js`, `${workSpaceDir}/bin/index.js`, `${workSpaceDir}/bin/game.js`];
  161. if (config.projectType !== "as") { // 开放域精简类库
  162. config.copyFilesFilter.push(`${workSpaceDir}/bin/libs/laya.opendata.js`);
  163. }
  164. } else if (platform === "wxgame") { // 微信项目,不拷贝index.html,不拷贝百度bin目录中的文件
  165. config.copyFilesFilter = baseCopyFilter.concat([`!${workSpaceDir}/bin/index.html`, `!${workSpaceDir}/bin/{project.swan.json,swan-game-adapter.js}`]);
  166. } else if (platform === "bdgame") { // 百度项目,不拷贝index.html,不拷贝微信bin目录中的文件
  167. config.copyFilesFilter = baseCopyFilter.concat([`!${workSpaceDir}/bin/index.html`, `!${workSpaceDir}/bin/{project.config.json,weapp-adapter.js}`]);
  168. } else { // web|QQ项目|bili|快游戏,不拷贝微信、百度在bin目录中的文件
  169. config.copyFilesFilter = baseCopyFilter.concat([`!${workSpaceDir}/bin/{game.js,game.json,project.config.json,weapp-adapter.js,project.swan.json,swan-game-adapter.js}`]);
  170. }
  171. // bili/alipay/qq,不拷贝index.html
  172. if (["biligame", "Alipaygame", "qqgame"].includes(platform)) {
  173. config.copyFilesFilter = config.copyFilesFilter.concat([`!${workSpaceDir}/bin/index.html`]);
  174. }
  175. // 快游戏,需要新建一个快游戏项目,拷贝的只是项目的一部分,将文件先拷贝到文件夹的临时目录中去
  176. if (QUICKGAMELIST.includes(platform)) {
  177. config.copyFilesFilter = config.copyFilesFilter.concat([`!${workSpaceDir}/bin/index.html`]);
  178. releaseDir = global.tempReleaseDir = path.join(releaseDir, "temprelease");
  179. }
  180. if (config.exclude) { // 排除文件
  181. config.excludeFilter.forEach(function(item, index, list) {
  182. releaseDir = releaseDir.replace(/\\/g, "/");
  183. config.excludeFilter[index] = item.replace(releaseDir, binPath);
  184. });
  185. config.copyFilesFilter = config.copyFilesFilter.concat(config.excludeFilter);
  186. }
  187. global.releaseDir = releaseDir;
  188. var stream = gulp.src(config.copyFilesFilter, { base: `${workSpaceDir}/bin` });
  189. return stream.pipe(gulp.dest(releaseDir));
  190. });
  191. // copy libs中的js文件到release文件夹
  192. gulp.task("copyLibsJsFile", ["copyFile"], function () {
  193. if (!config.onlyIndexJS) {
  194. return;
  195. }
  196. if (platform === "wxgame" && isOpendataProj) { // 开放域项目微信发布,拷贝文件时已经拷贝类库文件了
  197. return;
  198. }
  199. // 开放域项目,as语言,没有libs目录,mac系统报错
  200. let libs = path.join(workSpaceDir, "bin", "libs");
  201. if (!fs.existsSync(libs)) {
  202. return;
  203. }
  204. // 分析index.js
  205. let indexJSPath = path.join(workSpaceDir, "bin", "index.js");
  206. let indexJsContent = fs.readFileSync(indexJSPath, "utf8");
  207. let libsList = indexJsContent.match(/loadLib\(['"]libs\/[\w-./]+\.(js|wasm)['"]\)/g);
  208. if (!libsList) {
  209. libsList = [];
  210. }
  211. let
  212. item,
  213. libsName = "",
  214. libsStr = "";
  215. for (let i = 0, len = libsList.length; i < len; i++) {
  216. item = libsList[i];
  217. libsName = item.match(/loadLib\(['"]libs\/([\w-./]+\.(js|wasm))['"]\)/);
  218. libsStr += libsStr ? `,${libsName[1]}` : libsName[1];
  219. }
  220. // 发布web项目,如果使用了physics3D,默认拷贝runtime
  221. if (platform === "web" && libsStr.includes("laya.physics3D")) {
  222. libsStr += ',laya.physics3D.runtime.js';
  223. }
  224. let copyLibsList = [`${workSpaceDir}/bin/libs/{${libsStr}}`];
  225. if (!libsStr.includes(",")) {
  226. copyLibsList = [`${workSpaceDir}/bin/libs/${libsStr}`];
  227. }
  228. var stream = gulp.src(copyLibsList, { base: `${workSpaceDir}/bin` });
  229. return stream.pipe(gulp.dest(releaseDir));
  230. });
  231. // es6toes5
  232. gulp.task("es6toes5", platformCopyTask, function() {
  233. if (config.es6toes5) {
  234. return gulp.src(`${releaseDir}/**/*.js`, { base: releaseDir })
  235. .pipe(babel({
  236. presets: ['@babel/env'],
  237. compact: true
  238. }))
  239. .pipe(gulp.dest(releaseDir));
  240. }
  241. })
  242. // 压缩json
  243. gulp.task("compressJson", ["es6toes5"], function () {
  244. if (config.compressJson) {
  245. return gulp.src(config.compressJsonFilter, { base: releaseDir })
  246. .pipe(jsonminify())
  247. .pipe(gulp.dest(releaseDir));
  248. }
  249. });
  250. // 压缩js
  251. gulp.task("compressJs", ["compressJson"], function () {
  252. if (config.compressJs) {
  253. return gulp.src(config.compressJsFilter, { base: releaseDir })
  254. .pipe(uglify({
  255. mangle: {
  256. keep_fnames:true
  257. }
  258. }))
  259. .on('error', function (err) {
  260. console.warn(err.toString());
  261. })
  262. .pipe(gulp.dest(releaseDir));
  263. }
  264. });
  265. // 压缩png,jpg
  266. gulp.task("compressImage", ["compressJs"], function () {
  267. if (config.compressImage) {
  268. return gulp.src(config.compressImageFilter, { base: releaseDir })
  269. .pipe(image({
  270. pngquant: true, //PNG优化工具
  271. optipng: false, //PNG优化工具
  272. zopflipng: true, //PNG优化工具
  273. jpegRecompress: false, //jpg优化工具
  274. mozjpeg: true, //jpg优化工具
  275. guetzli: false, //jpg优化工具
  276. gifsicle: false, //gif优化工具
  277. svgo: false, //SVG优化工具
  278. concurrent: 10, //并发线程数
  279. quiet: true //是否是静默方式
  280. // optipng: ['-i 1', '-strip all', '-fix', '-o7', '-force'],
  281. // pngquant: ['--speed=1', '--force', 256],
  282. // zopflipng: ['-y', '--lossy_8bit', '--lossy_transparent'],
  283. // jpegRecompress: ['--strip', '--quality', 'medium', '--min', 40, '--max', 80],
  284. // mozjpeg: ['-optimize', '-progressive'],
  285. // guetzli: ['--quality', 85]
  286. }))
  287. .pipe(gulp.dest(releaseDir));
  288. }
  289. });
  290. // 生成版本管理信息
  291. gulp.task("version1", ["compressImage"], function () {
  292. if (config.version) {
  293. return gulp.src(config.versionFilter, { base: releaseDir })
  294. .pipe(rev())
  295. .pipe(gulp.dest(releaseDir))
  296. .pipe(revdel())
  297. .pipe(rev.manifest("version.json"))
  298. .pipe(gulp.dest(releaseDir));
  299. }
  300. });
  301. // 替换index.js里面的变化的文件名
  302. gulp.task("version2", ["version1"], function () {
  303. if (config.version) {
  304. //替换index.html和index.js里面的文件名称
  305. let htmlPath = releaseDir + "/index.html";
  306. let versionPath = releaseDir + "/version.json";
  307. let gameJSPath = releaseDir + "/game.js";
  308. let mainJSPath = releaseDir + "/main.js";
  309. let indexJSPath;
  310. let versionCon = fs.readFileSync(versionPath, "utf8");
  311. versionCon = JSON.parse(versionCon);
  312. let indexJsStr = (versionCon && versionCon["index.js"]) ? versionCon["index.js"] : "index.js";
  313. indexJSPath = releaseDir + "/" + indexJsStr;
  314. // 替换config.packfileFullValue中的路径
  315. let packfileStr = JSON.stringify(config.packfileFullValue).replace(/\\\\/g, "/");
  316. let tempPackfile = `${workSpaceDir}/.laya/configTemp.json`;
  317. fs.writeFileSync(tempPackfile, packfileStr, "utf8");
  318. let srcList = [versionPath, indexJSPath, tempPackfile];
  319. if (fs.existsSync(htmlPath)) {
  320. srcList.push(htmlPath);
  321. }
  322. if (fs.existsSync(gameJSPath)) {
  323. srcList.push(gameJSPath);
  324. }
  325. if (fs.existsSync(mainJSPath)) {
  326. srcList.push(mainJSPath);
  327. }
  328. return gulp.src(srcList)
  329. .pipe(revCollector())
  330. .pipe(gulp.dest(releaseDir));
  331. }
  332. });
  333. // 筛选4M包
  334. gulp.task("packfile", ["version2"], function() {
  335. if (config.version) {
  336. // 从release目录取得带有版本号的目录
  337. let tempPackfile = `${workSpaceDir}/.laya/configTemp.json`;
  338. let releasePackfile = `${releaseDir}/configTemp.json`;
  339. let packfileStr = fs.readFileSync(releasePackfile, "utf8");
  340. config.packfileFullValue = JSON.parse(packfileStr);
  341. // 删掉临时目录
  342. fs.unlinkSync(tempPackfile);
  343. fs.unlinkSync(releasePackfile);
  344. }
  345. if (config.packfile) { // 提取本地包(文件列表形式)
  346. return gulp.src(config.packfileFullValue, { base: releaseDir })
  347. .pipe(gulp.dest(config.packfileTargetValue || releaseDir + "_pack"));
  348. }
  349. });
  350. // 起始任务
  351. gulp.task("publish", platformTask , function () {
  352. console.log("All tasks completed!");
  353. });