publish_wxgame.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. // v1.4.0
  2. // publish 2.x 也是用这个文件,需要做兼容
  3. let isPublish2 = process.argv[2].includes("publish_wxgame.js") && process.argv[3].includes("--evn=publish2");
  4. // 获取Node插件和工作路径
  5. let ideModuleDir, workSpaceDir;
  6. if (isPublish2) {
  7. //是否使用IDE自带的node环境和插件,设置false后,则使用自己环境(使用命令行方式执行)
  8. const useIDENode = process.argv[0].indexOf("LayaAir") > -1 ? true : false;
  9. ideModuleDir = useIDENode ? process.argv[1].replace("gulp\\bin\\gulp.js", "").replace("gulp/bin/gulp.js", "") : "";
  10. workSpaceDir = useIDENode ? process.argv[2].replace("--gulpfile=", "").replace("\\.laya\\publish_wxgame.js", "").replace("/.laya/publish_wxgame.js", "") + "/" : "./../";
  11. } else {
  12. ideModuleDir = global.ideModuleDir;
  13. workSpaceDir = global.workSpaceDir;
  14. }
  15. //引用插件模块
  16. const gulp = require(ideModuleDir + "gulp");
  17. const fs = require("fs");
  18. const path = require("path");
  19. const crypto = require("crypto");
  20. const del = require(ideModuleDir + "del");
  21. const revCollector = require(ideModuleDir + 'gulp-rev-collector');
  22. let commandSuffix = ".cmd";
  23. const provider = "wx70d8aa25ec591f7a";
  24. const fullRemoteEngineList = ["laya.core.js", "laya.webgl.js", "laya.filter.js", "laya.ani.js", "laya.d3.js", "laya.html.js", "laya.particle.js", "laya.ui.js", "laya.d3Plugin.js"];
  25. let copyLibsTask = ["copyLibsJsFile"];
  26. let packfiletask = ["packfile"];
  27. if (isPublish2) {
  28. copyLibsTask = "";
  29. packfiletask = ["copyPlatformFile_WX"];
  30. }
  31. let
  32. config,
  33. platform,
  34. releaseDir;
  35. let isGlobalCli = true;
  36. let isOpendataProj;
  37. let versionCon; // 版本管理version.json
  38. let layarepublicPath = path.join(ideModuleDir, "../", "code", "layarepublic");
  39. if (!fs.existsSync(layarepublicPath)) {
  40. layarepublicPath = path.join(ideModuleDir, "../", "out", "layarepublic");
  41. }
  42. // 应该在publish中的,但是为了方便发布2.0及IDE 1.x,放在这里修改
  43. gulp.task("preCreate_WX", copyLibsTask, function() {
  44. if (isPublish2) {
  45. let pubsetPath = path.join(workSpaceDir, ".laya", "pubset.json");
  46. let content = fs.readFileSync(pubsetPath, "utf8");
  47. let pubsetJson = JSON.parse(content);
  48. platform = "wxgame";
  49. releaseDir = path.join(workSpaceDir, "release", platform).replace(/\\/g, "/");
  50. config = pubsetJson[1];
  51. } else {
  52. platform = global.platform;
  53. releaseDir = global.releaseDir;
  54. config = global.config;
  55. }
  56. // 如果不是微信小游戏
  57. if (platform !== "wxgame") {
  58. return;
  59. }
  60. if (process.platform === "darwin") {
  61. commandSuffix = "";
  62. }
  63. // 是否是开放域项目
  64. let projInfoPath = path.join(workSpaceDir, path.basename(workSpaceDir) + ".laya");
  65. let isExist = fs.existsSync(projInfoPath);
  66. if (isExist) {
  67. try {
  68. let projInfo = fs.readFileSync(projInfoPath, "utf8");
  69. projInfo = projInfo && JSON.parse(projInfo);
  70. isOpendataProj = projInfo.layaProType === 12;
  71. } catch (e) {}
  72. }
  73. if (isOpendataProj) {
  74. return;
  75. }
  76. let copyLibsList = [`${workSpaceDir}/bin/libs/laya.wxmini.js`];
  77. var stream = gulp.src(copyLibsList, { base: `${workSpaceDir}/bin` });
  78. return stream.pipe(gulp.dest(releaseDir));
  79. });
  80. gulp.task("copyPlatformFile_WX", ["preCreate_WX"], function() {
  81. // 如果不是微信小游戏
  82. if (platform !== "wxgame") {
  83. return;
  84. }
  85. let adapterPath = path.join(layarepublicPath, "LayaAirProjectPack", "lib", "data", "wxfiles");
  86. // 开放域项目
  87. if (isOpendataProj) {
  88. let platformDir = path.join(adapterPath, "weapp-adapter.js");
  89. let stream = gulp.src(platformDir);
  90. return stream.pipe(gulp.dest(releaseDir));
  91. }
  92. // 如果新建项目时已经点击了"微信/百度小游戏bin目录快速调试",不再拷贝
  93. let isHadWXFiles =
  94. fs.existsSync(path.join(workSpaceDir, "bin", "game.js")) &&
  95. fs.existsSync(path.join(workSpaceDir, "bin", "game.json")) &&
  96. fs.existsSync(path.join(workSpaceDir, "bin", "project.config.json")) &&
  97. fs.existsSync(path.join(workSpaceDir, "bin", "weapp-adapter.js"));
  98. if (isHadWXFiles) {
  99. return;
  100. }
  101. let isHasPublish =
  102. fs.existsSync(path.join(releaseDir, "game.js")) &&
  103. fs.existsSync(path.join(releaseDir, "game.json")) &&
  104. fs.existsSync(path.join(releaseDir, "project.config.json")) &&
  105. fs.existsSync(path.join(releaseDir, "weapp-adapter.js"));
  106. if (isHasPublish) {
  107. return;
  108. }
  109. let copyLibsList = [`${adapterPath}/*.*`];
  110. var stream = gulp.src(copyLibsList);
  111. return stream.pipe(gulp.dest(releaseDir));
  112. });
  113. // 开放域的情况下,合并game.js和index.js,并删除game.js
  114. gulp.task("openData_WX", packfiletask, function (cb) {
  115. // 如果不是微信小游戏
  116. if (platform !== "wxgame") {
  117. return cb();
  118. }
  119. if (config.openDataZone) {
  120. let versionCon;
  121. if (config.version) {
  122. let versionPath = releaseDir + "/version.json";
  123. versionCon = fs.readFileSync(versionPath, "utf8");
  124. versionCon = JSON.parse(versionCon);
  125. }
  126. let indexJsStr = (versionCon && versionCon["index.js"]) ? versionCon["index.js"] : "index.js";
  127. let indexPath = path.join(releaseDir, indexJsStr);
  128. let indexjs = readFile(indexPath);
  129. let gamejs = readFile(releaseDir + "/game.js");
  130. if (gamejs && indexjs) {
  131. gamejs = gamejs.replace(`require("index.js")`, indexjs);
  132. fs.writeFileSync(indexPath, gamejs, 'utf-8');
  133. }
  134. if (isOpendataProj) {
  135. // 开放域项目,将game.js删掉,发布最小包
  136. del(`${releaseDir}/game.js`, { force: true }).then(paths => {
  137. cb();
  138. });
  139. } else {
  140. cb();
  141. }
  142. } else {
  143. cb();
  144. }
  145. });
  146. function readFile(path) {
  147. if (fs.existsSync(path)) {
  148. return fs.readFileSync(path, "utf-8");
  149. }
  150. return null;
  151. }
  152. gulp.task("version_WX", ["openData_WX"], function() {
  153. // 如果不是微信小游戏
  154. if (platform !== "wxgame") {
  155. return;
  156. }
  157. if (config.version) {
  158. let versionPath = releaseDir + "/version.json";
  159. let gameJSPath = releaseDir + "/game.js";
  160. let srcList = [versionPath, gameJSPath];
  161. return gulp.src(srcList)
  162. .pipe(revCollector())
  163. .pipe(gulp.dest(releaseDir));
  164. }
  165. });
  166. gulp.task("optimizeOpen_WX", ["version_WX"], function(cb) {
  167. // 如果不是微信小游戏
  168. if (platform !== "wxgame") {
  169. return cb();
  170. }
  171. let wxOptimize = config.wxOptimize;
  172. if (!wxOptimize || !wxOptimize.useOptimizeOpen) { // 没有使用微信引擎插件,还是像以前一样发布
  173. return cb();
  174. }
  175. // 首屏加载优化(秒开),修改game.json
  176. let filePath = path.join(releaseDir, "game.json");
  177. if (!fs.existsSync(filePath)) {
  178. return cb();
  179. }
  180. let fileContent = fs.readFileSync(filePath, "utf8");
  181. let fileConObj = JSON.parse(fileContent);
  182. if (wxOptimize.preloadRes) {
  183. fileConObj.preloadResources = wxOptimize.preloadResList;
  184. } else {
  185. delete fileConObj.preloadResources;
  186. }
  187. if (wxOptimize.preloadSubpack) {
  188. fileConObj.preloadSubpackages = wxOptimize.preloadSubpackList;
  189. } else {
  190. delete fileConObj.preloadSubpackages;
  191. }
  192. fs.writeFileSync(filePath, JSON.stringify(fileConObj, null, 4), "utf8");
  193. return cb();
  194. });
  195. gulp.task("pluginEngin_WX", ["optimizeOpen_WX"], function(cb) {
  196. // 如果不是微信小游戏
  197. if (platform !== "wxgame") {
  198. return cb();
  199. }
  200. if (!config.uesEnginePlugin) { // 没有使用微信引擎插件,还是像以前一样发布
  201. return cb();
  202. }
  203. if (config.version) {
  204. let versionPath = releaseDir + "/version.json";
  205. versionCon = fs.readFileSync(versionPath, "utf8");
  206. versionCon = JSON.parse(versionCon);
  207. }
  208. let indexJsStr = (versionCon && versionCon["index.js"]) ? versionCon["index.js"] : "index.js";
  209. // 获取version等信息
  210. let coreLibPath = path.join(workSpaceDir, "bin", "libs", "laya.core.js");
  211. let isHasCoreLib = fs.existsSync(coreLibPath);
  212. let isOldAsProj = fs.existsSync(`${workSpaceDir}/asconfig.json`) && !isHasCoreLib;
  213. let isNewTsProj = fs.existsSync(`${workSpaceDir}/src/tsconfig.json`) && !isHasCoreLib;
  214. let EngineVersion = getEngineVersion();
  215. if (!EngineVersion) {
  216. throw new Error(`读取引擎版本号失败,请于服务提供商联系!`);
  217. }
  218. if (!EngineVersion || EngineVersion.includes("beta") || !canUsePluginEngine(EngineVersion)) {
  219. throw new Error(`该版本引擎无法使用引擎插件功能(engineVersion: ${EngineVersion})`);
  220. }
  221. console.log(`通过版本号检查: ${EngineVersion}`);
  222. // 使用引擎插件
  223. let localUseEngineList = [];
  224. let copyEnginePathList;
  225. new Promise(function(resolve, reject) {
  226. console.log(`修改game.js和game.json`);
  227. // 1) 修改game.js和game.json
  228. // 修改game.js
  229. let gameJsPath = path.join(releaseDir, "game.js");
  230. let gameJscontent = `require("weapp-adapter.js");\nrequire("./libs/laya.wxmini.js");\nrequirePlugin('layaPlugin');\nwindow.loadLib = require;\nrequire("./${indexJsStr}");`;
  231. fs.writeFileSync(gameJsPath, gameJscontent, "utf8");
  232. // 修改game.json,使其支持引擎插件
  233. let gameJsonPath = path.join(releaseDir, "game.json");
  234. let gameJsonContent = fs.readFileSync(gameJsonPath, "utf8");
  235. let conJson = JSON.parse(gameJsonContent);
  236. conJson.plugins = {
  237. "layaPlugin": {
  238. "version": EngineVersion,
  239. "provider": provider,
  240. "path": "laya-libs"
  241. }
  242. }
  243. gameJsonContent = JSON.stringify(conJson, null, 4);
  244. fs.writeFileSync(gameJsonPath, gameJsonContent, "utf8");
  245. resolve();
  246. }).then(function() {
  247. return new Promise(function(resolve, reject) {
  248. console.log(`确定用到的插件引擎`);
  249. // 2) 确定用到了那些插件引擎,并将插件引擎从index.js的引用中去掉
  250. let indexJsPath = path.join(releaseDir, indexJsStr);
  251. let indexJsCon = fs.readFileSync(indexJsPath, "utf8");
  252. let item, fullRequireItem;
  253. for (let i = 0, len = fullRemoteEngineList.length; i < len; i++) {
  254. item = fullRemoteEngineList[i];
  255. fullRequireItem = `loadLib("libs/${item}")`;
  256. if (indexJsCon.includes(fullRequireItem)) {
  257. localUseEngineList.push(item);
  258. indexJsCon = indexJsCon.replace(fullRequireItem, "");
  259. }
  260. }
  261. if (isOldAsProj || isNewTsProj) { // 如果as||ts_new语言,开发者将laya.js也写入index.js中了,将其删掉
  262. fullRequireItem = `loadLib("laya.js")`;
  263. if (indexJsCon.includes(fullRequireItem)) {
  264. indexJsCon = indexJsCon.replace(fullRequireItem, "");
  265. }
  266. }
  267. fs.writeFileSync(indexJsPath, indexJsCon, "utf8");
  268. // ts/js再次修改game.js,仅引用使用到的类库
  269. // as||ts_new因为本地只有laya.js,无法仅引用使用到的类库
  270. if (!isOldAsProj && !isNewTsProj) {
  271. let pluginCon = "";
  272. localUseEngineList.forEach(function(item) {
  273. pluginCon += `requirePlugin("layaPlugin/${item}");\n`;
  274. });
  275. let gameJsPath = path.join(releaseDir, "game.js");
  276. let gameJsCon = fs.readFileSync(gameJsPath, "utf8");
  277. gameJsCon = gameJsCon.replace(`requirePlugin('layaPlugin');`, pluginCon);
  278. fs.writeFileSync(gameJsPath, gameJsCon, "utf8");
  279. }
  280. resolve();
  281. });
  282. }).then(function() {
  283. return new Promise(function(resolve, reject) {
  284. console.log(`将本地的引擎插件移动到laya-libs中`);
  285. // 3) 将本地的引擎插件移动到laya-libs中
  286. copyEnginePathList = [`${releaseDir}/libs/{${localUseEngineList.join(",")}}`];
  287. if (isOldAsProj || isNewTsProj) { // 单独拷贝laya.js
  288. copyEnginePathList = [`${releaseDir}/laya.js`];
  289. }
  290. gulp.src(copyEnginePathList).pipe(gulp.dest(`${releaseDir}/laya-libs`));
  291. setTimeout(resolve, 500);
  292. });
  293. }).then(function() {
  294. return new Promise(function(resolve, reject) {
  295. console.log(`将libs中的本地引擎插件删掉`);
  296. // 4) 将libs中的本地引擎插件删掉
  297. del(copyEnginePathList, { force: true }).then(resolve);
  298. });
  299. }).then(function() {
  300. return new Promise(async function(resolve, reject) {
  301. console.log(`完善引擎插件目录`);
  302. // 5) 引擎插件目录laya-libs中还需要新建几个文件,使该目录能够使用
  303. if (isOldAsProj || isNewTsProj) { // 单独拷贝laya.js
  304. localUseEngineList.push("laya.js");
  305. }
  306. let
  307. layalibsPath = path.join(releaseDir, "laya-libs"),
  308. engineIndex = path.join(layalibsPath, "index.js"),
  309. engineplugin = path.join(layalibsPath, "plugin.json"),
  310. enginesignature = path.join(layalibsPath, "signature.json");
  311. // index.js
  312. if (!fs.existsSync(layalibsPath)) {
  313. throw new Error("引擎插件目录创建失败,请与服务提供商联系!");
  314. }
  315. let indexCon = "";
  316. localUseEngineList.forEach(function(item) {
  317. indexCon += `require("./${item}");\n`;
  318. });
  319. fs.writeFileSync(engineIndex, indexCon, "utf8");
  320. // plugin.json
  321. let pluginCon = {"main": "index.js"};
  322. fs.writeFileSync(engineplugin, JSON.stringify(pluginCon, null, 4), "utf8");
  323. // signature.json
  324. let signatureCon = {
  325. "provider": provider,
  326. "signature": []
  327. };
  328. localUseEngineList.unshift("index.js");
  329. let fileName, md5Str;
  330. for (let i = 0, len = localUseEngineList.length; i < len; i++) {
  331. fileName = localUseEngineList[i];
  332. let md5Str = await getFileMd5(path.join(releaseDir, "laya-libs", fileName));
  333. signatureCon.signature.push({
  334. "path": fileName,
  335. "md5": md5Str
  336. });
  337. }
  338. fs.writeFileSync(enginesignature, JSON.stringify(signatureCon, null, 4), "utf8");
  339. resolve();
  340. });
  341. })
  342. .then(function() {
  343. cb();
  344. }).catch(function(e) {
  345. throw e;
  346. })
  347. });
  348. function getEngineVersion() {
  349. let coreLibPath = path.join(workSpaceDir, "bin", "libs", "laya.core.js");
  350. let isHasCoreLib = fs.existsSync(coreLibPath);
  351. let isOldAsProj = fs.existsSync(`${workSpaceDir}/asconfig.json`) && !isHasCoreLib;
  352. let isNewTsProj = fs.existsSync(`${workSpaceDir}/src/tsconfig.json`) && !isHasCoreLib;
  353. let EngineVersion;
  354. if (isHasCoreLib) {
  355. let con = fs.readFileSync(coreLibPath, "utf8");
  356. let matchList = con.match(/Laya\.version\s*=\s*['"]([0-9\.]+(beta)?.*)['"]/);
  357. if (!Array.isArray(matchList)) {
  358. return null;
  359. }
  360. EngineVersion = matchList[1];
  361. } else { // newts项目和旧版本as项目
  362. if (isOldAsProj) {
  363. let coreLibFilePath = path.join(workSpaceDir, "libs", "laya", "src", "Laya.as");
  364. if (!fs.existsSync(coreLibFilePath)) {
  365. return null;
  366. }
  367. let con = fs.readFileSync(coreLibFilePath, "utf8");
  368. let matchList = con.match(/version:String\s*=\s*['"]([0-9\.]+(beta)?.*)['"]/);
  369. if (!Array.isArray(matchList)) {
  370. return null;
  371. }
  372. EngineVersion = matchList[1];
  373. } else if (isNewTsProj) {
  374. let coreLibFilePath = path.join(workSpaceDir, "libs", "Laya.ts");
  375. if (!fs.existsSync(coreLibFilePath)) {
  376. return null;
  377. }
  378. let con = fs.readFileSync(coreLibFilePath, "utf8");
  379. let matchList = con.match(/static\s*version:\s*string\s*=\s*['"]([0-9\.]+(beta)?.*)['"]/);
  380. if (!Array.isArray(matchList)) {
  381. return null;
  382. }
  383. EngineVersion = matchList[1];
  384. }
  385. }
  386. // 特殊处理,因为历史原因,我们有一些4位的正式版本,调整为3位
  387. if (EngineVersion && /[\d\.]+/.test(EngineVersion) && EngineVersion.split(".").length > 3) {
  388. let verList = EngineVersion.split(".");
  389. verList.length = 3;
  390. EngineVersion = verList.join(".");
  391. }
  392. return EngineVersion;
  393. }
  394. function getFileMd5(filePath) {
  395. return new Promise(function(resolve, reject) {
  396. let md5 = crypto.createHash('md5');
  397. let stream = fs.createReadStream(filePath);
  398. stream.on("data", function(data) {
  399. md5.update(data);
  400. });
  401. stream.on("end", function() {
  402. let md5Str = md5.digest('hex');
  403. return resolve(md5Str);
  404. });
  405. });
  406. }
  407. function canUsePluginEngine(version) {
  408. const minVersionNum = "2.0.1";
  409. let compileMacthList = minVersionNum.match(/^(\d+)\.(\d+)\.(\d+)/);
  410. let matchList = version.match(/^(\d+)\.(\d+)\.(\d+)/);
  411. if (matchList[1] > compileMacthList[1]) {
  412. return true;
  413. }
  414. if (matchList[1] === compileMacthList[1] && matchList[2] > compileMacthList[2]) {
  415. return true;
  416. }
  417. if (matchList[1] === compileMacthList[1] && matchList[2] === compileMacthList[2] && matchList[3] >= compileMacthList[3]) {
  418. return true;
  419. }
  420. return false;
  421. }
  422. gulp.task("buildWXProj", ["pluginEngin_WX"], function() {
  423. console.log("all tasks completed");
  424. });