@maoyugames/phaser-framework 1.0.5 → 1.0.7

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/dist/cli/index.js CHANGED
@@ -3,7 +3,7 @@ import '../chunk-PKBMQBKP.js';
3
3
  import pc6 from 'picocolors';
4
4
  import { resolve, join, extname, relative, basename, dirname } from 'path';
5
5
  import { randomBytes } from 'crypto';
6
- import fse4 from 'fs-extra';
6
+ import fse from 'fs-extra';
7
7
  import { createRequire } from 'module';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { existsSync, mkdirSync, writeFileSync, readFile, readFileSync } from 'fs';
@@ -461,6 +461,74 @@ export default config;
461
461
  `;
462
462
  }
463
463
 
464
+ // src/cli/shells/tiktok.ts
465
+ var DEFAULT_SDK_URL = "https://connect.tiktok-minis.com/game/sdk.js";
466
+ function renderTikTokHtml(cfg, scriptSrc) {
467
+ const title = escapeHtml(cfg?.title ?? "TikTok Mini Game");
468
+ const sdkUrl = cfg?.sdkUrl ?? DEFAULT_SDK_URL;
469
+ const clientKey = cfg?.clientKey ?? "";
470
+ const sdkTag = sdkUrl ? `<!--
471
+ TikTok Mini Games(Minis)SDK \u6CE8\u5165:\u5FC5\u987B\u5728 <head> \u4E2D\u3001\u7D27\u8DDF\u5176\u540E\u4E00\u4E2A init \u8C03\u7528,
472
+ \u5BA1\u6838\u811A\u672C\u6309\u6B64 pattern \u68C0\u6D4B;\u8BE6\u89C1 @ttmg/cli \u7684 init \u6D41\u7A0B\u3002
473
+ -->
474
+ <script src="${escapeAttr(sdkUrl)}"></script>` : "";
475
+ const initTag = sdkUrl ? `<script>
476
+ window.TTMinis = TTMinis;
477
+ TTMinis.game.init({ clientKey: "${escapeAttr(clientKey)}" });
478
+ try { TTMinis.game.setLoadingProgress({ progress: 100 }); } catch (e) {}
479
+ try { TTMinis.game.setLoadingProgress(function () {}, { progress: 100 }); } catch (e) {}
480
+ </script>` : "";
481
+ return `<!doctype html>
482
+ <html lang="en">
483
+ <head>
484
+ <meta charset="UTF-8" />
485
+ <meta
486
+ name="viewport"
487
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
488
+ />
489
+ <title>${title}</title>
490
+ ${sdkTag}
491
+ ${initTag}
492
+ <style>
493
+ html,
494
+ body {
495
+ margin: 0;
496
+ padding: 0;
497
+ width: 100%;
498
+ height: 100%;
499
+ background: #000;
500
+ overflow: hidden;
501
+ box-sizing: border-box;
502
+ }
503
+ #game-root {
504
+ width: 100%;
505
+ height: 100%;
506
+ }
507
+ #game-root canvas {
508
+ display: block;
509
+ margin: 0 auto;
510
+ }
511
+ </style>
512
+ </head>
513
+ <body>
514
+ <!-- \u6E38\u620F\u753B\u5E03\u6302\u8F7D\u70B9 -->
515
+ <div id="game-root"></div>
516
+ <!-- TikTok \u5E73\u53F0\u5165\u53E3:\u4EC5\u9759\u6001 import TikTok \u9002\u914D\u5668 -->
517
+ <script type="module" src="${scriptSrc}"></script>
518
+ </body>
519
+ </html>
520
+ `;
521
+ }
522
+ function renderTikTokMinigameConfig(cfg) {
523
+ const orientation = (cfg?.orientation ?? "portrait").toLowerCase() === "landscape" ? "HORIZONTAL" : "VERTICAL";
524
+ const obj = {
525
+ _comment: "orientation is the orientation of the game. It can be either 'VERTICAL' or 'HORIZONTAL'. our game default is VERTICAL; minigame.config.json dev is a configuration file for minigame development. You can use it to configure the minigame.",
526
+ orientation,
527
+ dev: { port: 9527 }
528
+ };
529
+ return JSON.stringify(obj, null, 2) + "\n";
530
+ }
531
+
464
532
  // src/cli/shells/wechat.ts
465
533
  function renderGameJs() {
466
534
  return `/**
@@ -531,14 +599,32 @@ function renderWeChatShells(cfg) {
531
599
  }
532
600
 
533
601
  // src/cli/inject.ts
602
+ function removeEmptyFiles(dir) {
603
+ const removed = [];
604
+ const walk = (cur) => {
605
+ if (!fse.existsSync(cur)) return;
606
+ for (const name of fse.readdirSync(cur)) {
607
+ const full = join(cur, name);
608
+ const st = fse.statSync(full);
609
+ if (st.isDirectory()) {
610
+ walk(full);
611
+ } else if (st.size === 0) {
612
+ fse.removeSync(full);
613
+ removed.push(full);
614
+ }
615
+ }
616
+ };
617
+ walk(dir);
618
+ return removed;
619
+ }
534
620
  function wechatVendorDirs(projectRoot) {
535
621
  return [resolve(projectRoot, "wechat/vendor"), resolve(projectRoot, "platforms/wechat/vendor")];
536
622
  }
537
623
  function writeShellFiles(distDir, projectRoot, files) {
538
624
  for (const f of files) {
539
625
  const dst = join(distDir, f.relPath);
540
- fse4.ensureDirSync(resolve(dst, ".."));
541
- fse4.writeFileSync(dst, f.content, "utf-8");
626
+ fse.ensureDirSync(resolve(dst, ".."));
627
+ fse.writeFileSync(dst, f.content, "utf-8");
542
628
  console.log(pc6.green(` \u2713 ${f.relPath} \u2192 ${relative(projectRoot, dst)}`));
543
629
  }
544
630
  }
@@ -546,8 +632,23 @@ function injectShell(opts) {
546
632
  const { platform, projectRoot, distDir, config } = opts;
547
633
  switch (platform) {
548
634
  case "web":
549
- case "tiktok":
550
635
  return true;
636
+ case "tiktok": {
637
+ console.log(pc6.cyan(` \u25B6 [tiktok] \u6CE8\u5165 minigame.config.json + \u6E05\u7406\u7A7A\u6587\u4EF6`));
638
+ writeShellFiles(distDir, projectRoot, [
639
+ { relPath: "minigame.config.json", content: renderTikTokMinigameConfig(config.tiktok) }
640
+ ]);
641
+ const removed = removeEmptyFiles(distDir);
642
+ if (removed.length > 0) {
643
+ console.log(pc6.gray(` \u6E05\u7406 ${removed.length} \u4E2A\u7A7A\u6587\u4EF6: ${removed.map((p) => relative(distDir, p)).join(", ")}`));
644
+ }
645
+ if (!config.tiktok?.clientKey) {
646
+ console.log(pc6.yellow(pc6.bold(" \u26A0 platform.config.tiktok.clientKey \u672A\u914D\u7F6E")));
647
+ console.log(pc6.yellow(' index.html \u5DF2\u6CE8\u5165 TTMinis.game.init({clientKey: ""}),\u63D0\u5BA1\u4F1A\u88AB\u62D2\u3002'));
648
+ console.log(pc6.yellow(" \u8BF7\u5728 platform.config.ts \u7684 tiktok \u6BB5\u586B clientKey(\u5F00\u53D1\u8005\u540E\u53F0\u62FF)\u3002"));
649
+ }
650
+ return true;
651
+ }
551
652
  case "facebook": {
552
653
  console.log(pc6.cyan(` \u25B6 [facebook] \u6CE8\u5165\u5916\u58F3\u6587\u4EF6`));
553
654
  writeShellFiles(distDir, projectRoot, [renderFacebookAppConfig(config.facebook)]);
@@ -556,7 +657,7 @@ function injectShell(opts) {
556
657
  case "capacitor": {
557
658
  console.log(pc6.cyan(` \u25B6 [capacitor] \u751F\u6210 capacitor.config.ts(\u9879\u76EE\u6839)`));
558
659
  const capCfgPath = resolve(projectRoot, "capacitor.config.ts");
559
- fse4.writeFileSync(capCfgPath, renderCapacitorConfig(config.capacitor), "utf-8");
660
+ fse.writeFileSync(capCfgPath, renderCapacitorConfig(config.capacitor), "utf-8");
560
661
  console.log(pc6.green(` \u2713 capacitor.config.ts \u2192 ${relative(projectRoot, capCfgPath)}`));
561
662
  return true;
562
663
  }
@@ -573,22 +674,22 @@ function injectShell(opts) {
573
674
  }
574
675
  function copyPublicAssetsToWechat(projectRoot, distDir) {
575
676
  const srcPublic = resolve(projectRoot, "src/game/public");
576
- if (!fse4.existsSync(srcPublic)) return;
677
+ if (!fse.existsSync(srcPublic)) return;
577
678
  console.log(pc6.cyan(" \u25B6 [wechat] \u62F7\u8D1D\u4E1A\u52A1\u9759\u6001\u8D44\u6E90(src/game/public)"));
578
- fse4.copySync(srcPublic, distDir);
679
+ fse.copySync(srcPublic, distDir);
579
680
  console.log(pc6.green(" \u2713 src/game/public/* \u2192 dist/wechat/"));
580
681
  }
581
682
  function copyWechatVendor(projectRoot, distDir) {
582
683
  console.log(pc6.cyan(" \u25B6 [wechat] \u68C0\u6D4B\u5FAE\u4FE1\u9002\u914D\u5668(vendor)"));
583
684
  const dirs = wechatVendorDirs(projectRoot);
584
- const adapter = dirs.map((d) => join(d, "weapp-adapter.js")).find((p) => fse4.existsSync(p));
685
+ const adapter = dirs.map((d) => join(d, "weapp-adapter.js")).find((p) => fse.existsSync(p));
585
686
  if (adapter) {
586
- fse4.copyFileSync(adapter, join(distDir, "weapp-adapter.js"));
687
+ fse.copyFileSync(adapter, join(distDir, "weapp-adapter.js"));
587
688
  console.log(pc6.green(" \u2713 weapp-adapter.js \u2192 dist/wechat/weapp-adapter.js"));
588
689
  const vendorDir = resolve(adapter, "..");
589
690
  const symbol = join(vendorDir, "symbol.js");
590
- if (fse4.existsSync(symbol)) {
591
- fse4.copyFileSync(symbol, join(distDir, "symbol.js"));
691
+ if (fse.existsSync(symbol)) {
692
+ fse.copyFileSync(symbol, join(distDir, "symbol.js"));
592
693
  console.log(pc6.green(" \u2713 symbol.js \u2192 dist/wechat/symbol.js"));
593
694
  }
594
695
  return true;
@@ -610,10 +711,10 @@ function copyWechatVendor(projectRoot, distDir) {
610
711
  }
611
712
  function listFiles(dir) {
612
713
  const out = [];
613
- if (!fse4.existsSync(dir)) return out;
614
- for (const name of fse4.readdirSync(dir)) {
714
+ if (!fse.existsSync(dir)) return out;
715
+ for (const name of fse.readdirSync(dir)) {
615
716
  const full = join(dir, name);
616
- const st = fse4.statSync(full);
717
+ const st = fse.statSync(full);
617
718
  if (st.isDirectory()) out.push(...listFiles(full));
618
719
  else out.push({ path: full, size: st.size });
619
720
  }
@@ -627,7 +728,7 @@ function findMainBundle(files) {
627
728
  return jsFiles.reduce((max, f) => f.size > max.size ? f : max, jsFiles[0]);
628
729
  }
629
730
  function checkPlatform(platform, distDir) {
630
- if (!fse4.existsSync(distDir)) {
731
+ if (!fse.existsSync(distDir)) {
631
732
  console.log(pc6.gray(` [${platform}] \u672A\u6784\u5EFA,\u8DF3\u8FC7`));
632
733
  return true;
633
734
  }
@@ -700,10 +801,10 @@ function invalidTarget(target) {
700
801
  }
701
802
  function collectJsFiles(dir) {
702
803
  const out = [];
703
- if (!fse4.existsSync(dir)) return out;
704
- for (const name of fse4.readdirSync(dir)) {
804
+ if (!fse.existsSync(dir)) return out;
805
+ for (const name of fse.readdirSync(dir)) {
705
806
  const full = join(dir, name);
706
- const st = fse4.statSync(full);
807
+ const st = fse.statSync(full);
707
808
  if (st.isDirectory()) out.push(...collectJsFiles(full));
708
809
  else if (/\.(js|mjs|cjs)$/i.test(name)) out.push(full);
709
810
  }
@@ -716,7 +817,7 @@ function snippetAround(text, index, span = 60) {
716
817
  }
717
818
  function verifyPlatform(platform, distDir, projectRoot) {
718
819
  const rules = ISOLATION_RULES[platform];
719
- if (!fse4.existsSync(distDir)) {
820
+ if (!fse.existsSync(distDir)) {
720
821
  console.log(pc6.gray(` [${platform}] \u672A\u6784\u5EFA(${relative(projectRoot, distDir)} \u4E0D\u5B58\u5728),\u8DF3\u8FC7`));
721
822
  return 0;
722
823
  }
@@ -727,7 +828,7 @@ function verifyPlatform(platform, distDir, projectRoot) {
727
828
  }
728
829
  let hits = 0;
729
830
  for (const file of files) {
730
- const text = fse4.readFileSync(file, "utf-8");
831
+ const text = fse.readFileSync(file, "utf-8");
731
832
  for (const sig of rules.forbidden) {
732
833
  let from = 0;
733
834
  let idx = text.indexOf(sig, from);
@@ -833,58 +934,6 @@ function renderWebHtml(cfg, scriptSrc) {
833
934
  `;
834
935
  }
835
936
 
836
- // src/cli/shells/tiktok.ts
837
- var DEFAULT_SDK_URL = "https://developers.tiktok.com/js/minis.js";
838
- function renderTikTokHtml(cfg, scriptSrc) {
839
- const title = escapeHtml(cfg?.title ?? "TikTok Mini Game");
840
- const sdkUrl = cfg?.sdkUrl ?? DEFAULT_SDK_URL;
841
- const sdkTag = sdkUrl ? `<!--
842
- TikTok Mini Games(Minis)SDK \u6CE8\u5165(\u5730\u5740\u6765\u81EA platform.config.tiktok.sdkUrl)\u3002
843
- \u5FC5\u987B\u5728\u6E38\u620F\u811A\u672C\u4E4B\u524D\u52A0\u8F7D,\u8FD0\u884C\u65F6\u901A\u8FC7\u5168\u5C40 TTMinis.game.* \u8C03\u7528\u6865\u63A5\u80FD\u529B\u3002
844
- -->
845
- <script src="${escapeAttr(sdkUrl)}"></script>` : "";
846
- return `<!doctype html>
847
- <html lang="en">
848
- <head>
849
- <meta charset="UTF-8" />
850
- <meta
851
- name="viewport"
852
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
853
- />
854
- <title>${title}</title>
855
- <style>
856
- html,
857
- body {
858
- margin: 0;
859
- padding: 0;
860
- width: 100%;
861
- height: 100%;
862
- background: #000;
863
- overflow: hidden;
864
- box-sizing: border-box;
865
- }
866
- #game-root {
867
- width: 100%;
868
- height: 100%;
869
- }
870
- #game-root canvas {
871
- display: block;
872
- margin: 0 auto;
873
- }
874
- </style>
875
- </head>
876
- <body>
877
- ${sdkTag}
878
-
879
- <!-- \u6E38\u620F\u753B\u5E03\u6302\u8F7D\u70B9 -->
880
- <div id="game-root"></div>
881
- <!-- TikTok \u5E73\u53F0\u5165\u53E3:\u4EC5\u9759\u6001 import TikTok \u9002\u914D\u5668 -->
882
- <script type="module" src="${scriptSrc}"></script>
883
- </body>
884
- </html>
885
- `;
886
- }
887
-
888
937
  // src/cli/commands/build.ts
889
938
  function cacheDir(projectRoot) {
890
939
  return resolve(projectRoot, "node_modules/.cache/pf");
@@ -905,20 +954,20 @@ function renderHtmlShell(platform, config, scriptSrc) {
905
954
  }
906
955
  function normalizeHtmlOutput(distDir) {
907
956
  const finalHtml = join(distDir, "index.html");
908
- if (fse4.existsSync(finalHtml)) return;
957
+ if (fse.existsSync(finalHtml)) return;
909
958
  const found = findFirstHtml(distDir);
910
959
  if (found) {
911
- fse4.moveSync(found, finalHtml, { overwrite: true });
960
+ fse.moveSync(found, finalHtml, { overwrite: true });
912
961
  }
913
962
  const nm = join(distDir, "node_modules");
914
- if (fse4.existsSync(nm)) {
915
- fse4.removeSync(nm);
963
+ if (fse.existsSync(nm)) {
964
+ fse.removeSync(nm);
916
965
  }
917
966
  }
918
967
  function findFirstHtml(dir) {
919
- for (const name of fse4.readdirSync(dir)) {
968
+ for (const name of fse.readdirSync(dir)) {
920
969
  const full = join(dir, name);
921
- const st = fse4.statSync(full);
970
+ const st = fse.statSync(full);
922
971
  if (st.isDirectory()) {
923
972
  const inner = findFirstHtml(full);
924
973
  if (inner) return inner;
@@ -931,11 +980,11 @@ function findFirstHtml(dir) {
931
980
  async function buildPlatform(platform, ctx, config, vite) {
932
981
  console.log(pc6.bgCyan(pc6.black(` \u6784\u5EFA\u5E73\u53F0:${platform} `)));
933
982
  const cache = cacheDir(ctx.root);
934
- fse4.ensureDirSync(cache);
983
+ fse.ensureDirSync(cache);
935
984
  const hash = randomBytes(4).toString("hex");
936
985
  const entryFileName = `main.${platform}.${hash}.ts`;
937
986
  const entryPath = join(cache, entryFileName);
938
- fse4.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
987
+ fse.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
939
988
  const tempFiles = [entryPath];
940
989
  const distDir = resolve(ctx.root, "dist", platform);
941
990
  try {
@@ -945,7 +994,7 @@ async function buildPlatform(platform, ctx, config, vite) {
945
994
  } else {
946
995
  const htmlName = `index.${platform}.${hash}.html`;
947
996
  const htmlPath = join(cache, htmlName);
948
- fse4.writeFileSync(htmlPath, renderHtmlShell(platform, config, `./${entryFileName}`), "utf-8");
997
+ fse.writeFileSync(htmlPath, renderHtmlShell(platform, config, `./${entryFileName}`), "utf-8");
949
998
  tempFiles.push(htmlPath);
950
999
  inputFile = htmlPath;
951
1000
  }
@@ -982,7 +1031,7 @@ async function buildPlatform(platform, ctx, config, vite) {
982
1031
  } finally {
983
1032
  for (const f of tempFiles) {
984
1033
  try {
985
- fse4.removeSync(f);
1034
+ fse.removeSync(f);
986
1035
  } catch {
987
1036
  }
988
1037
  }
@@ -1054,15 +1103,15 @@ async function runDev(target) {
1054
1103
  const cache = cacheDir2(ctx.root);
1055
1104
  const hash = randomBytes(4).toString("hex");
1056
1105
  const runDir = join(cache, `dev-${platform}-${hash}`);
1057
- fse4.ensureDirSync(runDir);
1106
+ fse.ensureDirSync(runDir);
1058
1107
  const entryFileName = `main.${platform}.ts`;
1059
1108
  const entryPath = join(runDir, entryFileName);
1060
1109
  const htmlPath = join(runDir, "index.html");
1061
- fse4.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
1062
- fse4.writeFileSync(htmlPath, renderHtmlShell2(platform, config, `./${entryFileName}`), "utf-8");
1110
+ fse.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
1111
+ fse.writeFileSync(htmlPath, renderHtmlShell2(platform, config, `./${entryFileName}`), "utf-8");
1063
1112
  const cleanup = () => {
1064
1113
  try {
1065
- fse4.removeSync(runDir);
1114
+ fse.removeSync(runDir);
1066
1115
  } catch {
1067
1116
  }
1068
1117
  };
@@ -1353,7 +1402,7 @@ function runCap(action, platform) {
1353
1402
  if (action === "sync") {
1354
1403
  console.log(pc6.cyan(pc6.bold("\u25B6 Capacitor sync")));
1355
1404
  const distDir = resolve(ctx.root, "dist", "capacitor");
1356
- if (!fse4.existsSync(distDir)) {
1405
+ if (!fse.existsSync(distDir)) {
1357
1406
  console.log(pc6.red("\u2717 dist/capacitor \u4E0D\u5B58\u5728"));
1358
1407
  console.log(pc6.yellow(" \u8BF7\u5148\u6784\u5EFA:pf build capacitor"));
1359
1408
  return false;
package/dist/index.d.ts CHANGED
@@ -1757,11 +1757,20 @@ interface WebPlatformConfig {
1757
1757
  }
1758
1758
  /** TikTok Mini Games 平台配置 */
