@maoyugames/phaser-framework 1.0.5 → 1.0.6

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,72 @@ 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
+ </script>` : "";
479
+ return `<!doctype html>
480
+ <html lang="en">
481
+ <head>
482
+ <meta charset="UTF-8" />
483
+ <meta
484
+ name="viewport"
485
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
486
+ />
487
+ <title>${title}</title>
488
+ ${sdkTag}
489
+ ${initTag}
490
+ <style>
491
+ html,
492
+ body {
493
+ margin: 0;
494
+ padding: 0;
495
+ width: 100%;
496
+ height: 100%;
497
+ background: #000;
498
+ overflow: hidden;
499
+ box-sizing: border-box;
500
+ }
501
+ #game-root {
502
+ width: 100%;
503
+ height: 100%;
504
+ }
505
+ #game-root canvas {
506
+ display: block;
507
+ margin: 0 auto;
508
+ }
509
+ </style>
510
+ </head>
511
+ <body>
512
+ <!-- \u6E38\u620F\u753B\u5E03\u6302\u8F7D\u70B9 -->
513
+ <div id="game-root"></div>
514
+ <!-- TikTok \u5E73\u53F0\u5165\u53E3:\u4EC5\u9759\u6001 import TikTok \u9002\u914D\u5668 -->
515
+ <script type="module" src="${scriptSrc}"></script>
516
+ </body>
517
+ </html>
518
+ `;
519
+ }
520
+ function renderTikTokMinigameConfig(cfg) {
521
+ const orientation = (cfg?.orientation ?? "portrait").toLowerCase() === "landscape" ? "HORIZONTAL" : "VERTICAL";
522
+ const obj = {
523
+ _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.",
524
+ orientation,
525
+ dev: { port: 9527 }
526
+ };
527
+ return JSON.stringify(obj, null, 2) + "\n";
528
+ }
529
+
464
530
  // src/cli/shells/wechat.ts
465
531
  function renderGameJs() {
466
532
  return `/**
@@ -531,14 +597,32 @@ function renderWeChatShells(cfg) {
531
597
  }
532
598
 
533
599
  // src/cli/inject.ts
600
+ function removeEmptyFiles(dir) {
601
+ const removed = [];
602
+ const walk = (cur) => {
603
+ if (!fse.existsSync(cur)) return;
604
+ for (const name of fse.readdirSync(cur)) {
605
+ const full = join(cur, name);
606
+ const st = fse.statSync(full);
607
+ if (st.isDirectory()) {
608
+ walk(full);
609
+ } else if (st.size === 0) {
610
+ fse.removeSync(full);
611
+ removed.push(full);
612
+ }
613
+ }
614
+ };
615
+ walk(dir);
616
+ return removed;
617
+ }
534
618
  function wechatVendorDirs(projectRoot) {
535
619
  return [resolve(projectRoot, "wechat/vendor"), resolve(projectRoot, "platforms/wechat/vendor")];
536
620
  }
537
621
  function writeShellFiles(distDir, projectRoot, files) {
538
622
  for (const f of files) {
539
623
  const dst = join(distDir, f.relPath);
540
- fse4.ensureDirSync(resolve(dst, ".."));
541
- fse4.writeFileSync(dst, f.content, "utf-8");
624
+ fse.ensureDirSync(resolve(dst, ".."));
625
+ fse.writeFileSync(dst, f.content, "utf-8");
542
626
  console.log(pc6.green(` \u2713 ${f.relPath} \u2192 ${relative(projectRoot, dst)}`));
543
627
  }
544
628
  }
@@ -546,8 +630,23 @@ function injectShell(opts) {
546
630
  const { platform, projectRoot, distDir, config } = opts;
547
631
  switch (platform) {
548
632
  case "web":
549
- case "tiktok":
550
633
  return true;
634
+ case "tiktok": {
635
+ console.log(pc6.cyan(` \u25B6 [tiktok] \u6CE8\u5165 minigame.config.json + \u6E05\u7406\u7A7A\u6587\u4EF6`));
636
+ writeShellFiles(distDir, projectRoot, [
637
+ { relPath: "minigame.config.json", content: renderTikTokMinigameConfig(config.tiktok) }
638
+ ]);
639
+ const removed = removeEmptyFiles(distDir);
640
+ if (removed.length > 0) {
641
+ console.log(pc6.gray(` \u6E05\u7406 ${removed.length} \u4E2A\u7A7A\u6587\u4EF6: ${removed.map((p) => relative(distDir, p)).join(", ")}`));
642
+ }
643
+ if (!config.tiktok?.clientKey) {
644
+ console.log(pc6.yellow(pc6.bold(" \u26A0 platform.config.tiktok.clientKey \u672A\u914D\u7F6E")));
645
+ console.log(pc6.yellow(' index.html \u5DF2\u6CE8\u5165 TTMinis.game.init({clientKey: ""}),\u63D0\u5BA1\u4F1A\u88AB\u62D2\u3002'));
646
+ console.log(pc6.yellow(" \u8BF7\u5728 platform.config.ts \u7684 tiktok \u6BB5\u586B clientKey(\u5F00\u53D1\u8005\u540E\u53F0\u62FF)\u3002"));
647
+ }
648
+ return true;
649
+ }
551
650
  case "facebook": {
552
651
  console.log(pc6.cyan(` \u25B6 [facebook] \u6CE8\u5165\u5916\u58F3\u6587\u4EF6`));
553
652
  writeShellFiles(distDir, projectRoot, [renderFacebookAppConfig(config.facebook)]);
@@ -556,7 +655,7 @@ function injectShell(opts) {
556
655
  case "capacitor": {
557
656
  console.log(pc6.cyan(` \u25B6 [capacitor] \u751F\u6210 capacitor.config.ts(\u9879\u76EE\u6839)`));
558
657
  const capCfgPath = resolve(projectRoot, "capacitor.config.ts");
559
- fse4.writeFileSync(capCfgPath, renderCapacitorConfig(config.capacitor), "utf-8");
658
+ fse.writeFileSync(capCfgPath, renderCapacitorConfig(config.capacitor), "utf-8");
560
659
  console.log(pc6.green(` \u2713 capacitor.config.ts \u2192 ${relative(projectRoot, capCfgPath)}`));
561
660
  return true;
562
661
  }
@@ -573,22 +672,22 @@ function injectShell(opts) {
573
672
  }
574
673
  function copyPublicAssetsToWechat(projectRoot, distDir) {
575
674
  const srcPublic = resolve(projectRoot, "src/game/public");
576
- if (!fse4.existsSync(srcPublic)) return;
675
+ if (!fse.existsSync(srcPublic)) return;
577
676
  console.log(pc6.cyan(" \u25B6 [wechat] \u62F7\u8D1D\u4E1A\u52A1\u9759\u6001\u8D44\u6E90(src/game/public)"));
578
- fse4.copySync(srcPublic, distDir);
677
+ fse.copySync(srcPublic, distDir);
579
678
  console.log(pc6.green(" \u2713 src/game/public/* \u2192 dist/wechat/"));
580
679
  }
581
680
  function copyWechatVendor(projectRoot, distDir) {
582
681
  console.log(pc6.cyan(" \u25B6 [wechat] \u68C0\u6D4B\u5FAE\u4FE1\u9002\u914D\u5668(vendor)"));
583
682
  const dirs = wechatVendorDirs(projectRoot);
584
- const adapter = dirs.map((d) => join(d, "weapp-adapter.js")).find((p) => fse4.existsSync(p));
683
+ const adapter = dirs.map((d) => join(d, "weapp-adapter.js")).find((p) => fse.existsSync(p));
585
684
  if (adapter) {
586
- fse4.copyFileSync(adapter, join(distDir, "weapp-adapter.js"));
685
+ fse.copyFileSync(adapter, join(distDir, "weapp-adapter.js"));
587
686
  console.log(pc6.green(" \u2713 weapp-adapter.js \u2192 dist/wechat/weapp-adapter.js"));
588
687
  const vendorDir = resolve(adapter, "..");
589
688
  const symbol = join(vendorDir, "symbol.js");
590
- if (fse4.existsSync(symbol)) {
591
- fse4.copyFileSync(symbol, join(distDir, "symbol.js"));
689
+ if (fse.existsSync(symbol)) {
690
+ fse.copyFileSync(symbol, join(distDir, "symbol.js"));
592
691
  console.log(pc6.green(" \u2713 symbol.js \u2192 dist/wechat/symbol.js"));
593
692
  }
594
693
  return true;
@@ -610,10 +709,10 @@ function copyWechatVendor(projectRoot, distDir) {
610
709
  }
611
710
  function listFiles(dir) {
612
711
  const out = [];
613
- if (!fse4.existsSync(dir)) return out;
614
- for (const name of fse4.readdirSync(dir)) {
712
+ if (!fse.existsSync(dir)) return out;
713
+ for (const name of fse.readdirSync(dir)) {
615
714
  const full = join(dir, name);
616
- const st = fse4.statSync(full);
715
+ const st = fse.statSync(full);
617
716
  if (st.isDirectory()) out.push(...listFiles(full));
618
717
  else out.push({ path: full, size: st.size });
619
718
  }
@@ -627,7 +726,7 @@ function findMainBundle(files) {
627
726
  return jsFiles.reduce((max, f) => f.size > max.size ? f : max, jsFiles[0]);
628
727
  }
629
728
  function checkPlatform(platform, distDir) {
630
- if (!fse4.existsSync(distDir)) {
729
+ if (!fse.existsSync(distDir)) {
631
730
  console.log(pc6.gray(` [${platform}] \u672A\u6784\u5EFA,\u8DF3\u8FC7`));
632
731
  return true;
633
732
  }
@@ -700,10 +799,10 @@ function invalidTarget(target) {
700
799
  }
701
800
  function collectJsFiles(dir) {
702
801
  const out = [];
703
- if (!fse4.existsSync(dir)) return out;
704
- for (const name of fse4.readdirSync(dir)) {
802
+ if (!fse.existsSync(dir)) return out;
803
+ for (const name of fse.readdirSync(dir)) {
705
804
  const full = join(dir, name);
706
- const st = fse4.statSync(full);
805
+ const st = fse.statSync(full);
707
806
  if (st.isDirectory()) out.push(...collectJsFiles(full));
708
807
  else if (/\.(js|mjs|cjs)$/i.test(name)) out.push(full);
709
808
  }
@@ -716,7 +815,7 @@ function snippetAround(text, index, span = 60) {
716
815
  }
717
816
  function verifyPlatform(platform, distDir, projectRoot) {
718
817
  const rules = ISOLATION_RULES[platform];
719
- if (!fse4.existsSync(distDir)) {
818
+ if (!fse.existsSync(distDir)) {
720
819
  console.log(pc6.gray(` [${platform}] \u672A\u6784\u5EFA(${relative(projectRoot, distDir)} \u4E0D\u5B58\u5728),\u8DF3\u8FC7`));
721
820
  return 0;
722
821
  }
@@ -727,7 +826,7 @@ function verifyPlatform(platform, distDir, projectRoot) {
727
826
  }
728
827
  let hits = 0;
729
828
  for (const file of files) {
730
- const text = fse4.readFileSync(file, "utf-8");
829
+ const text = fse.readFileSync(file, "utf-8");
731
830
  for (const sig of rules.forbidden) {
732
831
  let from = 0;
733
832
  let idx = text.indexOf(sig, from);
@@ -833,58 +932,6 @@ function renderWebHtml(cfg, scriptSrc) {
833
932
  `;
834
933
  }
835
934
 
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
935
  // src/cli/commands/build.ts
889
936
  function cacheDir(projectRoot) {
890
937
  return resolve(projectRoot, "node_modules/.cache/pf");
@@ -905,20 +952,20 @@ function renderHtmlShell(platform, config, scriptSrc) {
905
952
  }
906
953
  function normalizeHtmlOutput(distDir) {
907
954
  const finalHtml = join(distDir, "index.html");
908
- if (fse4.existsSync(finalHtml)) return;
955
+ if (fse.existsSync(finalHtml)) return;
909
956
  const found = findFirstHtml(distDir);
910
957
  if (found) {
911
- fse4.moveSync(found, finalHtml, { overwrite: true });
958
+ fse.moveSync(found, finalHtml, { overwrite: true });
912
959
  }
913
960
  const nm = join(distDir, "node_modules");
914
- if (fse4.existsSync(nm)) {
915
- fse4.removeSync(nm);
961
+ if (fse.existsSync(nm)) {
962
+ fse.removeSync(nm);
916
963
  }
917
964
  }
918
965
  function findFirstHtml(dir) {
919
- for (const name of fse4.readdirSync(dir)) {
966
+ for (const name of fse.readdirSync(dir)) {
920
967
  const full = join(dir, name);
921
- const st = fse4.statSync(full);
968
+ const st = fse.statSync(full);
922
969
  if (st.isDirectory()) {
923
970
  const inner = findFirstHtml(full);
924
971
  if (inner) return inner;
@@ -931,11 +978,11 @@ function findFirstHtml(dir) {
931
978
  async function buildPlatform(platform, ctx, config, vite) {
932
979
  console.log(pc6.bgCyan(pc6.black(` \u6784\u5EFA\u5E73\u53F0:${platform} `)));
933
980
  const cache = cacheDir(ctx.root);
934
- fse4.ensureDirSync(cache);
981
+ fse.ensureDirSync(cache);
935
982
  const hash = randomBytes(4).toString("hex");
936
983
  const entryFileName = `main.${platform}.${hash}.ts`;
937
984
  const entryPath = join(cache, entryFileName);
938
- fse4.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
985
+ fse.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
939
986
  const tempFiles = [entryPath];
940
987
  const distDir = resolve(ctx.root, "dist", platform);
941
988
  try {
@@ -945,7 +992,7 @@ async function buildPlatform(platform, ctx, config, vite) {
945
992
  } else {
946
993
  const htmlName = `index.${platform}.${hash}.html`;
947
994
  const htmlPath = join(cache, htmlName);
948
- fse4.writeFileSync(htmlPath, renderHtmlShell(platform, config, `./${entryFileName}`), "utf-8");
995
+ fse.writeFileSync(htmlPath, renderHtmlShell(platform, config, `./${entryFileName}`), "utf-8");
949
996
  tempFiles.push(htmlPath);
950
997
  inputFile = htmlPath;
951
998
  }
@@ -982,7 +1029,7 @@ async function buildPlatform(platform, ctx, config, vite) {
982
1029
  } finally {
983
1030
  for (const f of tempFiles) {
984
1031
  try {
985
- fse4.removeSync(f);
1032
+ fse.removeSync(f);
986
1033
  } catch {
987
1034
  }
988
1035
  }
@@ -1054,15 +1101,15 @@ async function runDev(target) {
1054
1101
  const cache = cacheDir2(ctx.root);
1055
1102
  const hash = randomBytes(4).toString("hex");
1056
1103
  const runDir = join(cache, `dev-${platform}-${hash}`);
1057
- fse4.ensureDirSync(runDir);
1104
+ fse.ensureDirSync(runDir);
1058
1105
  const entryFileName = `main.${platform}.ts`;
1059
1106
  const entryPath = join(runDir, entryFileName);
1060
1107
  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");
1108
+ fse.writeFileSync(entryPath, renderEntry({ platform, projectRoot: ctx.root }), "utf-8");
1109
+ fse.writeFileSync(htmlPath, renderHtmlShell2(platform, config, `./${entryFileName}`), "utf-8");
1063
1110
  const cleanup = () => {
1064
1111
  try {
1065
- fse4.removeSync(runDir);
1112
+ fse.removeSync(runDir);
1066
1113
  } catch {
1067
1114
  }
1068
1115
  };
@@ -1353,7 +1400,7 @@ function runCap(action, platform) {
1353
1400
  if (action === "sync") {
1354
1401
  console.log(pc6.cyan(pc6.bold("\u25B6 Capacitor sync")));
1355
1402
  const distDir = resolve(ctx.root, "dist", "capacitor");
1356
- if (!fse4.existsSync(distDir)) {
1403
+ if (!fse.existsSync(distDir)) {
1357
1404
  console.log(pc6.red("\u2717 dist/capacitor \u4E0D\u5B58\u5728"));
1358
1405
  console.log(pc6.yellow(" \u8BF7\u5148\u6784\u5EFA:pf build capacitor"));
1359
1406
  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.6",
4
4
  "description": "多平台 Phaser 游戏框架:业务/底层分离,HTTP/WebSocket/KCP,Web/TikTok/微信/Facebook/App 隔离打包",
5
5
  "type": "module",
6
6
  "license": "MIT",