gulpfile.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /** @format */
  2. const gulp = require('gulp')
  3. const del = require('del')
  4. const shell = require('gulp-shell')
  5. const replace = require('gulp-replace')
  6. const fs = require('fs')
  7. const zip = require('gulp-zip')
  8. const path = require('path')
  9. const Sftp = require('ssh2-sftp-client')
  10. const https = require('https')
  11. const minimist = require('minimist')
  12. const GulpSSH = require('gulp-ssh')
  13. //操作pipe中文件的路径
  14. const vinylPaths = require('vinyl-paths')
  15. //重命名文件
  16. const rename = require('gulp-rename')
  17. // 配置
  18. const knownOptions = {
  19. string: 'version',
  20. string: 'cocosPath',
  21. string: 'buildPath',
  22. string: 'debugBool',
  23. string: 'releaseBool',
  24. string: 'h5RemoteUrl',
  25. string: 'configUrl',
  26. string: 'packageName',
  27. string: 'keystorePath',
  28. string: 'isQQ',
  29. string: 'isTT',
  30. string: 'appid',
  31. string: 'appType',
  32. string: 'gameType',
  33. string: 'channel',
  34. default: {
  35. version: '1',
  36. cocosPath: 'D:/CocosEditors/Creator/2.4.12/CocosCreator.exe',
  37. buildPath: './build',
  38. debugBool: 'false',
  39. releaseBool: 'false',
  40. h5RemoteUrl: '/www/wwwroot/b22_client_h5_dev/',
  41. configUrl: '',
  42. packageName: 'com.company',
  43. autoCompile: 'false',
  44. keystorePath: 'D:/black_art.jks',
  45. appid: 'wx7a1fbe2f424a93b4',
  46. isQQ: 'false',
  47. isTT: 'false',
  48. appType: 1,
  49. gameType: 1,
  50. channel: '',
  51. },
  52. }
  53. const options = minimist(process.argv.slice(2), knownOptions)
  54. const resServerConfig = {
  55. host: options.debugBool == 'true' || options.releaseBool == 'true' ? '47.107.63.156' : '47.107.63.156',
  56. port: 22,
  57. username: 'root',
  58. privateKey: fs.existsSync('D:\\cer\\id_rsa') ? fs.readFileSync('D:\\cer\\id_rsa') : null,
  59. }
  60. let getGulpSSH = (isTest = true) => {
  61. return new GulpSSH({
  62. ignoreErrors: false,
  63. sshConfig: {
  64. host: isTest ? '43.139.94.120' : '43.139.94.120',
  65. port: 22,
  66. username: 'root',
  67. privateKey: fs.readFileSync('D:\\test_server_guangzhou.pem'),
  68. },
  69. })
  70. }
  71. const zipName = 'upload.zip'
  72. const testResUrl = ''
  73. const onlineResUrl = ''
  74. const localUploadUrl = path.join(options.buildPath, 'upload')
  75. const projectPath = 'D:\\b22_client'
  76. // shell
  77. let shellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=wechatgame;debug=${options.debugBool};"`
  78. let h5ShellTask = `${options.cocosPath} --path ./ --build "buildPath=${
  79. options.buildPath
  80. };platform=web-mobile;embedWebDebugger=${options.debugBool == 'true' || options.releaseBool == 'true'};debug=${
  81. options.debugBool
  82. };"`
  83. let IOSShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=ios;template=link;debug=${options.debugBool};"`
  84. let AndroidShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=android;template=link;debug=${options.debugBool};autoCompile=${options.autoCompile};useDebugKeystore=false;keystorePath=${options.keystorePath};keystorePassword=123456;keystoreAlias=key0;keystoreAliasPassword=123456;apiLevel=android-33;appABIs=['armeabi-v7a','arm64-v8a','x86','x86_64'];packageName=${options.packageName};md5Cache=false;"`
  85. let wxsubshellTask = `${options.cocosPath} --path ./wx_sub --build "buildPath=./build/;platform=wechatgame-subcontext"`
  86. let TTShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=bytedance;debug=${options.debugBool};mainIsRemote=true;"`
  87. let win32ShellTask = `${options.cocosPath} --path ./ --build "buildPath=${options.buildPath};platform=win32;template=link;debug=${options.debugBool};md5Cache=false;"`
  88. // 文件修改
  89. gulp.task('copy:Regular', () =>
  90. gulp
  91. .src('./assets/script/data/ConstValue.ts')
  92. .pipe(replace('DEBUG = true', 'DEBUG = ' + options.debugBool))
  93. .pipe(replace('DEBUG = false', 'DEBUG = ' + options.debugBool))
  94. .pipe(gulp.dest('./assets/script/data')),
  95. )
  96. gulp.task('copy:index', () =>
  97. gulp
  98. .src('./build-templates/web-mobile/index.html')
  99. .pipe(
  100. replace(
  101. '<script src="vconsole.min.js"></script>',
  102. `<script src="${
  103. options.debugBool == 'true' || options.releaseBool == 'true' ? 'vconsole.min.js' : ''
  104. }"></script>`,
  105. ),
  106. )
  107. .pipe(
  108. replace(
  109. '<script src=""></script>',
  110. `<script src="${
  111. options.debugBool == 'true' || options.releaseBool == 'true' ? 'vconsole.min.js' : ''
  112. }"></script>`,
  113. ),
  114. )
  115. .pipe(gulp.dest('./build-templates/web-mobile')),
  116. )
  117. const updateJson = (jsonUrl, key, value, key2) => {
  118. const json = JSON.parse(fs.readFileSync(jsonUrl).toString())
  119. if (key2) {
  120. json[key2][key] = value
  121. } else {
  122. json[key] = value
  123. }
  124. fs.writeFileSync(jsonUrl, JSON.stringify(json, '', ' '))
  125. }
  126. gulp.task('copy:REMOTE_SERVER_ROOT', cb => {
  127. let url = options.debugBool == 'true' ? testResUrl : onlineResUrl
  128. url += options.isQQ == 'true' ? 'card-qq' : 'card-wx'
  129. updateJson('./settings/wechatgame.json', 'REMOTE_SERVER_ROOT', url)
  130. updateJson('./settings/wechatgame.json', 'appid', options.appid)
  131. updateJson('./settings/builder.json', 'REMOTE_SERVER_ROOT', url, 'wechatgame')
  132. updateJson('./settings/builder.json', 'appid', options.appid, 'wechatgame')
  133. cb()
  134. })
  135. // 资源上传
  136. const copy = (src, dst) => fs.writeFileSync(dst, fs.readFileSync(src))
  137. const mkdirsSync = dirname => {
  138. if (fs.existsSync(dirname)) {
  139. return true
  140. } else if (mkdirsSync(path.dirname(dirname))) {
  141. fs.mkdirSync(dirname)
  142. return true
  143. }
  144. return false
  145. }
  146. const delDir = dirPath => {
  147. let files = []
  148. if (fs.existsSync(dirPath)) {
  149. files = fs.readdirSync(dirPath)
  150. files.forEach(file => {
  151. const curPath = path.join(dirPath, file)
  152. if (fs.statSync(curPath).isDirectory()) {
  153. delDir(curPath) // 递归删除文件夹
  154. } else {
  155. fs.unlinkSync(curPath) // 删除文件
  156. }
  157. })
  158. fs.rmdirSync(dirPath)
  159. }
  160. }
  161. const readFileList = (filePath, filesList = []) => {
  162. const files = fs.readdirSync(filePath)
  163. files.forEach(fileName => {
  164. const fullPath = path.join(filePath, fileName)
  165. if (fs.statSync(fullPath).isDirectory()) {
  166. readFileList(fullPath, filesList) // 递归读取文件
  167. } else {
  168. filesList.push(fullPath)
  169. }
  170. })
  171. return filesList
  172. }
  173. const readFileDirList = (filePath, filesList = []) => {
  174. const files = fs.readdirSync(filePath)
  175. files.forEach(fileName => {
  176. const fullPath = path.join(filePath, fileName)
  177. if (fs.statSync(fullPath).isDirectory()) {
  178. filesList.push(fullPath)
  179. readFileDirList(fullPath, filesList) // 递归读取文件夹
  180. }
  181. })
  182. return filesList
  183. }
  184. const curUpLoadResRecord = []
  185. let UpLoadResRecordKeys = []
  186. const UpLoadResRecordUrl = options.debugBool == 'true' ? './UpLoadResTestRecord.txt' : './UpLoadResRecord.txt'
  187. const uploadRes = (inputPath, platfrom) => {
  188. const files = readFileList(inputPath)
  189. if (!fs.existsSync(UpLoadResRecordUrl)) {
  190. fs.writeFileSync(UpLoadResRecordUrl, '', 'utf-8')
  191. }
  192. UpLoadResRecordKeys = fs.readFileSync(UpLoadResRecordUrl, 'utf-8').split('\r\n')
  193. UpLoadResRecordKeys = UpLoadResRecordKeys.filter(value => value != '')
  194. delDir(localUploadUrl) // 清空打包文件夹
  195. mkdirsSync(localUploadUrl) // 建立打包文件夹
  196. // 分析差异文件,拷贝到打包文件夹
  197. for (let i = 0; i < files.length; i++) {
  198. if (UpLoadResRecordKeys.indexOf(files[i]) < 0 || files[i].indexOf('index.html') != -1) {
  199. const dist = files[i].replace(path.join(options.buildPath, platfrom), localUploadUrl)
  200. // console.log(i, files[i], dist);
  201. mkdirsSync(path.resolve(dist, '..')) // 确保拷贝前目录存在
  202. if (fs.existsSync(files[i])) {
  203. copy(files[i], dist)
  204. } else {
  205. console.log(' uploadRes copy file:', files[i], 'no exist')
  206. }
  207. curUpLoadResRecord.push(files[i])
  208. }
  209. }
  210. mkdirsSync(path.join(localUploadUrl, 'empty'))
  211. // 拷贝分享目录
  212. /*
  213. const share = readFileList('./share');
  214. for (let i = 0; i < share.length; i++) {
  215. const dist = path.join(localUploadUrl, share[i]);
  216. mkdirsSync(path.resolve(dist, '..')); // 确保拷贝前目录存在
  217. copy(share[i], dist);
  218. }
  219. */
  220. }
  221. gulp.task('copy:uploadRes', cb => {
  222. let platform = 'wechatgame'
  223. if (options.isTT == 'true') platform = 'bytedance'
  224. uploadRes(`${options.buildPath}/${platform}/remote/`, platform)
  225. cb()
  226. })
  227. gulp.task('copy:uploadResH5', cb => {
  228. uploadRes(`${options.buildPath}/web-mobile/`, 'web-mobile')
  229. cb()
  230. })
  231. gulp.task('Zip', () => gulp.src(`${localUploadUrl}/**/*`).pipe(zip(zipName)).pipe(gulp.dest(localUploadUrl)))
  232. let preTime = 0
  233. let curByte = 0
  234. const ftpUpload = (cb, remoteUrl) => {
  235. let sftp = new Sftp()
  236. sftp.connect(resServerConfig)
  237. .then(() => {
  238. console.log(
  239. 'sftp连接成功,上传中... ',
  240. zipName,
  241. 'localUploadUrl-->',
  242. path.join(localUploadUrl, zipName),
  243. 'remoteUrl--->',
  244. `${remoteUrl}${zipName}`,
  245. )
  246. return sftp.fastPut(path.join(localUploadUrl, zipName), `${remoteUrl}${zipName}`, {
  247. step: (cur, chunk, total) => {
  248. if (preTime == 0) {
  249. preTime = Date.now()
  250. curByte = cur
  251. }
  252. const stepTime = Date.now() - preTime
  253. if (stepTime > 1000) {
  254. preTime = Date.now()
  255. const stepByte = cur - curByte
  256. console.log(((cur / total) * 100).toFixed(2), '% ', (stepByte / 1024).toFixed(2), 'kb/s')
  257. curByte = cur
  258. }
  259. },
  260. })
  261. })
  262. .then(() => {
  263. console.log('上传完成!')
  264. cb()
  265. })
  266. .catch(err => {
  267. console.log('sftp报错', err)
  268. })
  269. .finally(data => {
  270. console.log('sftpfinally', data)
  271. sftp.end()
  272. })
  273. }
  274. let unZipSucc = true
  275. let getDeleteJsonList = function (path, list) {
  276. let files = fs.readdirSync(path)
  277. files.forEach(item => {
  278. let stat = fs.statSync(path + item)
  279. if (stat.isDirectory()) {
  280. getDeleteJsonList(path + item + '/', list)
  281. } else if (stat.size > 0 * 1024) {
  282. list.push(path + item)
  283. }
  284. })
  285. return list
  286. }
  287. gulp.task('clean:res', cb => {
  288. let platform = 'wechatgame'
  289. if (options.isTT == 'true') platform = 'bytedance'
  290. let list = []
  291. let path = `${options.buildPath}/${platform}/remote/`
  292. getDeleteJsonList(path, list)
  293. console.log(list)
  294. del.sync(list, {force: true, allowEmpty: true})
  295. cb()
  296. })
  297. gulp.task('updateUploadUrl', cb => {
  298. if (unZipSucc) {
  299. let apendStr = ''
  300. for (let i = 0; i < curUpLoadResRecord.length; i++) {
  301. apendStr += `${curUpLoadResRecord[i]}\r\n`
  302. }
  303. fs.appendFileSync(UpLoadResRecordUrl, apendStr, 'utf-8')
  304. } else {
  305. console.log('远程解压缩失败')
  306. }
  307. cb()
  308. })
  309. gulp.task('clearUpdateUploadUrl', cb => {
  310. fs.writeFileSync('./UpLoadResTestRecord.txt', '', 'utf-8')
  311. fs.writeFileSync('./UpLoadResRecord.txt', '', 'utf-8')
  312. cb()
  313. })
  314. let getRemoteUrl = () => {
  315. let url = ''
  316. return url
  317. }
  318. gulp.task('SFTP', cb => ftpUpload(cb, getRemoteUrl()))
  319. gulp.task('H5SFTP', cb => ftpUpload(cb, options.h5RemoteUrl))
  320. gulp.task('UnZip', cb => {
  321. cb()
  322. // return getGulpSSH()
  323. // .shell(['cd ' + options.h5RemoteUrl, 'unzip -Co upload.zip -d ./'])
  324. })
  325. gulp.task('uploadQiniu', shell.task(`java -DwebRoot=${localUploadUrl} -DdirPath=${localUploadUrl} -jar qiniu.jar`))
  326. gulp.task('uploadResContinueH5', gulp.series('copy:uploadResH5', 'Zip', 'updateUploadUrl'))
  327. gulp.task('uploadResContinueH5qiniu', gulp.series('copy:uploadResH5', 'uploadQiniu', 'updateUploadUrl'))
  328. gulp.task('uploadResContinue', gulp.series('copy:uploadRes', 'Zip', 'SFTP', 'UnZip', 'clean:res', 'updateUploadUrl'))
  329. Date.prototype.Format = function (fmt) {
  330. let o = {
  331. 'Y+': this.getFullYear(), // 年
  332. 'M+': this.getMonth() + 1, // 月份
  333. 'd+': this.getDate(), // 日
  334. 'h+': this.getHours(), // 小时
  335. 'm+': this.getMinutes(), // 分
  336. 's+': this.getSeconds(), // 秒
  337. 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
  338. 'S+': this.getMilliseconds(), // 毫秒
  339. }
  340. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, `${this.getFullYear()}`.substr(4 - RegExp.$1.length))
  341. for (let k in o)
  342. if (new RegExp(`(${k})`).test(fmt))
  343. fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : `00${o[k]}`.substr(`${o[k]}`.length))
  344. return fmt
  345. }
  346. gulp.task('version', () => {
  347. let filePath = './assets/resources/version.json'
  348. let obj = {}
  349. obj.time = new Date().Format('YYMMddhhmmss')
  350. obj.appType = options.appType
  351. obj.gameType = options.gameType
  352. fs.writeFileSync(filePath, JSON.stringify(obj))
  353. return gulp
  354. .src('./build-templates/jsb-link/main.js')
  355. .pipe(replace(/window\._game_res_version = \'\d{12}\'/g, `window._game_res_version = \'${obj.time}\'`))
  356. .pipe(gulp.dest('./build-templates/jsb-link/'))
  357. })
  358. gulp.task(
  359. 'wxsub',
  360. gulp.series(
  361. /*'compile-wxsub','copywxsub'*/ cb => {
  362. cb()
  363. },
  364. ),
  365. )
  366. gulp.task('copywxsub', () => gulp.src('./wx_sub/build/**/*').pipe(gulp.dest(`${options.buildPath}/wechatgame`)))
  367. gulp.task('compile-wxsub', shell.task(wxsubshellTask))
  368. gulp.task(
  369. 'WX',
  370. gulp.series('version', 'copy:Regular', 'copy:REMOTE_SERVER_ROOT', shell.task(shellTask), 'uploadResContinue'),
  371. )
  372. gulp.task('H5', gulp.series('version', 'copy:Regular', 'copy:index', shell.task(h5ShellTask), 'uploadResContinueH5'))
  373. gulp.task(
  374. 'H5qiniu',
  375. gulp.series('version', 'copy:Regular', 'copy:index', shell.task(h5ShellTask), 'uploadResContinueH5qiniu'),
  376. )
  377. gulp.task('IOS', gulp.series('version', 'copy:Regular', shell.task(IOSShellTask)))
  378. gulp.task('Android', gulp.series('version', 'copy:Regular', shell.task(AndroidShellTask)))
  379. gulp.task('TT', gulp.series('version', 'copy:Regular', shell.task(TTShellTask), 'uploadResContinue'))
  380. gulp.task('win32', gulp.series('version', 'copy:Regular', shell.task(win32ShellTask)))
  381. const {URL} = require('url')
  382. const cwd = process.cwd()
  383. const root = cwd
  384. ;(exts = ['.jpg', '.png']), (max = 5200000) // 5MB == 5242848.754299136
  385. const tinypngoptions = {
  386. method: 'POST',
  387. hostname: 'tinypng.com',
  388. path: '/web/shrink',
  389. headers: {
  390. rejectUnauthorized: false,
  391. 'Postman-Token': Date.now(),
  392. 'Cache-Control': 'no-cache',
  393. 'Content-Type': 'application/x-www-form-urlencoded',
  394. 'User-Agent':
  395. 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  396. },
  397. }
  398. // 生成随机IP, 赋值给 X-Forwarded-For
  399. function getRandomIP() {
  400. return Array.from(Array(4))
  401. .map(() => parseInt(Math.random() * 255))
  402. .join('.')
  403. }
  404. let allUploadFiles = []
  405. let allSuccessUploadFiles = new Map()
  406. let curAllUploadCount = 0
  407. let maxReq = 500
  408. let fileUploadIDs = new Map()
  409. let tinyPngRecords = new Map()
  410. // 获取文件列表
  411. function fileList(folder) {
  412. let files = fs.readdirSync(folder)
  413. files.forEach(file1 => {
  414. let file = path.join(folder, file1)
  415. let stats = fs.statSync(file)
  416. if (
  417. // 必须是文件,小于5MB,后缀 jpg||png
  418. stats.size <= max &&
  419. stats.isFile() &&
  420. exts.includes(path.extname(file))
  421. ) {
  422. // 通过 X-Forwarded-For 头部伪造客户端IP
  423. console.log('可以压缩:' + file)
  424. allUploadFiles.push(file)
  425. }
  426. if (stats.isDirectory()) fileList(file + '/')
  427. })
  428. }
  429. let crypto = require('crypto')
  430. function MD5(img) {
  431. let buffer = fs.readFileSync(img)
  432. let fsHash = crypto.createHash('md5')
  433. fsHash.update(buffer)
  434. return fsHash.digest('hex')
  435. }
  436. function popUploadFiles(cb) {
  437. for (let i = 0; i < maxReq; i++) {
  438. let file = allUploadFiles.pop()
  439. if (file) {
  440. let hasRecord = false
  441. let recordData = tinyPngRecords.get(file)
  442. if (recordData && recordData == MD5(path.join(cwd, file))) {
  443. hasRecord = true
  444. }
  445. if (hasRecord) {
  446. allSuccessUploadFiles.set(file, true)
  447. if (allSuccessUploadFiles.size == curAllUploadCount) {
  448. cb()
  449. } else {
  450. let curCount = allSuccessUploadFiles.size
  451. if (curCount % maxReq == 0) popUploadFiles(cb)
  452. console.log('当前总进度:', allSuccessUploadFiles.size, '/', curAllUploadCount)
  453. }
  454. } else {
  455. fileUpload(file, cb)
  456. }
  457. }
  458. }
  459. }
  460. // 过滤文件格式,返回所有jpg,png图片
  461. function fileFilter(file) {
  462. // fs.stat(file, (err, stats) => {
  463. // if (err) return console.error(err);
  464. //
  465. // });
  466. }
  467. // 异步API,压缩图片
  468. // {"error":"Bad request","message":"Request is invalid"}
  469. // {"input": { "size": 887, "type": "image/png" },"output": { "size": 785, "type": "image/png", "width": 81, "height": 81, "ratio": 0.885, "url": "https://tinypng.com/web/output/7aztz90nq5p9545zch8gjzqg5ubdatd6" }}
  470. function fileUpload(img, cb) {
  471. tinypngoptions.headers['X-Forwarded-For'] = getRandomIP()
  472. let fileUploadID = fileUploadIDs.get(img)
  473. if (fileUploadID) clearTimeout(fileUploadID)
  474. var req = https.request(tinypngoptions, function (res) {
  475. res.on('data', buf => {
  476. try {
  477. let obj = JSON.parse(buf.toString())
  478. if (obj.error) {
  479. console.log(`[${img}]:压缩失败!报错:${obj.message}`)
  480. }
  481. fileUpdate(img, obj, cb)
  482. } catch (e) {
  483. }
  484. })
  485. })
  486. req.write(fs.readFileSync(img), 'binary')
  487. req.on('error', e => {
  488. console.error('fileUpload error:', e)
  489. })
  490. req.end()
  491. fileUploadID = setTimeout(() => {
  492. req.destroy()
  493. fileUpload(img, cb)
  494. }, 10000)
  495. fileUploadIDs.set(img, fileUploadID)
  496. }
  497. // 该方法被循环调用,请求图片数据
  498. function fileUpdate(imgpath, obj, cb, index) {
  499. const outputDir = path.join(cwd, '')
  500. let img = imgpath
  501. imgpath = path.join(cwd, '', imgpath.replace(cwd, ''))
  502. if (!fs.existsSync(outputDir)) {
  503. fs.mkdirSync(outputDir)
  504. }
  505. let options = new URL(obj.output.url)
  506. let req = https.request(options, res => {
  507. let body = ''
  508. res.setEncoding('binary')
  509. res.on('data', function (data) {
  510. body += data
  511. })
  512. res.on('end', function () {
  513. fs.writeFile(imgpath, body, 'binary', err => {
  514. if (err) console.error(err)
  515. console.log(
  516. `[${imgpath}] \n 压缩成功,原始大小-${obj.input.size},压缩大小-${obj.output.size},优化比例-${obj.output.ratio}`,
  517. )
  518. // 替换文件md5或者新增
  519. let recordData = tinyPngRecords.get(img)
  520. let fileMd5 = MD5(img)
  521. if (recordData) {
  522. let content = fs.readFileSync(tinyPngRecordUrl, 'utf-8')
  523. content.replace(img + '||' + recordData, img + '||' + fileMd5)
  524. fs.writeFileSync(tinyPngRecordUrl, content, 'utf-8')
  525. } else {
  526. let str = '\r\n' + img + '||' + fileMd5
  527. fs.appendFileSync(tinyPngRecordUrl, str, 'utf-8')
  528. }
  529. let fileUploadID = fileUploadIDs.get(img)
  530. if (fileUploadID) clearTimeout(fileUploadID)
  531. allSuccessUploadFiles.set(img, true)
  532. if (allSuccessUploadFiles.size == curAllUploadCount) {
  533. cb()
  534. } else {
  535. let curCount = allSuccessUploadFiles.size
  536. if (curCount % maxReq == 0) popUploadFiles(cb)
  537. console.log('当前总进度:', allSuccessUploadFiles.size, '/', curAllUploadCount)
  538. }
  539. })
  540. })
  541. })
  542. req.on('error', e => {
  543. console.error(e)
  544. })
  545. req.end()
  546. }
  547. let tinyPngRecordUrl = './tinyPngRecordUrl.txt'
  548. gulp.task('tinypng', function (cb) {
  549. if (!fs.existsSync(tinyPngRecordUrl)) {
  550. fs.writeFileSync(tinyPngRecordUrl, '', 'utf-8')
  551. }
  552. let tinyPngRecordArr = fs.readFileSync(tinyPngRecordUrl, 'utf-8').split('\r\n')
  553. for (let i = 0; i < tinyPngRecordArr.length; i++) {
  554. let obj = tinyPngRecordArr[i].split('||')
  555. tinyPngRecords.set(obj[0], obj[1])
  556. }
  557. fileList('./assets')
  558. curAllUploadCount = allUploadFiles.length
  559. console.log('tinypng curAllUploadCount:', curAllUploadCount)
  560. popUploadFiles(cb)
  561. })
  562. let qiniu = require('qiniu')
  563. let qiniuJS = require('qiniu-js')
  564. var accessKey = 'AnddGCzvj0jyF4NxdRNhTo6EcnmN3ccOdbi03xVS'
  565. var secretKey = 'eR6wVv-CTunigvfxPxPrwTPPQARUud4O7us_PvRd'
  566. var mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
  567. function uptoken(bucket, keyToOverwrite) {
  568. var options = {
  569. scope: bucket + ':' + keyToOverwrite,
  570. expires: 7200,
  571. }
  572. var putPolicy = new qiniu.rs.PutPolicy(options)
  573. var uploadToken = putPolicy.uploadToken(mac)
  574. return uploadToken
  575. }
  576. //构造上传函数
  577. function qiniuUploadFile(localFile) {
  578. let key = localFile.replace(`${projectPath}/packages-hot-update/manifest/`, '')
  579. if (localFile.includes('build/jsb-link')) {
  580. key = localFile.replace(`${projectPath}/build/jsb-link/`, '')
  581. }
  582. key = 'hotupdate/' + key
  583. //生成上传 Token
  584. token = uptoken('zedu-cdn', key)
  585. let config = new qiniu.conf.Config()
  586. config.zone = qiniu.zone.Zone_z2
  587. var formUploader = new qiniu.form_up.FormUploader(config)
  588. // 文件上传
  589. formUploader.putFile(token, key, localFile, new qiniu.form_up.PutExtra(), function (respErr, respBody, respInfo) {
  590. if (respErr) {
  591. throw respErr
  592. }
  593. if (respInfo.statusCode == 200) {
  594. console.log('七牛上传成功:-------------》', respBody)
  595. } else {
  596. qiniuUploadFile(localFile)
  597. console.log('七牛上传失败:-------------》', respInfo)
  598. }
  599. })
  600. }
  601. let upLoadHotAssets = {}
  602. const UpLoadHotUrl = './UpLoadHotResRecord.txt'
  603. const uploadHotRes = () => {
  604. let projectManifestUrl = `${projectPath}/packages-hot-update/manifest/project.manifest`
  605. let versionManifestUrl = `${projectPath}/packages-hot-update/manifest/version.manifest`
  606. let files = []
  607. readFileList(`${projectPath}/build/jsb-link/assets`, files)
  608. readFileList(`${projectPath}/build/jsb-link/src`, files)
  609. if (!fs.existsSync(UpLoadHotUrl)) {
  610. fs.writeFileSync(UpLoadHotUrl, JSON.stringify({}), 'utf-8')
  611. }
  612. let curAssets = JSON.parse(fs.readFileSync(projectManifestUrl, 'utf-8')).assets
  613. upLoadHotAssets = JSON.parse(fs.readFileSync(UpLoadHotUrl, 'utf-8'))
  614. delDir(localUploadUrl) // 清空打包文件夹
  615. mkdirsSync(localUploadUrl) // 建立打包文件夹
  616. copy(projectManifestUrl, localUploadUrl + '\\project.manifest')
  617. copy(versionManifestUrl, localUploadUrl + '\\version.manifest')
  618. // 分析差异文件,拷贝到打包文件夹
  619. for (let i = 0; i < files.length; i++) {
  620. let file = files[i]
  621. let srcKey = file.replace(`${projectPath}\\build\\jsb-link\\`, '').replace(new RegExp('\\\\', 'g'), '/')
  622. let resMd5 = upLoadHotAssets[srcKey]
  623. if (!resMd5 || curAssets[srcKey].md5 != resMd5) {
  624. const dist = file.replace(`${projectPath}\\build\\jsb-link`, localUploadUrl)
  625. mkdirsSync(path.resolve(dist, '..')) // 确保拷贝前目录存在
  626. if (fs.existsSync(file)) {
  627. copy(file, dist)
  628. console.log(' uploadRes copy file:', files[i], dist)
  629. upLoadHotAssets[srcKey] = curAssets[srcKey].md5
  630. } else {
  631. console.log(' uploadRes copy file:', file, 'no exist')
  632. }
  633. }
  634. }
  635. }
  636. gulp.task('updateHotUploadTxt', cb => {
  637. fs.writeFileSync(UpLoadHotUrl, JSON.stringify(upLoadHotAssets), 'utf-8')
  638. cb()
  639. })
  640. gulp.task('QiniuHotFresh', cb => {
  641. var dirsToRefresh = ['https://cdn.black-art.cn/b22_hotupdate/']
  642. var cdnManager = new qiniu.cdn.CdnManager(mac)
  643. //单次请求链接不可以超过10个,如果超过,请分批发送请求
  644. cdnManager.refreshDirs(dirsToRefresh, function (err, respBody, respInfo) {
  645. if (err) {
  646. throw err
  647. }
  648. console.log(respInfo.statusCode)
  649. if (respInfo.statusCode == 200) {
  650. console.log(dirsToRefresh, '七牛cdn刷新成功')
  651. }
  652. })
  653. cb()
  654. })
  655. let bucketPathName = ['b22_hotupdate', 'b22_hotupdate']
  656. gulp.task(
  657. 'uploadQiniuHot',
  658. shell.task(
  659. `java -DwebRoot=${localUploadUrl} -DdirPath=${localUploadUrl} -Dbucket=black-art-b22 -DbucketPath=${
  660. bucketPathName[options.gameType]
  661. } -jar qiniu.jar`,
  662. ),
  663. )
  664. gulp.task('copyUploadHot', cb => {
  665. uploadHotRes()
  666. cb()
  667. })
  668. gulp.task('uploadHotUpdate', gulp.series('copyUploadHot', 'uploadQiniuHot', 'updateHotUploadTxt', 'QiniuHotFresh'))
  669. let semeWordPinyin = {}
  670. let semeStroke = {}
  671. const {pinyin} = require('pinyin-pro')
  672. gulp.task('excle2js', shell.task(` excel2x -i ${options.configUrl ? options.configUrl : 'D:\\b22_config'} -o ./assets/script/config -t ts_alone`))
  673. gulp.task('updateConfig', gulp.series('excle2js'))
  674. gulp.task('copySpine', cb => {
  675. let desDir = 'D:\\b22_client\\assets\\texture\\Public\\role\\spine\\'
  676. let mainDir = 'D:\\b22_client\\assets\\texture\\MainUI\\spine\\'
  677. //delDir(desDir)
  678. if (!fs.existsSync(desDir)) {
  679. fs.mkdirSync(desDir)
  680. }
  681. let files = []
  682. readFileDirList('D:\\b22_spine\\角色', files)
  683. readFileDirList('D:\\b22_spine\\怪物', files)
  684. //readFileDirList('D:\\b22_spine\\主场景', files)
  685. for (let i = 0; i < files.length; i++) {
  686. let file = files[i]
  687. if (file.includes('skelOutput')) {
  688. let spineFiles = []
  689. readFileList(file, spineFiles)
  690. spineFiles.forEach((item) => {
  691. let des = file.includes('主场景') ? mainDir : desDir
  692. fs.copyFileSync(item, des + path.basename(item))
  693. })
  694. }
  695. }
  696. cb()
  697. })
  698. gulp.task('exportSpine', cb => {
  699. let spineDir = 'D:\\b22_spine\\'
  700. let skelConfig = path.join(spineDir, 'export_skel_setting.json')
  701. let jsonConfig = path.join(spineDir, 'export_json_setting.json')
  702. let files = []
  703. readFileList('D:\\b22_spine', files)
  704. let tasks = []
  705. for (let i = 0; i < files.length; i++) {
  706. let file = files[i]
  707. if (file.includes('.spine')) {
  708. if (!fs.existsSync(`${path.dirname(file)}/skelOutput/`)) {
  709. fs.mkdirSync(`${path.dirname(file)}/skelOutput/`)
  710. }
  711. if (!fs.existsSync(`${path.dirname(file)}/jsonOutput/`)) {
  712. fs.mkdirSync(`${path.dirname(file)}/jsonOutput/`)
  713. }
  714. tasks.push(shell.task(`spine --input "${file}" --output "${path.dirname(file)}/skelOutput/" --export "${skelConfig}"`))
  715. tasks.push(shell.task(`spine --input "${file}" --output "${path.dirname(file)}/jsonOutput/" --export "${jsonConfig}"`))
  716. }
  717. }
  718. // 使用 gulp.series 执行所有命令
  719. gulp.series(tasks)(cb)
  720. })
  721. gulp.task('startinit', cb => {
  722. let filePath = './assets/resources/version.json'
  723. let obj = {}
  724. obj.time = new Date().Format('YYMMddhhmmss')
  725. obj.appType = 1
  726. obj.gameType = 1
  727. obj.channel = ''
  728. fs.writeFileSync(filePath, JSON.stringify(obj))
  729. cb()
  730. })