ttmg-pack 0.2.7 → 0.2.8-requirePlugin.2

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/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * ==========================================
3
3
  * @Description: ttmg pack
4
- * @Version: 0.2.7
4
+ * @Version: 0.2.8-requirePlugin.2
5
5
  * @Author: zhanghongyang.mocha
6
- * @Date: 2025-12-09 19:56:48
6
+ * @Date: 2025-12-10 21:36:36
7
7
  * ==========================================
8
8
  */
9
9
  'use strict';
@@ -500,6 +500,40 @@ async function genOpenDataContext(entryPath) {
500
500
  return jsCode;
501
501
  }
502
502
 
503
+ function copyDirectory(src, dest) {
504
+ try {
505
+ if (!fs.existsSync(dest)) {
506
+ fs.mkdirSync(dest, { recursive: true });
507
+ }
508
+ const items = fs.readdirSync(src);
509
+ const normalizedDest = path.resolve(dest) + path.sep;
510
+ items.forEach(item => {
511
+ const srcPath = path.join(src, item);
512
+ const destPath = path.join(dest, item);
513
+ // 检查当前要处理的源路径是否就是目标路径
514
+ // 这可以防止将目标目录本身复制到自身中
515
+ if (path.resolve(srcPath) === path.resolve(dest)) {
516
+ return; // 跳过目标目录本身
517
+ }
518
+ // 获取文件状态
519
+ const stat = fs.statSync(srcPath);
520
+ if (stat.isFile()) {
521
+ // 复制文件
522
+ fs.copyFileSync(srcPath, destPath);
523
+ }
524
+ else if (stat.isDirectory()) {
525
+ const childNormalizedSrc = path.resolve(srcPath) + path.sep;
526
+ if (!normalizedDest.startsWith(childNormalizedSrc)) {
527
+ copyDirectory(srcPath, destPath);
528
+ }
529
+ }
530
+ });
531
+ }
532
+ catch (error) {
533
+ logger.error(`copyDirectory error: ${error}`);
534
+ }
535
+ }
536
+
503
537
  /**
504
538
  * 将 packageConfig packages 中 分拆的包 配置迁移到 odr_packages 中
505
539
  */
@@ -519,7 +553,7 @@ async function writeOdrConfig(outputDir) {
519
553
  if (!odrPackages[relatedPkgName]) {
520
554
  odrPackages[relatedPkgName] = {};
521
555
  }
522
- odrPackages[relatedPkgName] = Object.assign(Object.assign({}, odrPackages[relatedPkgName]), { root: pkgConfig.root, code_output: pkgConfig.output, code_md5: pkgConfig.md5, main: pkgConfig.main });
556
+ odrPackages[relatedPkgName] = Object.assign(Object.assign({}, odrPackages[relatedPkgName]), { root: pkgConfig.root, code_output: pkgConfig.output, code_md5: pkgConfig.md5, main: pkgConfig.main, dependencies: pkgConfig.dependencies, type: pkgConfig.type });
523
557
  delete packages[pkgName];
524
558
  }
