@ttmg/cli 0.1.0-beta.9 → 0.1.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/index.js +302 -185
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -14,3 +14,32 @@
|
|
|
14
14
|
|
|
15
15
|
1. 支持文件上传进度显示
|
|
16
16
|
2. 支持自动打开浏览器调试模式
|
|
17
|
+
|
|
18
|
+
## 0.1.0-beta.10
|
|
19
|
+
|
|
20
|
+
fix: 修复还未完成新编译就直接上传了的问题
|
|
21
|
+
|
|
22
|
+
## 0.1.0-beta.11
|
|
23
|
+
|
|
24
|
+
feat: 先关闭自动上传能力
|
|
25
|
+
|
|
26
|
+
## 0.1.0-beta.12
|
|
27
|
+
|
|
28
|
+
feat: 支持文件变更监听,告知浏览器文件变更,提醒开发者重新加载游戏
|
|
29
|
+
|
|
30
|
+
## 0.1.0-beta.13
|
|
31
|
+
|
|
32
|
+
1. 支持 sourcemap
|
|
33
|
+
2. 优化上传环节产物,过滤 sourcemap 文件,提高上传效率
|
|
34
|
+
|
|
35
|
+
## 0.1.0-beta.14
|
|
36
|
+
|
|
37
|
+
1. 修复 client key 未成功写入 mock meta 的问题,导致不一致
|
|
38
|
+
|
|
39
|
+
## 0.1.0-beta.15
|
|
40
|
+
|
|
41
|
+
1. 还原 open url 历史方法
|
|
42
|
+
|
|
43
|
+
## 0.1.1
|
|
44
|
+
|
|
45
|
+
发布最新版本,提醒开发者升级最新版本
|
package/dist/index.js
CHANGED
|
@@ -12,14 +12,36 @@ var path = require('path');
|
|
|
12
12
|
var require$$4 = require('cheerio');
|
|
13
13
|
var chromeLauncher = require('chrome-launcher');
|
|
14
14
|
var os = require('os');
|
|
15
|
+
var child_process = require('child_process');
|
|
16
|
+
var https = require('https');
|
|
15
17
|
var require$$6 = require('crypto');
|
|
16
18
|
var require$$5$1 = require('archiver');
|
|
17
19
|
var multer = require('multer');
|
|
18
20
|
var WebSocket = require('ws');
|
|
21
|
+
var glob = require('glob');
|
|
19
22
|
var got = require('got');
|
|
20
23
|
var FormData = require('form-data');
|
|
21
|
-
var qrcode = require('qrcode-terminal');
|
|
22
24
|
var ttmgPack = require('ttmg-pack');
|
|
25
|
+
var qrcode = require('qrcode-terminal');
|
|
26
|
+
|
|
27
|
+
function _interopNamespaceDefault(e) {
|
|
28
|
+
var n = Object.create(null);
|
|
29
|
+
if (e) {
|
|
30
|
+
Object.keys(e).forEach(function (k) {
|
|
31
|
+
if (k !== 'default') {
|
|
32
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
33
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
get: function () { return e[k]; }
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
n.default = e;
|
|
41
|
+
return Object.freeze(n);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var glob__namespace = /*#__PURE__*/_interopNamespaceDefault(glob);
|
|
23
45
|
|
|
24
46
|
function getDefaultExportFromCjs (x) {
|
|
25
47
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -275,10 +297,10 @@ async function openUrl(url) {
|
|
|
275
297
|
'--auto-open-devtools-for-tabs', // 自动打开 DevTools
|
|
276
298
|
'--no-default-browser-check',
|
|
277
299
|
'--allow-insecure-localhost',
|
|
278
|
-
'--ignore-certificate-errors',
|
|
279
300
|
'--allow-running-insecure-content',
|
|
280
301
|
'--remote-allow-origins=*',
|
|
281
302
|
'--user-data-dir=/tmp/chrome-debug-profile',
|
|
303
|
+
'--disable-popup-blocking',
|
|
282
304
|
],
|
|
283
305
|
});
|
|
284
306
|
await new Promise(() => { });
|
|
@@ -326,9 +348,65 @@ function getLocalIP() {
|
|
|
326
348
|
}
|
|
327
349
|
}
|
|
328
350
|
|
|
351
|
+
// 获取全局已安装版本
|
|
352
|
+
function getGlobalVersion(pkgName) {
|
|
353
|
+
try {
|
|
354
|
+
const output = child_process.execSync(`npm ls -g ${pkgName} --depth=0 --json`).toString();
|
|
355
|
+
const json = JSON.parse(output);
|
|
356
|
+
return json.dependencies[pkgName].version;
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// 获取 npm 最新版本
|
|
363
|
+
function getLatestVersion(pkgName) {
|
|
364
|
+
return new Promise((resolve, reject) => {
|
|
365
|
+
https
|
|
366
|
+
.get(`https://registry.npmjs.org/${encodeURIComponent(pkgName)}/latest`, res => {
|
|
367
|
+
let data = '';
|
|
368
|
+
res.on('data', chunk => (data += chunk));
|
|
369
|
+
res.on('end', () => {
|
|
370
|
+
try {
|
|
371
|
+
const info = JSON.parse(data);
|
|
372
|
+
resolve(info.version);
|
|
373
|
+
}
|
|
374
|
+
catch (err) {
|
|
375
|
+
reject(err);
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
})
|
|
379
|
+
.on('error', reject);
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
async function checkUpdate() {
|
|
383
|
+
const boxen = (await import('boxen')).default;
|
|
384
|
+
const pkgName = '@ttmg/cli';
|
|
385
|
+
const oldVersion = getGlobalVersion(pkgName);
|
|
386
|
+
const newVersion = await getLatestVersion(pkgName);
|
|
387
|
+
if (!oldVersion) {
|
|
388
|
+
console.log(chalk.yellow(`未检测到全局安装的 ${pkgName}`));
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if (oldVersion !== newVersion) {
|
|
392
|
+
const message = `
|
|
393
|
+
${chalk.bold('Update available!')} ${chalk.red(oldVersion)} ${chalk.white('→')} ${chalk.green(newVersion)}.
|
|
394
|
+
${chalk.magenta('Changelog:')} ${chalk.cyan(`https://npmjs.com/package/${pkgName}/v/${newVersion}`)}
|
|
395
|
+
To update, run: ${chalk.magenta(`npm i -g ${pkgName}`)}
|
|
396
|
+
`.trim();
|
|
397
|
+
console.log(boxen(message, {
|
|
398
|
+
padding: 1,
|
|
399
|
+
margin: 1,
|
|
400
|
+
borderStyle: 'round',
|
|
401
|
+
borderColor: 'yellowBright',
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
329
406
|
var libs = /*#__PURE__*/Object.freeze({
|
|
330
407
|
__proto__: null,
|
|
331
408
|
centerQRCode: centerQRCode,
|
|
409
|
+
checkUpdate: checkUpdate,
|
|
332
410
|
getDesktopPath: getDesktopPath,
|
|
333
411
|
getLocalIP: getLocalIP,
|
|
334
412
|
openUrl: openUrl
|
|
@@ -676,6 +754,79 @@ function requireBundle () {
|
|
|
676
754
|
var bundleExports = requireBundle();
|
|
677
755
|
var index = /*@__PURE__*/getDefaultExportFromCjs(bundleExports);
|
|
678
756
|
|
|
757
|
+
const CONFIG_DIR = path.join(os.homedir(), '.ttmg-cli');
|
|
758
|
+
path.join(CONFIG_DIR, 'config.json');
|
|
759
|
+
/**
|
|
760
|
+
* 获取 Client Key(选择或输入)
|
|
761
|
+
*/
|
|
762
|
+
function getClientKey() {
|
|
763
|
+
/**
|
|
764
|
+
* 读取 project.config.json 中的 appid/appId
|
|
765
|
+
*/
|
|
766
|
+
const projectConfigPath = path.join(process.cwd(), 'project.config.json');
|
|
767
|
+
let clientKey;
|
|
768
|
+
try {
|
|
769
|
+
const projectConfig = JSON.parse(fs.readFileSync(projectConfigPath, 'utf-8'));
|
|
770
|
+
clientKey = projectConfig.appid || projectConfig.appId;
|
|
771
|
+
}
|
|
772
|
+
catch (e) {
|
|
773
|
+
console.log('read project.config.json failed', e);
|
|
774
|
+
clientKey = '';
|
|
775
|
+
}
|
|
776
|
+
if (clientKey) {
|
|
777
|
+
return clientKey;
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
console.log(chalk.red.bold('No appid found in project.config.json, you should provide it in project.config.json'));
|
|
781
|
+
process.exit(1);
|
|
782
|
+
}
|
|
783
|
+
// const keys = readClientKeys();
|
|
784
|
+
// if (keys.length > 0) {
|
|
785
|
+
// // 有历史 key,展示选择框
|
|
786
|
+
// const { selectedKey } = await inquirer.prompt([
|
|
787
|
+
// {
|
|
788
|
+
// type: 'list',
|
|
789
|
+
// name: 'selectedKey',
|
|
790
|
+
// message: 'Please select your game id(client_key):',
|
|
791
|
+
// choices: [...keys, new inquirer.Separator(), 'Add new game id'],
|
|
792
|
+
// },
|
|
793
|
+
// ]);
|
|
794
|
+
// if (selectedKey === 'Add new game id') {
|
|
795
|
+
// // 输入新 key
|
|
796
|
+
// const { newKey } = await inquirer.prompt([
|
|
797
|
+
// {
|
|
798
|
+
// type: 'input',
|
|
799
|
+
// name: 'newKey',
|
|
800
|
+
// message: 'Please input your new game id(client_key):',
|
|
801
|
+
// validate: (input: string) => (input ? true : 'Please input game id'),
|
|
802
|
+
// },
|
|
803
|
+
// ]);
|
|
804
|
+
// saveClientKey(newKey);
|
|
805
|
+
// clientKey = newKey;
|
|
806
|
+
// } else {
|
|
807
|
+
// clientKey = selectedKey;
|
|
808
|
+
// }
|
|
809
|
+
// } else {
|
|
810
|
+
// // 没有历史 key,让用户输入
|
|
811
|
+
// const { newKey } = await inquirer.prompt([
|
|
812
|
+
// {
|
|
813
|
+
// type: 'input',
|
|
814
|
+
// name: 'newKey',
|
|
815
|
+
// message: 'Please input your game id(client_key):',
|
|
816
|
+
// validate: (input: string) => (input ? true : 'Please input game id'),
|
|
817
|
+
// },
|
|
818
|
+
// ]);
|
|
819
|
+
// saveClientKey(newKey);
|
|
820
|
+
// clientKey = newKey;
|
|
821
|
+
// }
|
|
822
|
+
// return clientKey;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
function getOutputDir() {
|
|
826
|
+
const clientKey = getClientKey();
|
|
827
|
+
return path.join(os.homedir(), '__TTMG__', clientKey);
|
|
828
|
+
}
|
|
829
|
+
|
|
679
830
|
class Store {
|
|
680
831
|
constructor(initialState) {
|
|
681
832
|
this.listeners = [];
|
|
@@ -746,6 +897,24 @@ async function createServer() {
|
|
|
746
897
|
app.use(express.json());
|
|
747
898
|
// 解析 FormData body
|
|
748
899
|
app.use(express.urlencoded({ extended: true }));
|
|
900
|
+
/**
|
|
901
|
+
* 支持文件访问
|
|
902
|
+
*/
|
|
903
|
+
const outputDir = getOutputDir();
|
|
904
|
+
/**
|
|
905
|
+
*
|
|
906
|
+
*/
|
|
907
|
+
app.use(express.static(outputDir));
|
|
908
|
+
/**
|
|
909
|
+
* 支持获取文件
|
|
910
|
+
*/
|
|
911
|
+
app.get('/game/files/:fileName', async (req, res) => {
|
|
912
|
+
const { fileName } = req.params;
|
|
913
|
+
res.sendFile(path.join(outputDir, fileName));
|
|
914
|
+
});
|
|
915
|
+
/**
|
|
916
|
+
* 支持文件访问
|
|
917
|
+
*/
|
|
749
918
|
/**
|
|
750
919
|
* TODO: 提供的接口供客户端进行调用,告诉 NodeServer 客户端的 host 和 port
|
|
751
920
|
*/
|
|
@@ -797,141 +966,52 @@ function closeServer() {
|
|
|
797
966
|
});
|
|
798
967
|
}
|
|
799
968
|
|
|
800
|
-
|
|
801
|
-
path.join(CONFIG_DIR, 'config.json');
|
|
802
|
-
/**
|
|
803
|
-
* 获取 Client Key(选择或输入)
|
|
804
|
-
*/
|
|
805
|
-
function getClientKey() {
|
|
806
|
-
/**
|
|
807
|
-
* 读取 project.config.json 中的 appid/appId
|
|
808
|
-
*/
|
|
809
|
-
const projectConfigPath = path.join(process.cwd(), 'project.config.json');
|
|
810
|
-
let clientKey;
|
|
811
|
-
try {
|
|
812
|
-
const projectConfig = JSON.parse(fs.readFileSync(projectConfigPath, 'utf-8'));
|
|
813
|
-
clientKey = projectConfig.appid || projectConfig.appId;
|
|
814
|
-
}
|
|
815
|
-
catch (e) {
|
|
816
|
-
clientKey = '';
|
|
817
|
-
}
|
|
818
|
-
if (clientKey) {
|
|
819
|
-
return clientKey;
|
|
820
|
-
}
|
|
821
|
-
else {
|
|
822
|
-
console.log(chalk.red.bold('No appid found in project.config.json, you should provide it in project.config.json'));
|
|
823
|
-
process.exit(1);
|
|
824
|
-
}
|
|
825
|
-
// const keys = readClientKeys();
|
|
826
|
-
// if (keys.length > 0) {
|
|
827
|
-
// // 有历史 key,展示选择框
|
|
828
|
-
// const { selectedKey } = await inquirer.prompt([
|
|
829
|
-
// {
|
|
830
|
-
// type: 'list',
|
|
831
|
-
// name: 'selectedKey',
|
|
832
|
-
// message: 'Please select your game id(client_key):',
|
|
833
|
-
// choices: [...keys, new inquirer.Separator(), 'Add new game id'],
|
|
834
|
-
// },
|
|
835
|
-
// ]);
|
|
836
|
-
// if (selectedKey === 'Add new game id') {
|
|
837
|
-
// // 输入新 key
|
|
838
|
-
// const { newKey } = await inquirer.prompt([
|
|
839
|
-
// {
|
|
840
|
-
// type: 'input',
|
|
841
|
-
// name: 'newKey',
|
|
842
|
-
// message: 'Please input your new game id(client_key):',
|
|
843
|
-
// validate: (input: string) => (input ? true : 'Please input game id'),
|
|
844
|
-
// },
|
|
845
|
-
// ]);
|
|
846
|
-
// saveClientKey(newKey);
|
|
847
|
-
// clientKey = newKey;
|
|
848
|
-
// } else {
|
|
849
|
-
// clientKey = selectedKey;
|
|
850
|
-
// }
|
|
851
|
-
// } else {
|
|
852
|
-
// // 没有历史 key,让用户输入
|
|
853
|
-
// const { newKey } = await inquirer.prompt([
|
|
854
|
-
// {
|
|
855
|
-
// type: 'input',
|
|
856
|
-
// name: 'newKey',
|
|
857
|
-
// message: 'Please input your game id(client_key):',
|
|
858
|
-
// validate: (input: string) => (input ? true : 'Please input game id'),
|
|
859
|
-
// },
|
|
860
|
-
// ]);
|
|
861
|
-
// saveClientKey(newKey);
|
|
862
|
-
// clientKey = newKey;
|
|
863
|
-
// }
|
|
864
|
-
// return clientKey;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
function getOutputDir() {
|
|
868
|
-
const clientKey = getClientKey();
|
|
869
|
-
return path.join(os.homedir(), '__TTMG__', clientKey);
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
async function uploadGame() {
|
|
969
|
+
async function uploadGame(callback) {
|
|
873
970
|
const outputDir = getOutputDir();
|
|
971
|
+
callback({
|
|
972
|
+
status: 'start',
|
|
973
|
+
percent: '0%',
|
|
974
|
+
});
|
|
874
975
|
console.log(chalk.yellow.bold('Start compress game resource'));
|
|
875
976
|
const zipPath = path.join(os.homedir(), '__TTMG__', 'upload.zip');
|
|
876
977
|
await zipDirectory(outputDir, zipPath);
|
|
877
978
|
console.log(chalk.green.bold('Compress game package resource success \n'));
|
|
878
|
-
|
|
879
|
-
return {
|
|
880
|
-
isSuccess: res?.statusCode === 200,
|
|
881
|
-
};
|
|
979
|
+
await uploadZip(zipPath, callback);
|
|
882
980
|
}
|
|
883
|
-
function zipDirectory(sourceDir, outPath) {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
output.on('close', () =>
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
});
|
|
891
|
-
output.on('error', err => {
|
|
892
|
-
// console.error('Compress directory error:', err);
|
|
893
|
-
reject(err);
|
|
894
|
-
});
|
|
895
|
-
archive.on('error', err => {
|
|
896
|
-
reject(err);
|
|
897
|
-
});
|
|
981
|
+
async function zipDirectory(sourceDir, outPath) {
|
|
982
|
+
const output = fs.createWriteStream(outPath);
|
|
983
|
+
const archive = require$$5$1('zip', { zlib: { level: 9 } });
|
|
984
|
+
return new Promise(async (resolve, reject) => {
|
|
985
|
+
output.on('close', () => resolve());
|
|
986
|
+
output.on('error', err => reject(err));
|
|
987
|
+
archive.on('error', err => reject(err));
|
|
898
988
|
archive.pipe(output);
|
|
899
|
-
|
|
900
|
-
|
|
989
|
+
try {
|
|
990
|
+
// 注意这里用 await glob.glob
|
|
991
|
+
const files = await glob__namespace.glob('**/*', {
|
|
992
|
+
cwd: sourceDir,
|
|
993
|
+
nodir: true,
|
|
994
|
+
ignore: '**/*.js.map',
|
|
995
|
+
});
|
|
996
|
+
files.forEach(file => {
|
|
997
|
+
archive.file(path.join(sourceDir, file), { name: file });
|
|
998
|
+
});
|
|
999
|
+
archive.finalize();
|
|
1000
|
+
}
|
|
1001
|
+
catch (err) {
|
|
1002
|
+
reject(err);
|
|
1003
|
+
}
|
|
901
1004
|
});
|
|
902
1005
|
}
|
|
903
|
-
|
|
904
|
-
* 上传 zip 文件到指定接口
|
|
905
|
-
* @param zipFilePath zip 文件路径
|
|
906
|
-
* @param uploadUrl 上传接口
|
|
907
|
-
*/
|
|
908
|
-
// export async function uploadZip(zipPath: string) {
|
|
909
|
-
// const form = new FormData();
|
|
910
|
-
// form.append('file', fs.createReadStream(zipPath), 'upload.zip');
|
|
911
|
-
// try {
|
|
912
|
-
// console.log(chalk.yellow.bold('Start upload resource to client'));
|
|
913
|
-
// const { clientServerHost, clientServerPort } = store.getState();
|
|
914
|
-
// const res = await axios.post(
|
|
915
|
-
// `http://${clientServerHost}:${clientServerPort}/game/upload`,
|
|
916
|
-
// form,
|
|
917
|
-
// {
|
|
918
|
-
// headers: form.getHeaders(),
|
|
919
|
-
// },
|
|
920
|
-
// );
|
|
921
|
-
// fs.unlinkSync(zipPath);
|
|
922
|
-
// return res;
|
|
923
|
-
// } catch (err: any) {
|
|
924
|
-
// console.error('Upload resource to client failed:', err.message);
|
|
925
|
-
// }
|
|
926
|
-
// }
|
|
927
|
-
// 使用 require 语法,完全兼容 CommonJS
|
|
928
|
-
async function uploadZip(zipPath) {
|
|
1006
|
+
async function uploadZip(zipPath, callback) {
|
|
929
1007
|
const form = new FormData();
|
|
930
1008
|
form.append('file', fs.createReadStream(zipPath), {
|
|
931
1009
|
filename: 'upload.zip',
|
|
932
1010
|
contentType: 'application/zip',
|
|
933
1011
|
});
|
|
934
|
-
|
|
1012
|
+
// 帮我计算下文件大小,变成 MB 为单位
|
|
1013
|
+
const fileSize = fs.statSync(zipPath).size / 1024 / 1024;
|
|
1014
|
+
console.log(chalk.yellow.bold(`Start upload resource to client, size: ${fileSize.toFixed(2)} MB`));
|
|
935
1015
|
const { clientServerHost, clientServerPort } = store.getState();
|
|
936
1016
|
const url = `http://${clientServerHost}:${clientServerPort}/game/upload`;
|
|
937
1017
|
try {
|
|
@@ -942,12 +1022,12 @@ async function uploadZip(zipPath) {
|
|
|
942
1022
|
// 2. 监听上传进度 (这个回调是并行的,不影响封装)
|
|
943
1023
|
stream.on('uploadProgress', progress => {
|
|
944
1024
|
const percent = (progress.percent * 100).toFixed(1);
|
|
945
|
-
const transferred = progress.transferred;
|
|
946
|
-
const total = progress.total;
|
|
1025
|
+
// const transferred = progress.transferred;
|
|
1026
|
+
// const total = progress.total;
|
|
947
1027
|
process.stdout.write(`\r${chalk.cyan('Uploading progress: ')}${chalk.green(percent + '%')}`);
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1028
|
+
callback({
|
|
1029
|
+
status: 'process',
|
|
1030
|
+
percent: `${percent}%`,
|
|
951
1031
|
});
|
|
952
1032
|
});
|
|
953
1033
|
// 3. 【核心封装】将流的处理过程包装在 Promise 中
|
|
@@ -964,6 +1044,10 @@ async function uploadZip(zipPath) {
|
|
|
964
1044
|
// const responseBody = Buffer.concat(chunks).toString('utf-8');
|
|
965
1045
|
// stream.response 在流结束后才可用
|
|
966
1046
|
// 将完整的响应对象 resolve 出去
|
|
1047
|
+
callback({
|
|
1048
|
+
status: 'success',
|
|
1049
|
+
percent: '100%',
|
|
1050
|
+
});
|
|
967
1051
|
resolve({
|
|
968
1052
|
statusCode: 200,
|
|
969
1053
|
});
|
|
@@ -972,17 +1056,25 @@ async function uploadZip(zipPath) {
|
|
|
972
1056
|
stream.on('error', err => {
|
|
973
1057
|
// 将错误 reject 出去,这样外层的 try...catch 就能捕获到
|
|
974
1058
|
reject(err);
|
|
1059
|
+
callback({
|
|
1060
|
+
status: 'error',
|
|
1061
|
+
percent: '',
|
|
1062
|
+
msg: err.message,
|
|
1063
|
+
});
|
|
975
1064
|
});
|
|
976
1065
|
});
|
|
977
1066
|
// 4. 当 await 完成后,说明流已成功结束,可以安全地执行后续操作
|
|
978
1067
|
process.stdout.write('\n'); // 换行,保持终端整洁
|
|
979
1068
|
console.log(chalk.green.bold('✔ Upload completed successfully!'));
|
|
980
1069
|
fs.unlinkSync(zipPath);
|
|
981
|
-
// 5. 返回从 Promise 中解析出的响应数据
|
|
982
1070
|
return response;
|
|
983
1071
|
}
|
|
984
1072
|
catch (err) {
|
|
985
|
-
|
|
1073
|
+
callback({
|
|
1074
|
+
status: 'error',
|
|
1075
|
+
percent: '',
|
|
1076
|
+
msg: err?.message,
|
|
1077
|
+
});
|
|
986
1078
|
process.stdout.write('\n');
|
|
987
1079
|
if (err.response) {
|
|
988
1080
|
console.error(chalk.red.bold('✖ Upload failed with server error:'), {
|
|
@@ -1008,27 +1100,31 @@ class WsServer {
|
|
|
1008
1100
|
if (from === 'browser') {
|
|
1009
1101
|
const method = clientMessage.method;
|
|
1010
1102
|
switch (method) {
|
|
1011
|
-
case '
|
|
1103
|
+
case 'startUpload':
|
|
1012
1104
|
this.sendUploadStatus('start');
|
|
1013
|
-
uploadGame()
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
isSuccess: res.isSuccess,
|
|
1105
|
+
uploadGame(({ status, percent, msg }) => {
|
|
1106
|
+
if (status === 'process') {
|
|
1107
|
+
this.sendUploadStatus('process', {
|
|
1108
|
+
status: 'process',
|
|
1109
|
+
progress: percent,
|
|
1019
1110
|
});
|
|
1020
1111
|
}
|
|
1021
|
-
else {
|
|
1112
|
+
else if (status === 'error') {
|
|
1022
1113
|
this.sendUploadStatus('error', {
|
|
1023
|
-
|
|
1114
|
+
status: 'error',
|
|
1115
|
+
errMsg: msg,
|
|
1116
|
+
isSuccess: false,
|
|
1117
|
+
});
|
|
1118
|
+
console.log(chalk.red.bold('Upload resource to client failed!'));
|
|
1119
|
+
}
|
|
1120
|
+
else if (status === 'success') {
|
|
1121
|
+
this.sendUploadStatus('success', {
|
|
1122
|
+
status: 'success',
|
|
1123
|
+
packages: store.getState().packages,
|
|
1124
|
+
clientKey: getClientKey(),
|
|
1125
|
+
isSuccess: true,
|
|
1024
1126
|
});
|
|
1025
1127
|
}
|
|
1026
|
-
})
|
|
1027
|
-
.catch(() => {
|
|
1028
|
-
this.sendUploadStatus('error', {
|
|
1029
|
-
isSuccess: false,
|
|
1030
|
-
});
|
|
1031
|
-
console.log(chalk.red.bold('Start upload resource to client failed!'));
|
|
1032
1128
|
});
|
|
1033
1129
|
break;
|
|
1034
1130
|
case 'closeLocalDebug':
|
|
@@ -1093,30 +1189,69 @@ class WsServer {
|
|
|
1093
1189
|
}
|
|
1094
1190
|
const wsServer = new WsServer();
|
|
1095
1191
|
|
|
1192
|
+
async function prepareResource() {
|
|
1193
|
+
console.log(chalk.yellow.bold('Start compile game for debug'));
|
|
1194
|
+
const entryDir = process.cwd();
|
|
1195
|
+
const outputDir = getOutputDir();
|
|
1196
|
+
if (!fs.existsSync(outputDir)) {
|
|
1197
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
1198
|
+
}
|
|
1199
|
+
const { isSuccess, errorMsg, packages } = await ttmgPack.debugPkgs({
|
|
1200
|
+
entry: entryDir,
|
|
1201
|
+
output: outputDir,
|
|
1202
|
+
dev: {
|
|
1203
|
+
enable: true,
|
|
1204
|
+
port: DEV_PORT,
|
|
1205
|
+
host: 'localhost',
|
|
1206
|
+
enableSourcemap: true,
|
|
1207
|
+
enableLog: false,
|
|
1208
|
+
},
|
|
1209
|
+
build: {
|
|
1210
|
+
pkgSizeLimit: 30 * 1024 * 1024,
|
|
1211
|
+
mainPkgSizeLimit: 4 * 1024 * 1024,
|
|
1212
|
+
},
|
|
1213
|
+
});
|
|
1214
|
+
if (!isSuccess) {
|
|
1215
|
+
console.log(chalk.redBright('Build game package failed, Please check the error message below:'));
|
|
1216
|
+
console.log(chalk.redBright(errorMsg));
|
|
1217
|
+
process.exit(1);
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
store.setState({
|
|
1221
|
+
packages,
|
|
1222
|
+
});
|
|
1223
|
+
console.log(chalk.green.bold('Compile game package success \n'));
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// import { uploadGame } from './uploadGame';
|
|
1096
1228
|
async function watchChange() {
|
|
1097
1229
|
let debounceTimer = null;
|
|
1098
1230
|
fs.watch(process.cwd(), (eventType, filename) => {
|
|
1099
|
-
console.log(chalk.yellow('game resource change, restart to upload'));
|
|
1100
1231
|
// 清除之前的定时器
|
|
1101
1232
|
if (debounceTimer)
|
|
1102
1233
|
clearTimeout(debounceTimer);
|
|
1103
1234
|
// 重新设置定时器
|
|
1104
1235
|
debounceTimer = setTimeout(async () => {
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
wsServer.sendUploadStatus('success');
|
|
1110
|
-
}
|
|
1111
|
-
else {
|
|
1112
|
-
wsServer.sendUploadStatus('error', {
|
|
1113
|
-
errMsg: res.errorMsg,
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
1116
|
-
})
|
|
1117
|
-
.catch(() => {
|
|
1118
|
-
wsServer.sendUploadStatus('error');
|
|
1236
|
+
console.log(chalk.yellow('game resource change, restart to upload'));
|
|
1237
|
+
await prepareResource();
|
|
1238
|
+
wsServer.send({
|
|
1239
|
+
method: 'resourceChange',
|
|
1119
1240
|
});
|
|
1241
|
+
// TODO:只做文件预准备,但不主动上传
|
|
1242
|
+
// uploadGame()
|
|
1243
|
+
// .then((res) => {
|
|
1244
|
+
// if (res.isSuccess) {
|
|
1245
|
+
// wsServer.sendUploadStatus('success');
|
|
1246
|
+
// } else {
|
|
1247
|
+
// wsServer.sendUploadStatus('error', {
|
|
1248
|
+
// errMsg: res.errorMsg,
|
|
1249
|
+
// });
|
|
1250
|
+
// }
|
|
1251
|
+
// })
|
|
1252
|
+
// .catch(() => {
|
|
1253
|
+
// wsServer.sendUploadStatus('error');
|
|
1254
|
+
// });
|
|
1120
1255
|
debounceTimer = null;
|
|
1121
1256
|
}, 500); // 500ms内只执行一次
|
|
1122
1257
|
});
|
|
@@ -1138,30 +1273,6 @@ async function showSchema() {
|
|
|
1138
1273
|
});
|
|
1139
1274
|
}
|
|
1140
1275
|
|
|
1141
|
-
async function prepareResource() {
|
|
1142
|
-
console.log(chalk.yellow.bold('Start compile game for debug'));
|
|
1143
|
-
const entryDir = process.cwd();
|
|
1144
|
-
const outputDir = getOutputDir();
|
|
1145
|
-
if (!fs.existsSync(outputDir)) {
|
|
1146
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
1147
|
-
}
|
|
1148
|
-
const { isSuccess, errorMsg, packages } = await ttmgPack.debugPkgs({
|
|
1149
|
-
entry: entryDir,
|
|
1150
|
-
output: outputDir,
|
|
1151
|
-
});
|
|
1152
|
-
if (!isSuccess) {
|
|
1153
|
-
console.log(chalk.redBright('Build game package failed, Please check the error message below:'));
|
|
1154
|
-
console.log(chalk.redBright(errorMsg));
|
|
1155
|
-
process.exit(1);
|
|
1156
|
-
}
|
|
1157
|
-
else {
|
|
1158
|
-
store.setState({
|
|
1159
|
-
packages,
|
|
1160
|
-
});
|
|
1161
|
-
console.log(chalk.green.bold('Compile game package success \n'));
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
1276
|
async function dev() {
|
|
1166
1277
|
/**
|
|
1167
1278
|
* 1. 准备游戏资源
|
|
@@ -1181,11 +1292,17 @@ async function dev() {
|
|
|
1181
1292
|
await watchChange();
|
|
1182
1293
|
}
|
|
1183
1294
|
|
|
1184
|
-
var version = "0.1.
|
|
1295
|
+
var version = "0.1.1-beta.1";
|
|
1185
1296
|
var pkg = {
|
|
1186
1297
|
version: version};
|
|
1187
1298
|
|
|
1188
1299
|
const program = new commander.Command();
|
|
1300
|
+
(async () => {
|
|
1301
|
+
try {
|
|
1302
|
+
await checkUpdate();
|
|
1303
|
+
}
|
|
1304
|
+
catch (err) { }
|
|
1305
|
+
})();
|
|
1189
1306
|
program
|
|
1190
1307
|
.name('ttmg')
|
|
1191
1308
|
.description('TikTok Mini Games Command Line Tool')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttmg/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1-beta.1",
|
|
4
4
|
"description": "TikTok Mini Game Command Line Tool",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"bin": {
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"prepublish": "npm run build",
|
|
14
14
|
"build": "rollup -c",
|
|
15
15
|
"watch": "rollup -c -w",
|
|
16
|
-
"perf": "rollup -c --perf"
|
|
16
|
+
"perf": "rollup -c --perf",
|
|
17
|
+
"dev": "ts-node -r tsconfig-paths/register src/index.ts"
|
|
17
18
|
},
|
|
18
19
|
"keywords": [
|
|
19
20
|
"TTMG",
|
|
20
|
-
"
|
|
21
|
-
"Mini Game"
|
|
21
|
+
"Mini Games"
|
|
22
22
|
],
|
|
23
23
|
"author": "zhanghongyang.mocha",
|
|
24
24
|
"dependencies": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"estraverse": "^5.3.0",
|
|
35
35
|
"express": "^5.1.0",
|
|
36
36
|
"form-data": "^4.0.4",
|
|
37
|
+
"glob": "^11.0.3",
|
|
37
38
|
"got": "^11.8.5",
|
|
38
39
|
"inquirer": "^12.7.0",
|
|
39
40
|
"jsdom": "^26.1.0",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"open": "^10.2.0",
|
|
42
43
|
"prettier": "^3.6.2",
|
|
43
44
|
"qrcode-terminal": "^0.12.0",
|
|
44
|
-
"ttmg-pack": "0.0.
|
|
45
|
+
"ttmg-pack": "0.0.22",
|
|
45
46
|
"ws": "^8.18.3"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
@@ -59,6 +60,8 @@
|
|
|
59
60
|
"eslint": "^9.31.0",
|
|
60
61
|
"rollup": "^4.46.4",
|
|
61
62
|
"rollup-plugin-visualizer": "^6.0.3",
|
|
63
|
+
"ts-node": "^10.9.2",
|
|
64
|
+
"tsconfig-paths": "^4.2.0",
|
|
62
65
|
"typescript": "^5.9.2"
|
|
63
66
|
},
|
|
64
67
|
"engines": {
|