1759
1759
  interface TikTokPlatformConfig {
1760
- /** TikTok 小游戏 SDK 脚本地址(注入 index.html) */
1760
+ /**
1761
+ * TikTok 小游戏 SDK 脚本地址(注入 index.html <head> 第一个 script)。
1762
+ * 不填用默认 https://connect.tiktok-minis.com/game/sdk.js(TikTok 现行 SDK URL);
1763
+ * 旧的 https://developers.tiktok.com/js/minis.js 已不被审核脚本识别,出现 "JSSDK missing" 报错。
1764
+ */
1761
1765
  sdkUrl?: string;
1766
+ /**
1767
+ * TikTok 开发者后台拿的 client_key(等同 app_id),会注入 index.html 调用
1768
+ * `TTMinis.game.init({clientKey})`。审核脚本按此 pattern 检测,必填才能过审。
1769
+ */
1770
+ clientKey?: string;
1762
1771
  /** 页面标题 */
1763
1772
  title?: string;
1764
- /** 屏幕方向 */
1773
+ /** 屏幕方向(VERTICAL/HORIZONTAL,写入 minigame.config.json;不填默认 VERTICAL) */
1765
1774
  orientation?: Orientation;
1766
1775
  /** 业务后端基址(覆盖 common.apiBaseURL) */
1767
1776
  apiBaseURL?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maoyugames/phaser-framework",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "多平台 Phaser 游戏框架:业务/底层分离,HTTP/WebSocket/KCP,Web/TikTok/微信/Facebook/App 隔离打包",
5
5
  "type": "module",
6
6
  "license": "MIT",