525
559
  if (pkgName.endsWith(ODR_ASSET_DIR_SUFFIX)) {
@@ -548,12 +582,14 @@ async function makeOdrPkgs(outputDir) {
548
582
  const pkgOutput = path.join(outputDir, pkgName);
549
583
  const codeOutput = path.join(outputDir, `${pkgName}${ODR_CODE_DIR_SUFFIX}`);
550
584
  const assetOutput = path.join(outputDir, `${pkgName}${ODR_ASSET_DIR_SUFFIX}`);
551
- ensureDirSync(codeOutput);
552
- ensureDirSync(assetOutput);
553
- fs.cpSync(pkgOutput, codeOutput, { recursive: true });
554
- fs.cpSync(pkgOutput, assetOutput, { recursive: true });
555
- deleteNoJsFilesSync(codeOutput);
556
- deleteJsFilesSync(assetOutput);
585
+ if (packages[pkgName].type === 'game') {
586
+ ensureDirSync(codeOutput);
587
+ ensureDirSync(assetOutput);
588
+ fs.cpSync(pkgOutput, codeOutput, { recursive: true });
589
+ fs.cpSync(pkgOutput, assetOutput, { recursive: true });
590
+ deleteNoJsFilesSync(codeOutput);
591
+ deleteJsFilesSync(assetOutput);
592
+ }
557
593
  /**
558
594
  * 写入配置
559
595
  */
@@ -1240,6 +1276,8 @@ async function setup(entryDir, outputDir) {
1240
1276
  root: '',
1241
1277
  main: 'game.js',
1242
1278
  output: `${GAME_MAIN_PACKAGE_NAME}${STTPKG_EXT}`,
1279
+ type: 'game',
1280
+ dependencies: []
1243
1281
  };
1244
1282
  transformSubPackages(gameJson.subpackages).forEach(({ name, root, main, independent }) => {
1245
1283
  // root 是目录
@@ -1250,6 +1288,8 @@ async function setup(entryDir, outputDir) {
1250
1288
  main,
1251
1289
  output: `${name}${STTPKG_EXT}`,
1252
1290
  independent,
1291
+ type: 'game',
1292
+ dependencies: []
1253
1293
  };
1254
1294
  if (independent) {
1255
1295
  fyfPackages.push({
@@ -1397,6 +1437,27 @@ function collectMaps(entryDir, packages) {
1397
1437
  logger.info('基于游戏源代码收集分包中的 JS 文件完成');
1398
1438
  return result;
1399
1439
  }
1440
+ function collectPluginMaps(gameDir, entryDir, name) {
1441
+ logger.info('开始基于插件源代码收集分包中的 JS 文件');
1442
+ const result = {};
1443
+ let jsFiles;
1444
+ jsFiles = collectPkgJsFiles({
1445
+ entry: entryDir,
1446
+ root: entryDir,
1447
+ exts: ['.js', '.ts', '.jsx', '.tsx'],
1448
+ excludeDirs: [],
1449
+ });
1450
+ const list = [];
1451
+ jsFiles.forEach(absPath => {
1452
+ list.push(path.relative(gameDir, absPath).replace(/\\/g, '/'));
1453
+ });
1454
+ const packNameRoot = name;
1455
+ result[name] = {
1456
+ [`${packNameRoot}/game.pack.js`]: list,
1457
+ };
1458
+ logger.info('基于插件源代码收集分包中的 JS 文件完成');
1459
+ return result;
1460
+ }
1400
1461
 
1401
1462
  function collectDeps(gameEntry, packages) {
1402
1463
  // 自动扫描 game 目录下的一级文件夹作为根前缀
@@ -1449,6 +1510,7 @@ function collectDeps(gameEntry, packages) {
1449
1510
  }
1450
1511
  requireCalls.push({
1451
1512
  file: path.relative(gameEntry, fullPath),
1513
+ type: 'game',
1452
1514
  callee: node.callee.name,
1453
1515
  requirePath,
1454
1516
  resolvedPath: resolvedPath
@@ -1456,6 +1518,20 @@ function collectDeps(gameEntry, packages) {
1456
1518
  : '',
1457
1519
  });
1458
1520
  }
1521
+ else if (node.type === 'CallExpression' &&
1522
+ node.callee.type === 'Identifier' &&
1523
+ node.callee.name === 'requirePlugin' &&
1524
+ node.arguments.length > 0 &&
1525
+ node.arguments[0].type === 'Literal') {
1526
+ const requirePath = node.arguments[0].value;
1527
+ requireCalls.push({
1528
+ file: path.relative(gameEntry, fullPath),
1529
+ type: 'plugin',
1530
+ callee: node.callee.name,
1531
+ requirePath,
1532
+ resolvedPath: requirePath,
1533
+ });
1534
+ }
1459
1535
  });
1460
1536
  });
1461
1537
  const newRequireCalls = requireCalls.map(i => {
@@ -1463,11 +1539,16 @@ function collectDeps(gameEntry, packages) {
1463
1539
  * 基于 packages 来判断
1464
1540
  */
1465
1541
  let depModule = '';
1466
- Object.keys(packages).forEach(pkg => {
1467
- if (i.resolvedPath && i.resolvedPath.startsWith(packages[pkg].root)) {
1468
- depModule = pkg;
1469
- }
1470
- });
1542
+ if (i.type === 'plugin') {
1543
+ depModule = i.requirePath.split('/')[0];
1544
+ }
1545
+ else if (i.type === 'game') {
1546
+ Object.keys(packages).forEach(pkg => {
1547
+ if (i.resolvedPath && i.resolvedPath.startsWith(packages[pkg].root)) {
1548
+ depModule = pkg;
1549
+ }
1550
+ });
1551
+ }
1471
1552
  let curModule = '';
1472
1553
  Object.keys(packages).forEach(pkg => {
1473
1554
  if (i.file.startsWith(packages[pkg].root)) {
@@ -1481,17 +1562,26 @@ function collectDeps(gameEntry, packages) {
1481
1562
  const exts = ['.js', '.ts', '.jsx', '.tsx'];
1482
1563
  const isJsLike = f => exts.some(ext => f.endsWith(ext));
1483
1564
  const result = newRequireCalls.reduce((acc, cur) => {
1484
- if (!acc[cur.curModule]) {
1485
- acc[cur.curModule] = {};
1565
+ if (!acc.packageDeps[cur.curModule]) {
1566
+ acc.packageDeps[cur.curModule] = {};
1567
+ }
1568
+ if (!acc.pluginDeps[cur.curModule]) {
1569
+ acc.pluginDeps[cur.curModule] = [];
1486
1570
  }
1487
1571
  if (cur.curModule === cur.depModule) {
1488
1572
  return acc;
1489
1573
  }
1490
- if (cur.resolvedPath && isJsLike(cur.resolvedPath)) {
1491
- acc[cur.curModule] = Object.assign(Object.assign({}, acc[cur.curModule]), { [cur.resolvedPath]: cur.depModule });
1574
+ if (cur.resolvedPath && isJsLike(cur.resolvedPath) && cur.type === 'game') {
1575
+ acc.packageDeps[cur.curModule][cur.resolvedPath] = cur.depModule;
1576
+ }
1577
+ else if (cur.type === 'plugin') {
1578
+ acc.pluginDeps[cur.curModule].push(cur.depModule);
1492
1579
  }
1493
1580
  return acc;
1494
- }, {});
1581
+ }, {
1582
+ packageDeps: {},
1583
+ pluginDeps: {},
1584
+ });
1495
1585
  return result;
1496
1586
  }
1497
1587
  function getRootPrefixes(gameEntry) {
@@ -1537,7 +1627,7 @@ async function pack({ gameEntry, pkgName, allDeps, allMaps, pkgConfig, destRoot,
1537
1627
  const packMap = allMaps[pkgName];
1538
1628
  const moduleConfig = {
1539
1629
  main: pkgConfig.main,
1540
- deps: allDeps[pkgName] || {},
1630
+ deps: allDeps.packageDeps[pkgName] || {},
1541
1631
  map: allMaps[pkgName],
1542
1632
  };
1543
1633
  ensureDirSync(destRoot);
@@ -1588,7 +1678,8 @@ async function pack({ gameEntry, pkgName, allDeps, allMaps, pkgConfig, destRoot,
1588
1678
  // });
1589
1679
  // const code = fs.readFileSync(absPath, 'utf-8');
1590
1680
  const fileId = relPath.replace(/\\/g, '/');
1591
- const defineHeader = `define("game:${fileId}", ["require", "requireAsync", "module", "exports", "sandboxGlobal"], function(require, requireAsync, module, exports, sandboxGlobal){\nwith(sandboxGlobal){\n`;
1681
+ const schema = config.build.type === 'plugin' ? 'plugin' : 'game';
1682
+ const defineHeader = `define("${schema}:${fileId}", ["require", "requireAsync", "module", "exports", "sandboxGlobal"], function(require, requireAsync, module, exports, sandboxGlobal){\nwith(sandboxGlobal){\n`;
1592
1683
  const defineFooter = `\n}\n});\n`;
1593
1684
  const fileMagic = new MagicString(code, { filename: fileId });
1594
1685
  fileMagic.prepend(defineHeader);
@@ -1675,6 +1766,35 @@ async function partition({ pkgRoot, destRoot, packedFiles, gameEntry, gameOutput
1675
1766
  }
1676
1767
  }
1677
1768
 
1769
+ async function addDepsToPackages(gameEntry, outputDir, allDeps) {
1770
+ const gamePackConfigPath = path.join(outputDir, GAME_PACK_CONFIG_FILE_NAME);
1771
+ const gameJsonPath = path.join(gameEntry, GAME_ORIGIN_CONFIG_FILE_NAME);
1772
+ const gamePackConfig = JSON.parse(fs.readFileSync(gamePackConfigPath, 'utf-8'));
1773
+ const gameJson = JSON.parse(fs.readFileSync(gameJsonPath, 'utf-8'));
1774
+ const pluginConfig = gameJson.plugins;
1775
+ Object.entries(allDeps).forEach(([pkgName, plugins]) => {
1776
+ plugins.forEach(pluginName => {
1777
+ if (pluginConfig[pluginName]) {
1778
+ const version = pluginConfig[pluginName].version;
1779
+ gamePackConfig.packages[pkgName].dependencies.push(`${pluginName}_${version}`);
1780
+ if (!gamePackConfig.packages[`${pluginName}_${version}`]) {
1781
+ gamePackConfig.packages[`${pluginName}_${version}`] = {
1782
+ url: `https://connect.tiktok-minis.com/test/${pluginName}_${version}.txt`,
1783
+ md5: '',
1784
+ root: '',
1785
+ main: '',
1786
+ output: `${pluginName}_${version}${STTPKG_EXT}`,
1787
+ independent: false,
1788
+ type: 'plugin',
1789
+ dependencies: []
1790
+ };
1791
+ }
1792
+ }
1793
+ });
1794
+ });
1795
+ fs.writeFileSync(gamePackConfigPath, JSON.stringify(gamePackConfig, null, 2));
1796
+ }
1797
+
1678
1798
  function getSkipDirs({ packages, entryDir, }) {
1679
1799
  const skipDirs = [];
1680
1800
  if (packages) {
@@ -1692,6 +1812,7 @@ async function makePkgs({ gameEntry, gameOutput, config, }) {
1692
1812
  logger.info(`pack start,startTime:${startTime}`);
1693
1813
  const { packages } = await setup(gameEntry, gameOutput);
1694
1814
  const allDeps = collectDeps(gameEntry, packages);
1815
+ await addDepsToPackages(gameEntry, gameOutput, allDeps.pluginDeps);
1695
1816
  const allMaps = collectMaps(gameEntry, packages);
1696
1817
  const pkgOutput = {};
1697
1818
  /**
@@ -1741,6 +1862,46 @@ async function makePkgs({ gameEntry, gameOutput, config, }) {
1741
1862
  logger.info(`pack end,duration:${Date.now() - startTime}ms`);
1742
1863
  return pkgOutput;
1743
1864
  }
1865
+ async function makePlugin({ gameEntry, gameOutput, config, }) {
1866
+ try {
1867
+ const pluginConfig = fs.readFileSync(path.join(gameEntry, 'plugin.json'), 'utf-8');
1868
+ const { name, main, version } = JSON.parse(pluginConfig);
1869
+ const pluginName = `${name}_${version}`;
1870
+ // 把 entryDir 下的所有文件复制到 entryDir/plugin
1871
+ const pluginDir = path.join(gameEntry, pluginName);
1872
+ copyDirectory(gameEntry, pluginDir);
1873
+ const packages = {
1874
+ [pluginName]: {
1875
+ url: '',
1876
+ md5: '',
1877
+ root: pluginName,
1878
+ main,
1879
+ output: `${pluginName}${STTPKG_EXT}`,
1880
+ type: 'game',
1881
+ dependencies: []
1882
+ }
1883
+ };
1884
+ fs.writeFileSync(path.join(gameOutput, GAME_PACK_CONFIG_FILE_NAME), JSON.stringify({ packages }, null, 2));
1885
+ const pluginEntry = path.join(gameEntry, pluginName);
1886
+ const allMaps = collectPluginMaps(gameEntry, pluginEntry, pluginName);
1887
+ await pack({
1888
+ gameEntry,
1889
+ allDeps: {
1890
+ packageDeps: {},
1891
+ pluginDeps: {},
1892
+ },
1893
+ allMaps,
1894
+ pkgName: pluginName,
1895
+ pkgConfig: packages[pluginName],
1896
+ destRoot: path.join(gameOutput, pluginName, packages[pluginName].root),
1897
+ config,
1898
+ });
1899
+ }
1900
+ catch (error) {
1901
+ logger.error('plugin.json 不存在');
1902
+ return;
1903
+ }
1904
+ }
1744
1905
 
1745
1906
  /**
1746
1907
  * 将 packages 中的每个 package 下的文件内容合并到 outputDir 下,不保留 package name
@@ -1856,10 +2017,15 @@ async function debugPkgs(originConfig) {
1856
2017
  }
1857
2018
 
1858
2019
  async function buildPkgs(originConfig) {
2020
+ var _a;
2021
+ if (((_a = originConfig === null || originConfig === void 0 ? void 0 : originConfig.build) === null || _a === void 0 ? void 0 : _a.type) === 'plugin') {
2022
+ await buildPlugin(originConfig);
2023
+ return;
2024
+ }
1859
2025
  const { entry: entryDir, output: outputDir, build } = originConfig;
1860
2026
  let startTime = Date.now();
1861
2027
  logger.init(outputDir, true);
1862
- logger.info(`TTMG_PACK_VERSION: ${"0.2.7"}`);
2028
+ logger.info(`TTMG_PACK_VERSION: ${"0.2.8-requirePlugin.2"}`);
1863
2029
  logger.info(`pack start, startTime:${startTime}`);
1864
2030
  const config = overrideConfig(entryDir, originConfig);
1865
2031
  /**
@@ -1888,6 +2054,31 @@ async function buildPkgs(originConfig) {
1888
2054
  }
1889
2055
  logger.info(`pack end:${Date.now() - startTime}ms`);
1890
2056
  }
2057
+ async function buildPlugin(originConfig) {
2058
+ const { entry: entryDir, output: outputDir, build } = originConfig;
2059
+ let startTime = Date.now();
2060
+ logger.init(outputDir, true);
2061
+ logger.info(`TTMG_PACK_VERSION: ${"0.2.8-requirePlugin.2"}`);
2062
+ logger.info(`pack start, startTime:${startTime}`);
2063
+ /**
2064
+ * 打包
2065
+ */
2066
+ await makePlugin({
2067
+ config: originConfig,
2068
+ gameEntry: entryDir,
2069
+ gameOutput: outputDir,
2070
+ });
2071
+ if (build === null || build === void 0 ? void 0 : build.enableOdr) {
2072
+ /**
2073
+ * 等待文件全部读写完成后
2074
+ */
2075
+ await makeOdrPkgs(outputDir);
2076
+ /**
2077
+ * 分拆 odr 包
2078
+ */
2079
+ }
2080
+ logger.info(`pack end:${Date.now() - startTime}ms`);
2081
+ }
1891
2082
 
1892
2083
  async function getPkgs({ entryDir, }) {
1893
2084
  const independentPackages = getIndependentPackagesConfig(entryDir);
@@ -1915,6 +2106,12 @@ async function getPkgs({ entryDir, }) {
1915
2106
  name: sub.name,
1916
2107
  root: sub.root,
1917
2108
  })),
2109
+ {
2110
+ name: 'aaa',
2111
+ root: 'aaa',
2112
+ size: 123,
2113
+ type: 'independent',
2114
+ }
1918
2115
  ],
1919
2116
  };
1920
2117
  }