@maoyugames/phaser-framework 1.0.2 → 1.0.4
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.d.ts +1 -0
- package/dist/cli/index.js +312 -93
- package/dist/index.js +50 -35
- package/package.json +6 -2
package/dist/cli/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* pf build <platform|all> 构建某平台/全部平台(临时入口 + 编程式 vite + 外壳注入 + 校验)
|
|
8
8
|
* pf size-check [platform] 产物体积检查(扫 <root>/dist/<p>)
|
|
9
9
|
* pf verify-isolation [platform] SDK 隔离校验(扫 <root>/dist/<p>)
|
|
10
|
+
* pf verify [platform] [--no-build] 实跑冒烟验证(Playwright 无头:确认渲染 + 无运行期错误)
|
|
10
11
|
* pf cap <sync|open> [android|ios] Capacitor 同步/打开原生工程
|
|
11
12
|
* pf help 查看帮助
|
|
12
13
|
*
|
package/dist/cli/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import '../chunk-PKBMQBKP.js';
|
|
3
|
-
import
|
|
4
|
-
import { resolve, join, relative, basename, dirname } from 'path';
|
|
3
|
+
import pc6 from 'picocolors';
|
|
4
|
+
import { resolve, join, extname, relative, basename, dirname } from 'path';
|
|
5
5
|
import { randomBytes } from 'crypto';
|
|
6
6
|
import fse4 from 'fs-extra';
|
|
7
7
|
import { createRequire } from 'module';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { existsSync, readFileSync } from 'fs';
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync, readFile, readFileSync } from 'fs';
|
|
10
|
+
import http from 'http';
|
|
10
11
|
import { spawnSync } from 'child_process';
|
|
11
12
|
|
|
12
13
|
// src/cli/platforms-meta.ts
|
|
@@ -538,7 +539,7 @@ function writeShellFiles(distDir, projectRoot, files) {
|
|
|
538
539
|
const dst = join(distDir, f.relPath);
|
|
539
540
|
fse4.ensureDirSync(resolve(dst, ".."));
|
|
540
541
|
fse4.writeFileSync(dst, f.content, "utf-8");
|
|
541
|
-
console.log(
|
|
542
|
+
console.log(pc6.green(` \u2713 ${f.relPath} \u2192 ${relative(projectRoot, dst)}`));
|
|
542
543
|
}
|
|
543
544
|
}
|
|
544
545
|
function injectShell(opts) {
|
|
@@ -548,19 +549,19 @@ function injectShell(opts) {
|
|
|
548
549
|
case "tiktok":
|
|
549
550
|
return true;
|
|
550
551
|
case "facebook": {
|
|
551
|
-
console.log(
|
|
552
|
+
console.log(pc6.cyan(` \u25B6 [facebook] \u6CE8\u5165\u5916\u58F3\u6587\u4EF6`));
|
|
552
553
|
writeShellFiles(distDir, projectRoot, [renderFacebookAppConfig(config.facebook)]);
|
|
553
554
|
return true;
|
|
554
555
|
}
|
|
555
556
|
case "capacitor": {
|
|
556
|
-
console.log(
|
|
557
|
+
console.log(pc6.cyan(` \u25B6 [capacitor] \u751F\u6210 capacitor.config.ts(\u9879\u76EE\u6839)`));
|
|
557
558
|
const capCfgPath = resolve(projectRoot, "capacitor.config.ts");
|
|
558
559
|
fse4.writeFileSync(capCfgPath, renderCapacitorConfig(config.capacitor), "utf-8");
|
|
559
|
-
console.log(
|
|
560
|
+
console.log(pc6.green(` \u2713 capacitor.config.ts \u2192 ${relative(projectRoot, capCfgPath)}`));
|
|
560
561
|
return true;
|
|
561
562
|
}
|
|
562
563
|
case "wechat": {
|
|
563
|
-
console.log(
|
|
564
|
+
console.log(pc6.cyan(` \u25B6 [wechat] \u6CE8\u5165\u5916\u58F3\u6587\u4EF6`));
|
|
564
565
|
writeShellFiles(distDir, projectRoot, renderWeChatShells(config.wechat));
|
|
565
566
|
copyPublicAssetsToWechat(projectRoot, distDir);
|
|
566
567
|
copyWechatVendor(projectRoot, distDir);
|
|
@@ -573,37 +574,37 @@ function injectShell(opts) {
|
|
|
573
574
|
function copyPublicAssetsToWechat(projectRoot, distDir) {
|
|
574
575
|
const srcPublic = resolve(projectRoot, "src/game/public");
|
|
575
576
|
if (!fse4.existsSync(srcPublic)) return;
|
|
576
|
-
console.log(
|
|
577
|
+
console.log(pc6.cyan(" \u25B6 [wechat] \u62F7\u8D1D\u4E1A\u52A1\u9759\u6001\u8D44\u6E90(src/game/public)"));
|
|
577
578
|
fse4.copySync(srcPublic, distDir);
|
|
578
|
-
console.log(
|
|
579
|
+
console.log(pc6.green(" \u2713 src/game/public/* \u2192 dist/wechat/"));
|
|
579
580
|
}
|
|
580
581
|
function copyWechatVendor(projectRoot, distDir) {
|
|
581
|
-
console.log(
|
|
582
|
+
console.log(pc6.cyan(" \u25B6 [wechat] \u68C0\u6D4B\u5FAE\u4FE1\u9002\u914D\u5668(vendor)"));
|
|
582
583
|
const dirs = wechatVendorDirs(projectRoot);
|
|
583
584
|
const adapter = dirs.map((d) => join(d, "weapp-adapter.js")).find((p) => fse4.existsSync(p));
|
|
584
585
|
if (adapter) {
|
|
585
586
|
fse4.copyFileSync(adapter, join(distDir, "weapp-adapter.js"));
|
|
586
|
-
console.log(
|
|
587
|
+
console.log(pc6.green(" \u2713 weapp-adapter.js \u2192 dist/wechat/weapp-adapter.js"));
|
|
587
588
|
const vendorDir = resolve(adapter, "..");
|
|
588
589
|
const symbol = join(vendorDir, "symbol.js");
|
|
589
590
|
if (fse4.existsSync(symbol)) {
|
|
590
591
|
fse4.copyFileSync(symbol, join(distDir, "symbol.js"));
|
|
591
|
-
console.log(
|
|
592
|
+
console.log(pc6.green(" \u2713 symbol.js \u2192 dist/wechat/symbol.js"));
|
|
592
593
|
}
|
|
593
594
|
return true;
|
|
594
595
|
}
|
|
595
|
-
console.log(
|
|
596
|
+
console.log(pc6.yellow(pc6.bold(" \u26A0 \u7F3A\u5C11\u5FAE\u4FE1\u9002\u914D\u5668 weapp-adapter.js")));
|
|
596
597
|
console.log(
|
|
597
|
-
|
|
598
|
+
pc6.yellow(
|
|
598
599
|
" \u5FAE\u4FE1\u5C0F\u6E38\u620F\u65E0 DOM,\u9700\u6B64\u5B98\u65B9\u9002\u914D\u5668\u6CE8\u5165 canvas/document shim,\u5426\u5219 game.js \u542F\u52A8\u5373\u62A5\u9519\u3002"
|
|
599
600
|
)
|
|
600
601
|
);
|
|
601
|
-
console.log(
|
|
602
|
+
console.log(pc6.yellow(` \u8BF7\u628A\u5B98\u65B9 weapp-adapter.js(\u53CA\u53EF\u9009 symbol.js)\u653E\u5230\u4EE5\u4E0B\u4EFB\u4E00\u76EE\u5F55\u540E\u91CD\u65B0\u6784\u5EFA:`));
|
|
602
603
|
for (const d of wechatVendorDirs(projectRoot)) {
|
|
603
|
-
console.log(
|
|
604
|
+
console.log(pc6.yellow(` - ${relative(projectRoot, d)}/weapp-adapter.js`));
|
|
604
605
|
}
|
|
605
606
|
console.log(
|
|
606
|
-
|
|
607
|
+
pc6.yellow(" \u83B7\u53D6\u65B9\u5F0F:\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u65B0\u5EFA\u300C\u5C0F\u6E38\u620F\u300D\u9879\u76EE\u6A21\u677F\u91CC\u9644\u5E26 weapp-adapter.js\u3002")
|
|
607
608
|
);
|
|
608
609
|
return false;
|
|
609
610
|
}
|
|
@@ -627,43 +628,43 @@ function findMainBundle(files) {
|
|
|
627
628
|
}
|
|
628
629
|
function checkPlatform(platform, distDir) {
|
|
629
630
|
if (!fse4.existsSync(distDir)) {
|
|
630
|
-
console.log(
|
|
631
|
+
console.log(pc6.gray(` [${platform}] \u672A\u6784\u5EFA,\u8DF3\u8FC7`));
|
|
631
632
|
return true;
|
|
632
633
|
}
|
|
633
634
|
const files = listFiles(distDir);
|
|
634
635
|
const total = files.reduce((s, f) => s + f.size, 0);
|
|
635
636
|
const main2 = findMainBundle(files);
|
|
636
637
|
const limits = SIZE_LIMITS[platform];
|
|
637
|
-
console.log(
|
|
638
|
-
console.log(` \u603B\u4F53\u79EF:${
|
|
638
|
+
console.log(pc6.cyan(` [${platform}]`));
|
|
639
|
+
console.log(` \u603B\u4F53\u79EF:${pc6.bold(formatBytes(total))}(${files.length} \u4E2A\u6587\u4EF6)`);
|
|
639
640
|
if (main2) {
|
|
640
|
-
console.log(` \u4E3B bundle:${basename(main2.path)} = ${
|
|
641
|
+
console.log(` \u4E3B bundle:${basename(main2.path)} = ${pc6.bold(formatBytes(main2.size))}`);
|
|
641
642
|
}
|
|
642
643
|
let ok = true;
|
|
643
644
|
if (limits?.totalHardLimit) {
|
|
644
645
|
if (total > limits.totalHardLimit) {
|
|
645
646
|
console.log(
|
|
646
|
-
|
|
647
|
+
pc6.red(
|
|
647
648
|
` \u2717 \u8D85\u51FA TikTok \u6574\u5305\u786C\u4E0A\u9650 ${formatBytes(limits.totalHardLimit)}(\u8D85 ${formatBytes(total - limits.totalHardLimit)})`
|
|
648
649
|
)
|
|
649
650
|
);
|
|
650
651
|
ok = false;
|
|
651
652
|
} else {
|
|
652
653
|
console.log(
|
|
653
|
-
|
|
654
|
+
pc6.green(` \u2713 \u5728 TikTok 50MB \u6574\u5305\u4E0A\u9650\u5185(\u4F59 ${formatBytes(limits.totalHardLimit - total)})`)
|
|
654
655
|
);
|
|
655
656
|
}
|
|
656
657
|
}
|
|
657
658
|
if (limits?.mainBundleSoftLimit && main2) {
|
|
658
659
|
if (main2.size > limits.mainBundleSoftLimit) {
|
|
659
660
|
console.log(
|
|
660
|
-
|
|
661
|
+
pc6.yellow(
|
|
661
662
|
` \u26A0 \u5FAE\u4FE1\u4E3B\u5305\u8D85\u8FC7\u5EFA\u8BAE ${formatBytes(limits.mainBundleSoftLimit)}(\u5F53\u524D ${formatBytes(main2.size)});\u5EFA\u8BAE\u62C6\u5206\u5305\u6216\u88C1\u526A\u8D44\u6E90,\u4F46\u4E0D\u963B\u65AD\u6784\u5EFA`
|
|
662
663
|
)
|
|
663
664
|
);
|
|
664
665
|
} else {
|
|
665
666
|
console.log(
|
|
666
|
-
|
|
667
|
+
pc6.green(` \u2713 \u5FAE\u4FE1\u4E3B\u5305\u5728 4MB \u5EFA\u8BAE\u503C\u5185(\u4F59 ${formatBytes(limits.mainBundleSoftLimit - main2.size)})`)
|
|
667
668
|
);
|
|
668
669
|
}
|
|
669
670
|
}
|
|
@@ -672,29 +673,29 @@ function checkPlatform(platform, distDir) {
|
|
|
672
673
|
function runSizeCheck(target) {
|
|
673
674
|
const ctx = resolveProject();
|
|
674
675
|
const targets = target ? isPlatform(target) ? [target] : invalidTarget(target) : ALL_PLATFORMS;
|
|
675
|
-
console.log(
|
|
676
|
+
console.log(pc6.cyan(pc6.bold("\u25B6 \u4EA7\u7269\u4F53\u79EF\u68C0\u67E5")));
|
|
676
677
|
let allOk = true;
|
|
677
678
|
for (const p of targets) {
|
|
678
679
|
const distDir = join(ctx.root, "dist", p);
|
|
679
680
|
if (!checkPlatform(p, distDir)) allOk = false;
|
|
680
681
|
}
|
|
681
682
|
if (!allOk) {
|
|
682
|
-
console.log(
|
|
683
|
+
console.log(pc6.red(pc6.bold("\n\u2717 \u4F53\u79EF\u68C0\u67E5\u672A\u901A\u8FC7(\u5B58\u5728\u8D85\u786C\u4E0A\u9650\u7684\u5E73\u53F0)")));
|
|
683
684
|
return false;
|
|
684
685
|
}
|
|
685
|
-
console.log(
|
|
686
|
+
console.log(pc6.green(pc6.bold("\n\u2713 \u4F53\u79EF\u68C0\u67E5\u5B8C\u6210")));
|
|
686
687
|
return true;
|
|
687
688
|
}
|
|
688
689
|
function sizeCheckPlatform(platform, distDir) {
|
|
689
|
-
console.log(
|
|
690
|
+
console.log(pc6.cyan(pc6.bold("\u25B6 \u4EA7\u7269\u4F53\u79EF\u68C0\u67E5")));
|
|
690
691
|
const ok = checkPlatform(platform, distDir);
|
|
691
|
-
if (ok) console.log(
|
|
692
|
-
else console.log(
|
|
692
|
+
if (ok) console.log(pc6.green(pc6.bold("\u2713 \u4F53\u79EF\u68C0\u67E5\u5B8C\u6210")));
|
|
693
|
+
else console.log(pc6.red(pc6.bold("\u2717 \u4F53\u79EF\u68C0\u67E5\u672A\u901A\u8FC7")));
|
|
693
694
|
return ok;
|
|
694
695
|
}
|
|
695
696
|
function invalidTarget(target) {
|
|
696
|
-
console.log(
|
|
697
|
-
console.log(
|
|
697
|
+
console.log(pc6.red(`\u672A\u77E5\u5E73\u53F0:${target}`));
|
|
698
|
+
console.log(pc6.gray(`\u53EF\u9009:${ALL_PLATFORMS.join(" / ")}`));
|
|
698
699
|
process.exit(1);
|
|
699
700
|
}
|
|
700
701
|
function collectJsFiles(dir) {
|
|
@@ -716,12 +717,12 @@ function snippetAround(text, index, span = 60) {
|
|
|
716
717
|
function verifyPlatform(platform, distDir, projectRoot) {
|
|
717
718
|
const rules = ISOLATION_RULES[platform];
|
|
718
719
|
if (!fse4.existsSync(distDir)) {
|
|
719
|
-
console.log(
|
|
720
|
+
console.log(pc6.gray(` [${platform}] \u672A\u6784\u5EFA(${relative(projectRoot, distDir)} \u4E0D\u5B58\u5728),\u8DF3\u8FC7`));
|
|
720
721
|
return 0;
|
|
721
722
|
}
|
|
722
723
|
const files = collectJsFiles(distDir);
|
|
723
724
|
if (files.length === 0) {
|
|
724
|
-
console.log(
|
|
725
|
+
console.log(pc6.yellow(` [${platform}] \u672A\u53D1\u73B0 JS \u4EA7\u7269,\u8DF3\u8FC7`));
|
|
725
726
|
return 0;
|
|
726
727
|
}
|
|
727
728
|
let hits = 0;
|
|
@@ -735,13 +736,13 @@ function verifyPlatform(platform, distDir, projectRoot) {
|
|
|
735
736
|
hits++;
|
|
736
737
|
perSig++;
|
|
737
738
|
const rel = relative(projectRoot, file);
|
|
738
|
-
console.log(
|
|
739
|
-
console.log(
|
|
740
|
-
console.log(
|
|
739
|
+
console.log(pc6.red(` \u2717 [${platform}] \u547D\u4E2D\u7981\u7528 SDK \u7B7E\u540D ${pc6.bold(sig)}`));
|
|
740
|
+
console.log(pc6.gray(` \u6587\u4EF6:${rel}`));
|
|
741
|
+
console.log(pc6.gray(` \u7247\u6BB5:\u2026${snippetAround(text, idx)}\u2026`));
|
|
741
742
|
from = idx + sig.length;
|
|
742
743
|
idx = text.indexOf(sig, from);
|
|
743
744
|
if (perSig >= 3 && idx !== -1) {
|
|
744
|
-
console.log(
|
|
745
|
+
console.log(pc6.gray(` (\u8BE5\u7B7E\u540D\u5728\u672C\u6587\u4EF6\u8FD8\u6709\u66F4\u591A\u547D\u4E2D,\u5DF2\u6298\u53E0)`));
|
|
745
746
|
break;
|
|
746
747
|
}
|
|
747
748
|
}
|
|
@@ -749,7 +750,7 @@ function verifyPlatform(platform, distDir, projectRoot) {
|
|
|
749
750
|
}
|
|
750
751
|
if (hits === 0) {
|
|
751
752
|
console.log(
|
|
752
|
-
|
|
753
|
+
pc6.green(` \u2713 [${platform}] \u9694\u79BB\u901A\u8FC7(\u626B\u63CF ${files.length} \u4E2A JS \u6587\u4EF6,\u65E0\u5176\u5B83\u5E73\u53F0 SDK \u7B7E\u540D)`)
|
|
753
754
|
);
|
|
754
755
|
}
|
|
755
756
|
return hits;
|
|
@@ -757,32 +758,32 @@ function verifyPlatform(platform, distDir, projectRoot) {
|
|
|
757
758
|
function runVerifyIsolation(target) {
|
|
758
759
|
const ctx = resolveProject();
|
|
759
760
|
const targets = target ? isPlatform(target) ? [target] : invalidTarget2(target) : ALL_PLATFORMS;
|
|
760
|
-
console.log(
|
|
761
|
+
console.log(pc6.cyan(pc6.bold("\u25B6 SDK \u9694\u79BB\u6821\u9A8C")));
|
|
761
762
|
let totalHits = 0;
|
|
762
763
|
for (const p of targets) {
|
|
763
764
|
totalHits += verifyPlatform(p, join(ctx.root, "dist", p), ctx.root);
|
|
764
765
|
}
|
|
765
766
|
if (totalHits > 0) {
|
|
766
|
-
console.log(
|
|
767
|
+
console.log(pc6.red(pc6.bold(`
|
|
767
768
|
\u2717 \u9694\u79BB\u6821\u9A8C\u5931\u8D25:\u5171\u53D1\u73B0 ${totalHits} \u5904\u8DE8\u5E73\u53F0 SDK \u7B7E\u540D\u6CC4\u6F0F`)));
|
|
768
769
|
return false;
|
|
769
770
|
}
|
|
770
|
-
console.log(
|
|
771
|
+
console.log(pc6.green(pc6.bold("\n\u2713 \u9694\u79BB\u6821\u9A8C\u5168\u90E8\u901A\u8FC7")));
|
|
771
772
|
return true;
|
|
772
773
|
}
|
|
773
774
|
function verifyIsolationPlatform(platform, distDir, projectRoot) {
|
|
774
|
-
console.log(
|
|
775
|
+
console.log(pc6.cyan(pc6.bold("\u25B6 SDK \u9694\u79BB\u6821\u9A8C")));
|
|
775
776
|
const hits = verifyPlatform(platform, distDir, projectRoot);
|
|
776
777
|
if (hits > 0) {
|
|
777
|
-
console.log(
|
|
778
|
+
console.log(pc6.red(pc6.bold(`\u2717 \u9694\u79BB\u6821\u9A8C\u5931\u8D25:${hits} \u5904\u8DE8\u5E73\u53F0 SDK \u7B7E\u540D\u6CC4\u6F0F`)));
|
|
778
779
|
return false;
|
|
779
780
|
}
|
|
780
|
-
console.log(
|
|
781
|
+
console.log(pc6.green(pc6.bold("\u2713 \u9694\u79BB\u6821\u9A8C\u901A\u8FC7")));
|
|
781
782
|
return true;
|
|
782
783
|
}
|
|
783
784
|
function invalidTarget2(target) {
|
|
784
|
-
console.log(
|
|
785
|
-
console.log(
|
|
785
|
+
console.log(pc6.red(`\u672A\u77E5\u5E73\u53F0:${target}`));
|
|
786
|
+
console.log(pc6.gray(`\u53EF\u9009:${ALL_PLATFORMS.join(" / ")}`));
|
|
786
787
|
process.exit(1);
|
|
787
788
|
}
|
|
788
789
|
|
|
@@ -928,7 +929,7 @@ function findFirstHtml(dir) {
|
|
|
928
929
|
return void 0;
|
|
929
930
|
}
|
|
930
931
|
async function buildPlatform(platform, ctx, config, vite) {
|
|
931
|
-
console.log(
|
|
932
|
+
console.log(pc6.bgCyan(pc6.black(` \u6784\u5EFA\u5E73\u53F0:${platform} `)));
|
|
932
933
|
const cache = cacheDir(ctx.root);
|
|
933
934
|
fse4.ensureDirSync(cache);
|
|
934
935
|
const hash = randomBytes(4).toString("hex");
|
|
@@ -948,7 +949,7 @@ async function buildPlatform(platform, ctx, config, vite) {
|
|
|
948
949
|
tempFiles.push(htmlPath);
|
|
949
950
|
inputFile = htmlPath;
|
|
950
951
|
}
|
|
951
|
-
console.log(
|
|
952
|
+
console.log(pc6.cyan(` \u25B6 [${platform}] vite build`));
|
|
952
953
|
const inlineConfig = createPlatformConfig(platform, {
|
|
953
954
|
projectRoot: ctx.root,
|
|
954
955
|
viteRoot: platform === "wechat" ? ctx.root : cache,
|
|
@@ -961,22 +962,22 @@ async function buildPlatform(platform, ctx, config, vite) {
|
|
|
961
962
|
if (platform !== "wechat") {
|
|
962
963
|
normalizeHtmlOutput(distDir);
|
|
963
964
|
}
|
|
964
|
-
console.log(
|
|
965
|
+
console.log(pc6.green(` \u2713 [${platform}] vite build \u5B8C\u6210 \u2192 ${relative(ctx.root, distDir)}`));
|
|
965
966
|
const injectOk = injectShell({ platform, projectRoot: ctx.root, distDir, config });
|
|
966
967
|
const sizeOk = sizeCheckPlatform(platform, distDir);
|
|
967
968
|
const isoOk = verifyIsolationPlatform(platform, distDir, ctx.root);
|
|
968
969
|
const allOk = injectOk && sizeOk && isoOk;
|
|
969
970
|
if (allOk) {
|
|
970
|
-
console.log(
|
|
971
|
+
console.log(pc6.green(pc6.bold(`\u2713 [${platform}] \u6784\u5EFA + \u6821\u9A8C\u5B8C\u6210 \u2192 ${relative(ctx.root, distDir)}
|
|
971
972
|
`)));
|
|
972
973
|
} else {
|
|
973
|
-
console.log(
|
|
974
|
+
console.log(pc6.red(pc6.bold(`\u2717 [${platform}] \u6821\u9A8C/\u6CE8\u5165\u672A\u5168\u90E8\u901A\u8FC7
|
|
974
975
|
`)));
|
|
975
976
|
}
|
|
976
977
|
return allOk;
|
|
977
978
|
} catch (e) {
|
|
978
|
-
console.log(
|
|
979
|
-
if (e.stack) console.log(
|
|
979
|
+
console.log(pc6.red(` \u2717 [${platform}] vite build \u5931\u8D25:${e.message}`));
|
|
980
|
+
if (e.stack) console.log(pc6.gray(e.stack ?? ""));
|
|
980
981
|
return false;
|
|
981
982
|
} finally {
|
|
982
983
|
for (const f of tempFiles) {
|
|
@@ -989,37 +990,37 @@ async function buildPlatform(platform, ctx, config, vite) {
|
|
|
989
990
|
}
|
|
990
991
|
async function runBuild(target) {
|
|
991
992
|
if (!target) {
|
|
992
|
-
console.log(
|
|
993
|
+
console.log(pc6.red("\u7528\u6CD5:pf build <web|tiktok|wechat|facebook|capacitor|all>"));
|
|
993
994
|
return false;
|
|
994
995
|
}
|
|
995
996
|
const platforms = target === "all" ? ALL_PLATFORMS : isPlatform(target) ? [target] : null;
|
|
996
997
|
if (!platforms) {
|
|
997
|
-
console.log(
|
|
998
|
-
console.log(
|
|
998
|
+
console.log(pc6.red(`\u672A\u77E5\u5E73\u53F0:${target}`));
|
|
999
|
+
console.log(pc6.gray(`\u53EF\u9009:${ALL_PLATFORMS.join(" / ")} / all`));
|
|
999
1000
|
return false;
|
|
1000
1001
|
}
|
|
1001
1002
|
const ctx = resolveProject();
|
|
1002
1003
|
const config = await loadPlatformConfig(ctx);
|
|
1003
1004
|
const vite = await loadViteFromRoot(ctx.root);
|
|
1004
|
-
console.log(
|
|
1005
|
+
console.log(pc6.cyan(pc6.bold(`\u25B6 \u5F00\u59CB\u6784\u5EFA:${platforms.join(", ")}(\u9879\u76EE:${ctx.root})
|
|
1005
1006
|
`)));
|
|
1006
1007
|
const results = [];
|
|
1007
1008
|
for (const p of platforms) {
|
|
1008
1009
|
results.push({ platform: p, ok: await buildPlatform(p, ctx, config, vite) });
|
|
1009
1010
|
}
|
|
1010
|
-
console.log(
|
|
1011
|
+
console.log(pc6.cyan(pc6.bold("\u25B6 \u6784\u5EFA\u6C47\u603B")));
|
|
1011
1012
|
let allOk = true;
|
|
1012
1013
|
for (const r of results) {
|
|
1013
|
-
if (r.ok) console.log(
|
|
1014
|
+
if (r.ok) console.log(pc6.green(` \u2713 ${r.platform}`));
|
|
1014
1015
|
else {
|
|
1015
|
-
console.log(
|
|
1016
|
+
console.log(pc6.red(` \u2717 ${r.platform}`));
|
|
1016
1017
|
allOk = false;
|
|
1017
1018
|
}
|
|
1018
1019
|
}
|
|
1019
1020
|
if (!allOk) {
|
|
1020
|
-
console.log(
|
|
1021
|
+
console.log(pc6.red(pc6.bold("\n\u2717 \u5B58\u5728\u6784\u5EFA/\u6821\u9A8C\u5931\u8D25\u7684\u5E73\u53F0")));
|
|
1021
1022
|
} else {
|
|
1022
|
-
console.log(
|
|
1023
|
+
console.log(pc6.green(pc6.bold("\n\u2713 \u5168\u90E8\u5B8C\u6210")));
|
|
1023
1024
|
}
|
|
1024
1025
|
return allOk;
|
|
1025
1026
|
}
|
|
@@ -1043,8 +1044,8 @@ function renderHtmlShell2(platform, config, scriptSrc) {
|
|
|
1043
1044
|
async function runDev(target) {
|
|
1044
1045
|
const platform = target ? isPlatform(target) ? target : invalidTarget3(target) : "web";
|
|
1045
1046
|
if (platform === "wechat") {
|
|
1046
|
-
console.log(
|
|
1047
|
-
console.log(
|
|
1047
|
+
console.log(pc6.red("\u2717 wechat \u65E0 HTML dev server \u5F62\u6001\u3002"));
|
|
1048
|
+
console.log(pc6.yellow(" \u8BF7\u7528 `pf build wechat` \u4EA7\u51FA dist/wechat,\u518D\u7528\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u6253\u5F00\u9884\u89C8\u3002"));
|
|
1048
1049
|
return false;
|
|
1049
1050
|
}
|
|
1050
1051
|
const ctx = resolveProject();
|
|
@@ -1096,9 +1097,9 @@ async function runDev(target) {
|
|
|
1096
1097
|
await server.listen();
|
|
1097
1098
|
const info = server.resolvedUrls;
|
|
1098
1099
|
const url = info?.local?.[0] ?? "http://localhost:5173/";
|
|
1099
|
-
console.log(
|
|
1100
|
-
console.log(` \u6253\u5F00:${
|
|
1101
|
-
console.log(
|
|
1100
|
+
console.log(pc6.green(pc6.bold(`\u25B6 [${platform}] dev server \u5C31\u7EEA`)));
|
|
1101
|
+
console.log(` \u6253\u5F00:${pc6.cyan(url)}`);
|
|
1102
|
+
console.log(pc6.gray(" (Ctrl+C \u9000\u51FA,\u4E34\u65F6\u5165\u53E3\u4F1A\u81EA\u52A8\u6E05\u7406)"));
|
|
1102
1103
|
const onExit = async () => {
|
|
1103
1104
|
cleanup();
|
|
1104
1105
|
await server.close();
|
|
@@ -1109,17 +1110,227 @@ async function runDev(target) {
|
|
|
1109
1110
|
return true;
|
|
1110
1111
|
} catch (e) {
|
|
1111
1112
|
cleanup();
|
|
1112
|
-
console.log(
|
|
1113
|
+
console.log(pc6.red(`\u2717 dev server \u542F\u52A8\u5931\u8D25:${e.message}`));
|
|
1113
1114
|
return false;
|
|
1114
1115
|
}
|
|
1115
1116
|
}
|
|
1116
1117
|
function invalidTarget3(target) {
|
|
1117
|
-
console.log(
|
|
1118
|
+
console.log(pc6.red(`\u672A\u77E5\u5E73\u53F0:${target}`));
|
|
1119
|
+
process.exit(1);
|
|
1120
|
+
}
|
|
1121
|
+
var CONTENT_TYPES = {
|
|
1122
|
+
".html": "text/html; charset=utf-8",
|
|
1123
|
+
".js": "text/javascript; charset=utf-8",
|
|
1124
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
1125
|
+
".json": "application/json; charset=utf-8",
|
|
1126
|
+
".css": "text/css; charset=utf-8",
|
|
1127
|
+
".png": "image/png",
|
|
1128
|
+
".jpg": "image/jpeg",
|
|
1129
|
+
".jpeg": "image/jpeg",
|
|
1130
|
+
".webp": "image/webp",
|
|
1131
|
+
".svg": "image/svg+xml",
|
|
1132
|
+
".wasm": "application/wasm"
|
|
1133
|
+
};
|
|
1134
|
+
function serveDist(distDir) {
|
|
1135
|
+
const server = http.createServer((req, res) => {
|
|
1136
|
+
let p = decodeURIComponent((req.url ?? "/").split("?")[0]);
|
|
1137
|
+
if (p === "/") p = "/index.html";
|
|
1138
|
+
if (p === "/favicon.ico") {
|
|
1139
|
+
res.statusCode = 204;
|
|
1140
|
+
res.end();
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
const fp = join(distDir, p);
|
|
1144
|
+
if (!resolve(fp).startsWith(resolve(distDir))) {
|
|
1145
|
+
res.statusCode = 403;
|
|
1146
|
+
res.end("forbidden");
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
readFile(fp, (err, data) => {
|
|
1150
|
+
if (err) {
|
|
1151
|
+
res.statusCode = 404;
|
|
1152
|
+
res.end("not found");
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
res.setHeader("Content-Type", CONTENT_TYPES[extname(fp).toLowerCase()] ?? "application/octet-stream");
|
|
1156
|
+
res.end(data);
|
|
1157
|
+
});
|
|
1158
|
+
});
|
|
1159
|
+
return new Promise((r) => {
|
|
1160
|
+
server.listen(0, "127.0.0.1", () => {
|
|
1161
|
+
const addr = server.address();
|
|
1162
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
1163
|
+
r({ server, port });
|
|
1164
|
+
});
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
function resolvePlaywright(root) {
|
|
1168
|
+
const req = createRequire(join(root, "package.json"));
|
|
1169
|
+
for (const name of ["playwright", "playwright-core", "@playwright/test"]) {
|
|
1170
|
+
try {
|
|
1171
|
+
const mod = req(name);
|
|
1172
|
+
if (mod && mod.chromium) return { chromium: mod.chromium };
|
|
1173
|
+
} catch {
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
return null;
|
|
1177
|
+
}
|
|
1178
|
+
async function readViewport(ctx) {
|
|
1179
|
+
try {
|
|
1180
|
+
const mod = await loadConfigModule(ctx.root, ctx.gameConfigPath);
|
|
1181
|
+
const cfg = mod.gameConfig ?? mod.default ?? {};
|
|
1182
|
+
const width = Number(cfg.designWidth) || 720;
|
|
1183
|
+
const height = Number(cfg.designHeight) || 1280;
|
|
1184
|
+
return { width, height };
|
|
1185
|
+
} catch {
|
|
1186
|
+
return { width: 720, height: 1280 };
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
async function runVerify(target, opts = {}) {
|
|
1190
|
+
const platform = target ? isPlatform(target) ? target : invalid(target) : "web";
|
|
1191
|
+
if (platform === "wechat") {
|
|
1192
|
+
console.log(pc6.yellow("\u26A0 wechat \u65E0 DOM\u3001\u9700\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177,\u65E0\u6CD5\u7528\u6D4F\u89C8\u5668 verify\u3002"));
|
|
1193
|
+
console.log(pc6.gray(" \u8BF7 `pf build wechat` \u540E\u7528\u5FAE\u4FE1\u5F00\u53D1\u8005\u5DE5\u5177\u6253\u5F00 dist/wechat \u9884\u89C8\u9A8C\u8BC1\u3002"));
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
const ctx = resolveProject();
|
|
1197
|
+
const pw = resolvePlaywright(ctx.root);
|
|
1198
|
+
if (!pw) {
|
|
1199
|
+
console.log(pc6.red("\u2717 pf verify \u9700\u8981 Playwright(\u53EF\u9009\u4F9D\u8D56,\u672A\u5B89\u88C5)\u3002"));
|
|
1200
|
+
console.log(pc6.yellow(" \u5B89\u88C5:") + pc6.cyan(" npm i -D playwright"));
|
|
1201
|
+
console.log(pc6.gray(" \u6D4F\u89C8\u5668\u4F18\u5148\u7528\u7CFB\u7EDF Chrome(channel:chrome),\u901A\u5E38\u65E0\u9700 `npx playwright install`\u3002"));
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1204
|
+
if (!opts.noBuild) {
|
|
1205
|
+
console.log(pc6.cyan(pc6.bold(`\u25B6 [verify] \u5148\u6784\u5EFA ${platform}`)));
|
|
1206
|
+
const built = await runBuild(platform);
|
|
1207
|
+
if (!built) {
|
|
1208
|
+
console.log(pc6.red("\u2717 [verify] \u6784\u5EFA\u5931\u8D25,\u7EC8\u6B62\u9A8C\u8BC1"));
|
|
1209
|
+
return false;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
const distDir = resolve(ctx.root, "dist", platform);
|
|
1213
|
+
if (!existsSync(join(distDir, "index.html"))) {
|
|
1214
|
+
console.log(pc6.red(`\u2717 [verify] \u627E\u4E0D\u5230 ${join(distDir, "index.html")}(\u5148 build \u6216\u53BB\u6389 --no-build)`));
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
const viewport = await readViewport(ctx);
|
|
1218
|
+
const { server, port } = await serveDist(distDir);
|
|
1219
|
+
const url = `http://127.0.0.1:${port}/`;
|
|
1220
|
+
console.log(pc6.cyan(pc6.bold(`\u25B6 [verify] \u65E0\u5934\u6D4F\u89C8\u5668\u6253\u5F00 ${platform} \u4EA7\u7269`)));
|
|
1221
|
+
const launchArgs = [
|
|
1222
|
+
"--no-sandbox",
|
|
1223
|
+
"--use-gl=angle",
|
|
1224
|
+
"--use-angle=swiftshader",
|
|
1225
|
+
"--enable-unsafe-swiftshader",
|
|
1226
|
+
"--ignore-gpu-blocklist"
|
|
1227
|
+
];
|
|
1228
|
+
let browser;
|
|
1229
|
+
try {
|
|
1230
|
+
browser = await pw.chromium.launch({ channel: "chrome", headless: true, args: launchArgs });
|
|
1231
|
+
} catch {
|
|
1232
|
+
try {
|
|
1233
|
+
browser = await pw.chromium.launch({ headless: true, args: launchArgs });
|
|
1234
|
+
} catch (e) {
|
|
1235
|
+
server.close();
|
|
1236
|
+
console.log(pc6.red(`\u2717 [verify] \u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25:${e.message}`));
|
|
1237
|
+
console.log(pc6.yellow(" \u88C5\u7CFB\u7EDF Chrome,\u6216\u8FD0\u884C `npx playwright install chromium`\u3002"));
|
|
1238
|
+
return false;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
const errors = [];
|
|
1242
|
+
let rendered = false;
|
|
1243
|
+
let distinctColors = 0;
|
|
1244
|
+
let canvasInView = false;
|
|
1245
|
+
let canvasInfo = null;
|
|
1246
|
+
const outDir = join(ctx.root, ".pf-verify");
|
|
1247
|
+
mkdirSync(outDir, { recursive: true });
|
|
1248
|
+
const shot = join(outDir, `${platform}.png`);
|
|
1249
|
+
try {
|
|
1250
|
+
const page = await browser.newPage({ viewport });
|
|
1251
|
+
page.on("pageerror", (e) => errors.push("PAGEERROR: " + e.message));
|
|
1252
|
+
page.on("console", (m) => {
|
|
1253
|
+
if (m.type() === "error" && !/favicon/i.test(m.text())) errors.push("CONSOLE: " + m.text());
|
|
1254
|
+
});
|
|
1255
|
+
await page.goto(url, { waitUntil: "load", timeout: 3e4 });
|
|
1256
|
+
for (let i = 0; i < 20; i++) {
|
|
1257
|
+
await page.waitForTimeout(1e3);
|
|
1258
|
+
const buf = await page.screenshot({ type: "png" }).catch(() => null);
|
|
1259
|
+
if (buf) writeFileSync(shot, buf);
|
|
1260
|
+
if (buf) {
|
|
1261
|
+
const dataUrl = "data:image/png;base64," + buf.toString("base64");
|
|
1262
|
+
distinctColors = await page.evaluate(async (u) => {
|
|
1263
|
+
const img = new Image();
|
|
1264
|
+
img.src = u;
|
|
1265
|
+
await img.decode();
|
|
1266
|
+
const cv = document.createElement("canvas");
|
|
1267
|
+
cv.width = img.width;
|
|
1268
|
+
cv.height = img.height;
|
|
1269
|
+
const cx = cv.getContext("2d");
|
|
1270
|
+
if (!cx) return 0;
|
|
1271
|
+
cx.drawImage(img, 0, 0);
|
|
1272
|
+
const data = cx.getImageData(0, 0, cv.width, cv.height).data;
|
|
1273
|
+
const colors = /* @__PURE__ */ new Set();
|
|
1274
|
+
const total = cv.width * cv.height;
|
|
1275
|
+
const step = Math.max(1, Math.floor(total / 5e3));
|
|
1276
|
+
for (let k = 0; k < total && colors.size < 40; k += step) {
|
|
1277
|
+
const o = k * 4;
|
|
1278
|
+
colors.add(`${data[o]},${data[o + 1]},${data[o + 2]}`);
|
|
1279
|
+
}
|
|
1280
|
+
return colors.size;
|
|
1281
|
+
}, dataUrl).catch(() => 0);
|
|
1282
|
+
}
|
|
1283
|
+
const vis = await page.evaluate(() => {
|
|
1284
|
+
const c = document.querySelector("canvas");
|
|
1285
|
+
if (!c) return { has: false, inView: false, w: 0, h: 0 };
|
|
1286
|
+
const r = c.getBoundingClientRect();
|
|
1287
|
+
const st = getComputedStyle(c);
|
|
1288
|
+
const inView = r.bottom > 0 && r.right > 0 && r.top < innerHeight && r.left < innerWidth && r.width > 1 && r.height > 1 && st.display !== "none" && st.visibility !== "hidden" && Number(st.opacity) > 0;
|
|
1289
|
+
return { has: true, inView, w: Math.round(r.width), h: Math.round(r.height) };
|
|
1290
|
+
}).catch(() => ({ has: false, inView: false, w: 0, h: 0 }));
|
|
1291
|
+
canvasInfo = vis.has ? { w: vis.w, h: vis.h } : canvasInfo;
|
|
1292
|
+
canvasInView = vis.inView;
|
|
1293
|
+
if (distinctColors > 3 && canvasInView) {
|
|
1294
|
+
rendered = true;
|
|
1295
|
+
break;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
console.log(pc6.gray(` \u622A\u56FE(\u5C4F\u5E55\u5B9E\u62CD):${shot}`));
|
|
1299
|
+
} catch (e) {
|
|
1300
|
+
errors.push("VERIFY: " + e.message);
|
|
1301
|
+
} finally {
|
|
1302
|
+
await browser.close();
|
|
1303
|
+
server.close();
|
|
1304
|
+
}
|
|
1305
|
+
const ok = errors.length === 0 && rendered;
|
|
1306
|
+
console.log("");
|
|
1307
|
+
console.log(pc6.bold("\u25B6 [verify] \u7ED3\u679C"));
|
|
1308
|
+
console.log(
|
|
1309
|
+
` canvas:${canvasInfo ? `${canvasInfo.w}\xD7${canvasInfo.h}` : "\u65E0"};\u5728\u89C6\u53E3\u5185:${canvasInView ? "\u662F" : "\u5426"};\u5C4F\u5E55\u989C\u8272\u6570:${distinctColors}(>3 \u89C6\u4E3A\u5DF2\u6E32\u67D3)`
|
|
1310
|
+
);
|
|
1311
|
+
if (errors.length) {
|
|
1312
|
+
console.log(pc6.red(` \u63A7\u5236\u53F0/\u9875\u9762\u9519\u8BEF(${errors.length}):`));
|
|
1313
|
+
errors.slice(0, 12).forEach((e) => console.log(pc6.red(" " + e)));
|
|
1314
|
+
} else {
|
|
1315
|
+
console.log(pc6.green(" \u65E0\u63A7\u5236\u53F0/\u9875\u9762\u9519\u8BEF"));
|
|
1316
|
+
}
|
|
1317
|
+
if (ok) {
|
|
1318
|
+
console.log(pc6.green(pc6.bold(`
|
|
1319
|
+
\u2713 [verify] ${platform} \u5B9E\u8DD1\u901A\u8FC7(\u5C4F\u5E55\u6E32\u67D3\u6B63\u5E38\u3001\u65E0\u8FD0\u884C\u671F\u9519\u8BEF)`)));
|
|
1320
|
+
} else {
|
|
1321
|
+
const reason = errors.length ? "\u5B58\u5728\u8FD0\u884C\u671F\u9519\u8BEF" : !canvasInView ? "canvas \u4E0D\u5728\u89C6\u53E3\u5185(\u88AB\u5E03\u5C40\u63A8\u51FA\u5C4F\u5E55/\u9690\u85CF \u2192 \u7528\u6237\u770B\u5230\u9ED1\u5C4F)" : "\u5C4F\u5E55\u753B\u9762\u672A\u6E32\u67D3\u51FA\u5185\u5BB9(\u7591\u4F3C\u5D29\u6E83/\u9ED1\u5C4F)";
|
|
1322
|
+
console.log(pc6.red(pc6.bold(`
|
|
1323
|
+
\u2717 [verify] ${platform} \u672A\u901A\u8FC7:${reason}`)));
|
|
1324
|
+
}
|
|
1325
|
+
return ok;
|
|
1326
|
+
}
|
|
1327
|
+
function invalid(target) {
|
|
1328
|
+
console.log(pc6.red(`\u672A\u77E5\u5E73\u53F0:${target}`));
|
|
1118
1329
|
process.exit(1);
|
|
1119
1330
|
}
|
|
1120
1331
|
function spawnCap(projectRoot, args) {
|
|
1121
1332
|
const npx = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
1122
|
-
console.log(
|
|
1333
|
+
console.log(pc6.gray(` $ ${npx} cap ${args.join(" ")}`));
|
|
1123
1334
|
const res = spawnSync(npx, ["cap", ...args], {
|
|
1124
1335
|
cwd: projectRoot,
|
|
1125
1336
|
stdio: "inherit",
|
|
@@ -1127,9 +1338,9 @@ function spawnCap(projectRoot, args) {
|
|
|
1127
1338
|
shell: process.platform === "win32"
|
|
1128
1339
|
});
|
|
1129
1340
|
if (res.error) {
|
|
1130
|
-
console.log(
|
|
1341
|
+
console.log(pc6.red(` \u2717 \u6267\u884C\u5931\u8D25:${res.error.message}`));
|
|
1131
1342
|
console.log(
|
|
1132
|
-
|
|
1343
|
+
pc6.yellow(
|
|
1133
1344
|
" \u8BF7\u786E\u8BA4\u5DF2\u5B89\u88C5 Capacitor CLI:npm i -D @capacitor/cli @capacitor/android @capacitor/ios"
|
|
1134
1345
|
)
|
|
1135
1346
|
);
|
|
@@ -1140,11 +1351,11 @@ function spawnCap(projectRoot, args) {
|
|
|
1140
1351
|
function runCap(action, platform) {
|
|
1141
1352
|
const ctx = resolveProject();
|
|
1142
1353
|
if (action === "sync") {
|
|
1143
|
-
console.log(
|
|
1354
|
+
console.log(pc6.cyan(pc6.bold("\u25B6 Capacitor sync")));
|
|
1144
1355
|
const distDir = resolve(ctx.root, "dist", "capacitor");
|
|
1145
1356
|
if (!fse4.existsSync(distDir)) {
|
|
1146
|
-
console.log(
|
|
1147
|
-
console.log(
|
|
1357
|
+
console.log(pc6.red("\u2717 dist/capacitor \u4E0D\u5B58\u5728"));
|
|
1358
|
+
console.log(pc6.yellow(" \u8BF7\u5148\u6784\u5EFA:pf build capacitor"));
|
|
1148
1359
|
return false;
|
|
1149
1360
|
}
|
|
1150
1361
|
const args = platform ? ["sync", platform] : ["sync"];
|
|
@@ -1152,13 +1363,13 @@ function runCap(action, platform) {
|
|
|
1152
1363
|
}
|
|
1153
1364
|
if (action === "open") {
|
|
1154
1365
|
if (platform !== "android" && platform !== "ios") {
|
|
1155
|
-
console.log(
|
|
1366
|
+
console.log(pc6.red("\u2717 open \u9700\u6307\u5B9A\u5E73\u53F0:pf cap open <android|ios>"));
|
|
1156
1367
|
return false;
|
|
1157
1368
|
}
|
|
1158
|
-
console.log(
|
|
1369
|
+
console.log(pc6.cyan(pc6.bold(`\u25B6 Capacitor open ${platform}`)));
|
|
1159
1370
|
return capExec(ctx.root, ["open", platform]);
|
|
1160
1371
|
}
|
|
1161
|
-
console.log(
|
|
1372
|
+
console.log(pc6.red("\u7528\u6CD5:"));
|
|
1162
1373
|
console.log(" pf cap sync [android|ios]");
|
|
1163
1374
|
console.log(" pf cap open <android|ios>");
|
|
1164
1375
|
return false;
|
|
@@ -1197,35 +1408,43 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1197
1408
|
process.exitCode = ok ? 0 : 1;
|
|
1198
1409
|
return;
|
|
1199
1410
|
}
|
|
1411
|
+
case "verify": {
|
|
1412
|
+
const noBuild = rest.includes("--no-build");
|
|
1413
|
+
const platform = rest.find((a) => !a.startsWith("-"));
|
|
1414
|
+
const ok = await runVerify(platform, { noBuild });
|
|
1415
|
+
process.exitCode = ok ? 0 : 1;
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1200
1418
|
case "cap": {
|
|
1201
1419
|
const ok = runCap(rest[0], rest[1]);
|
|
1202
1420
|
process.exitCode = ok ? 0 : 1;
|
|
1203
1421
|
return;
|
|
1204
1422
|
}
|
|
1205
1423
|
default: {
|
|
1206
|
-
console.log(
|
|
1207
|
-
console.log(
|
|
1424
|
+
console.log(pc6.yellow(`[pf] \u672A\u77E5\u547D\u4EE4 "${command}"\u3002`));
|
|
1425
|
+
console.log(pc6.dim("\u8FD0\u884C `pf help` \u67E5\u770B\u53EF\u7528\u547D\u4EE4\u3002"));
|
|
1208
1426
|
process.exitCode = 1;
|
|
1209
1427
|
}
|
|
1210
1428
|
}
|
|
1211
1429
|
} catch (e) {
|
|
1212
|
-
console.log(
|
|
1213
|
-
if (e.stack) console.log(
|
|
1430
|
+
console.log(pc6.red(`[pf] \u6267\u884C "${command}" \u51FA\u9519:${e.message}`));
|
|
1431
|
+
if (e.stack) console.log(pc6.gray(e.stack ?? ""));
|
|
1214
1432
|
process.exitCode = 1;
|
|
1215
1433
|
}
|
|
1216
1434
|
}
|
|
1217
1435
|
function printHelp() {
|
|
1218
|
-
console.log(
|
|
1219
|
-
console.log(
|
|
1436
|
+
console.log(pc6.bold("@maoyugames/phaser-framework CLI (pf)"));
|
|
1437
|
+
console.log(pc6.dim("\u591A\u5E73\u53F0 Phaser \u6846\u67B6\u6784\u5EFA\u5DE5\u5177\u3002"));
|
|
1220
1438
|
console.log("");
|
|
1221
1439
|
console.log("\u547D\u4EE4:");
|
|
1222
|
-
console.log(` ${
|
|
1223
|
-
console.log(` ${
|
|
1224
|
-
console.log(` ${
|
|
1225
|
-
console.log(` ${
|
|
1226
|
-
console.log(` ${
|
|
1440
|
+
console.log(` ${pc6.cyan("pf dev [platform]")} \u542F\u52A8\u67D0\u5E73\u53F0 dev server(\u9ED8\u8BA4 web)`);
|
|
1441
|
+
console.log(` ${pc6.cyan("pf build <platform|all>")} \u6784\u5EFA\u67D0\u5E73\u53F0/\u5168\u90E8\u5E73\u53F0`);
|
|
1442
|
+
console.log(` ${pc6.cyan("pf size-check [platform]")} \u4EA7\u7269\u4F53\u79EF\u68C0\u67E5`);
|
|
1443
|
+
console.log(` ${pc6.cyan("pf verify-isolation [platform]")} SDK \u9694\u79BB\u6821\u9A8C`);
|
|
1444
|
+
console.log(` ${pc6.cyan("pf verify [platform] [--no-build]")} \u5B9E\u8DD1\u5192\u70DF\u9A8C\u8BC1(Playwright \u65E0\u5934:\u6E32\u67D3+\u65E0\u8FD0\u884C\u671F\u9519\u8BEF)`);
|
|
1445
|
+
console.log(` ${pc6.cyan("pf cap <sync|open> [android|ios]")} Capacitor \u539F\u751F\u5DE5\u7A0B\u64CD\u4F5C`);
|
|
1227
1446
|
console.log("");
|
|
1228
|
-
console.log(
|
|
1447
|
+
console.log(pc6.dim("\u5E73\u53F0:web / tiktok / wechat / facebook / capacitor"));
|
|
1229
1448
|
}
|
|
1230
1449
|
void main();
|
|
1231
1450
|
|
package/dist/index.js
CHANGED
|
@@ -2091,6 +2091,15 @@ var AccountService = class {
|
|
|
2091
2091
|
}
|
|
2092
2092
|
};
|
|
2093
2093
|
|
|
2094
|
+
// src/scene/active-scene.ts
|
|
2095
|
+
var _active = null;
|
|
2096
|
+
function setActiveScene(scene) {
|
|
2097
|
+
_active = scene;
|
|
2098
|
+
}
|
|
2099
|
+
function getActiveScene() {
|
|
2100
|
+
return _active;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2094
2103
|
// src/services/SceneManager.ts
|
|
2095
2104
|
var SceneManager = class {
|
|
2096
2105
|
constructor() {
|
|
@@ -2108,19 +2117,18 @@ var SceneManager = class {
|
|
|
2108
2117
|
return;
|
|
2109
2118
|
}
|
|
2110
2119
|
const sceneData = asSceneData(data);
|
|
2111
|
-
const
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2120
|
+
const active = getActiveScene();
|
|
2121
|
+
if (active && active.scene && typeof active.scene.start === "function") {
|
|
2122
|
+
for (const scene of manager.getScenes(true)) {
|
|
2123
|
+
const sceneKey = scene.scene.key;
|
|
2124
|
+
if (sceneKey !== key && scene !== active) {
|
|
2125
|
+
manager.stop(sceneKey);
|
|
2126
|
+
}
|
|
2117
2127
|
}
|
|
2128
|
+
active.scene.start(key, sceneData);
|
|
2129
|
+
return;
|
|
2118
2130
|
}
|
|
2119
|
-
|
|
2120
|
-
vehicle.scene.start(key, sceneData);
|
|
2121
|
-
} else {
|
|
2122
|
-
manager.start(key, sceneData);
|
|
2123
|
-
}
|
|
2131
|
+
manager.start(key, sceneData);
|
|
2124
2132
|
}
|
|
2125
2133
|
push(key, data) {
|
|
2126
2134
|
const manager = this.game?.scene;
|
|
@@ -2868,9 +2876,6 @@ var PanelManager = class {
|
|
|
2868
2876
|
return actives[actives.length - 1];
|
|
2869
2877
|
}
|
|
2870
2878
|
};
|
|
2871
|
-
|
|
2872
|
-
// src/bootstrap.ts
|
|
2873
|
-
var _game = null;
|
|
2874
2879
|
async function startGame(opts) {
|
|
2875
2880
|
const { platform, config, scenes } = opts;
|
|
2876
2881
|
PlatformContext.set(platform);
|
|
@@ -2932,31 +2937,40 @@ async function startGame(opts) {
|
|
|
2932
2937
|
await opts.setup(App);
|
|
2933
2938
|
}
|
|
2934
2939
|
log.info(`[bootstrap] \u5E73\u53F0 ${platform.info.name} \u521D\u59CB\u5316\u5B8C\u6210,\u542F\u52A8 Phaser`);
|
|
2935
|
-
|
|
2936
|
-
audio.bindGame(
|
|
2937
|
-
sceneManager.bindGame(
|
|
2938
|
-
panelManager.bindGame(
|
|
2940
|
+
const game = createPhaserGameInstance(config, scenes);
|
|
2941
|
+
audio.bindGame(game);
|
|
2942
|
+
sceneManager.bindGame(game);
|
|
2943
|
+
panelManager.bindGame(game);
|
|
2944
|
+
await waitForGameReady(game);
|
|
2939
2945
|
await App.modules.initAll();
|
|
2940
2946
|
log.info("[bootstrap] \u6E38\u620F\u542F\u52A8\u5B8C\u6210");
|
|
2941
2947
|
}
|
|
2942
|
-
function
|
|
2948
|
+
function createPhaserGameInstance(config, scenes) {
|
|
2949
|
+
const gameConfig = {
|
|
2950
|
+
type: Phaser4.AUTO,
|
|
2951
|
+
// 关键:把 canvas 挂进各平台外壳的 #game-root(外壳已为它写好布局/居中 CSS)。
|
|
2952
|
+
// 不设 parent 时 Phaser 把 canvas 追加到 document.body —— 而外壳里 #game-root 占满
|
|
2953
|
+
// 100% 高度,canvas 作为其后的块级兄弟会被挤到视口外,再被 body 的 overflow:hidden
|
|
2954
|
+
// 裁掉 → 屏幕全黑(但 canvas 后备缓冲其实已渲染,故 toDataURL/getImageData 读不出问题)。
|
|
2955
|
+
// wechat 无 DOM(weapp-adapter),'game-root' 不存在时 Phaser 自动回退,安全。
|
|
2956
|
+
parent: "game-root",
|
|
2957
|
+
// 透明背景占位;业务场景自行绘制背景
|
|
2958
|
+
backgroundColor: "#1f2937",
|
|
2959
|
+
scale: {
|
|
2960
|
+
// FIT:按设计分辨率等比缩放铺满容器(保持比例,留黑边);CENTER_BOTH:居中
|
|
2961
|
+
mode: Phaser4.Scale.FIT,
|
|
2962
|
+
autoCenter: Phaser4.Scale.CENTER_BOTH,
|
|
2963
|
+
width: config.designWidth,
|
|
2964
|
+
height: config.designHeight
|
|
2965
|
+
},
|
|
2966
|
+
scene: scenes
|
|
2967
|
+
// 微信等无 DOM 平台由 weapp-adapter 提供 canvas;有 DOM 平台 Phaser 自动建 canvas
|
|
2968
|
+
};
|
|
2969
|
+
return new Phaser4.Game(gameConfig);
|
|
2970
|
+
}
|
|
2971
|
+
function waitForGameReady(game) {
|
|
2943
2972
|
return new Promise((resolve) => {
|
|
2944
|
-
|
|
2945
|
-
type: Phaser4.AUTO,
|
|
2946
|
-
// 透明背景占位;业务场景自行绘制背景
|
|
2947
|
-
backgroundColor: "#1f2937",
|
|
2948
|
-
scale: {
|
|
2949
|
-
// FIT:按设计分辨率等比缩放铺满容器(保持比例,留黑边);CENTER_BOTH:居中
|
|
2950
|
-
mode: Phaser4.Scale.FIT,
|
|
2951
|
-
autoCenter: Phaser4.Scale.CENTER_BOTH,
|
|
2952
|
-
width: config.designWidth,
|
|
2953
|
-
height: config.designHeight
|
|
2954
|
-
},
|
|
2955
|
-
scene: scenes
|
|
2956
|
-
// 微信等无 DOM 平台由 weapp-adapter 提供 canvas;有 DOM 平台 Phaser 自动建 canvas
|
|
2957
|
-
};
|
|
2958
|
-
const game = new Phaser4.Game(gameConfig);
|
|
2959
|
-
game.events.once(Phaser4.Core.Events.READY, () => resolve(game));
|
|
2973
|
+
game.events.once(Phaser4.Core.Events.READY, () => resolve());
|
|
2960
2974
|
});
|
|
2961
2975
|
}
|
|
2962
2976
|
|
|
@@ -3094,6 +3108,7 @@ var BaseScene = class extends Phaser4.Scene {
|
|
|
3094
3108
|
* 注意:业务场景若覆写 init(data),请调用 super.init(data) 以保留自动清理(this.bind / this.scheduler)。
|
|
3095
3109
|
*/
|
|
3096
3110
|
init(_data) {
|
|
3111
|
+
setActiveScene(this);
|
|
3097
3112
|
this.armCleanupHooks();
|
|
3098
3113
|
}
|
|
3099
3114
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maoyugames/phaser-framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "多平台 Phaser 游戏框架:业务/底层分离,HTTP/WebSocket/KCP,Web/TikTok/微信/Facebook/App 隔离打包",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,11 +53,15 @@
|
|
|
53
53
|
"phaser": "^3.60.0 || ^3.80.0 || ^3.90.0",
|
|
54
54
|
"vite": "^5.0.0",
|
|
55
55
|
"typescript": "^5.0.0",
|
|
56
|
-
"terser": "^5.0.0"
|
|
56
|
+
"terser": "^5.0.0",
|
|
57
|
+
"playwright": "^1.40.0"
|
|
57
58
|
},
|
|
58
59
|
"peerDependenciesMeta": {
|
|
59
60
|
"terser": {
|
|
60
61
|
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"playwright": {
|
|
64
|
+
"optional": true
|
|
61
65
|
}
|
|
62
66
|
},
|
|
63
67
|
"dependencies": {
|