@tmsfe/tmskit 0.0.65 → 0.0.67

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.cjs.js CHANGED
@@ -120,23 +120,23 @@ const succeed$2 = (message = '') => {
120
120
  const warn$2 = message => {
121
121
  console.log(`${moment$1().format('YYYY-MM-DD HH:mm:ss')}`, chalk$5.yellow(message));
122
122
  };
123
- const info$k = (...args) => console.log(`${moment$1().format('YYYY-MM-DD HH:mm:ss')}`, ...args);
123
+ const info$l = (...args) => console.log(`${moment$1().format('YYYY-MM-DD HH:mm:ss')}`, ...args);
124
124
  const infoNoTime$1 = (...args) => console.log(...args);
125
125
  var log$1 = {
126
126
  fail: fail$a,
127
127
  succeed: succeed$2,
128
128
  warn: warn$2,
129
- info: info$k,
129
+ info: info$l,
130
130
  infoNoTime: infoNoTime$1
131
131
  };
132
132
 
133
133
  const ora$2 = require$$0__default;
134
- const path$h = require$$1__default$1;
134
+ const path$i = require$$1__default$1;
135
135
  const fs$j = require$$0__default$1;
136
136
  const shelljs$7 = require$$0__default$2;
137
137
  const glob = require$$4__default;
138
138
  const {
139
- info: info$j
139
+ info: info$k
140
140
  } = log$1;
141
141
  const shelljsOptions = {
142
142
  slient: true,
@@ -146,7 +146,7 @@ const shelljsOptions = {
146
146
  // 获取当前目录
147
147
  const cwd = process.cwd();
148
148
  function resolve$k(...args) {
149
- return path$h.resolve(cwd, ...args);
149
+ return path$i.resolve(cwd, ...args);
150
150
  }
151
151
 
152
152
  /**
@@ -179,7 +179,7 @@ function downloadRepoForGit$1(url, dest, branch) {
179
179
  return new Promise((resolve, reject) => {
180
180
  // 如果目标目录不存在
181
181
  if (fs$j.existsSync(dest)) {
182
- shelljs$7.rm('-rf', path$h.join(dest));
182
+ shelljs$7.rm('-rf', path$i.join(dest));
183
183
  }
184
184
  shelljs$7.mkdir('-p', dest);
185
185
  shelljs$7.cd(dest);
@@ -278,7 +278,7 @@ function createTask$7(task, startText, endText) {
278
278
  return async (...args) => {
279
279
  const start = Date.now();
280
280
  const spinner = ora$2();
281
- info$j(startText);
281
+ info$k(startText);
282
282
  spinner.start();
283
283
  const result = await task(...args);
284
284
  endText && spinner.succeed(`${endText}, 耗时${cost(start) / 1000}s`);
@@ -300,7 +300,7 @@ const mergeMap$1 = function (obj, src) {
300
300
  return obj;
301
301
  };
302
302
  const relativeCwdPath$1 = function (file) {
303
- return path$h.relative(process.cwd(), file);
303
+ return path$i.relative(process.cwd(), file);
304
304
  };
305
305
 
306
306
  /**
@@ -387,35 +387,35 @@ var widgets = {
387
387
 
388
388
  var tmsMpconfig = {exports: {}};
389
389
 
390
- const path$g = require$$1__default$1;
390
+ const path$h = require$$1__default$1;
391
391
  const os = require$$1__default$2;
392
392
 
393
393
  // 用户目录
394
394
  const HOME_DIR = os.homedir();
395
395
 
396
396
  // 所有文件的缓存目录
397
- const CACHE_DIR = path$g.resolve(HOME_DIR, '.tmskit');
397
+ const CACHE_DIR = path$h.resolve(HOME_DIR, '.tmskit');
398
398
 
399
399
  // 版本管理的CDN地址
400
400
  const VERSION_URL = 'https://tms-web-1g1czzwka2fd06f2-1301126013.tcloudbaseapp.com/tmskit-template/version.json';
401
401
 
402
402
  // version缓存文件
403
- const VERSION_CACHE_FILE = path$g.resolve(CACHE_DIR, 'version_cache_file.json');
403
+ const VERSION_CACHE_FILE = path$h.resolve(CACHE_DIR, 'version_cache_file.json');
404
404
 
405
405
  // npm缓存文件
406
- const NPM_CACHE_FILE$1 = path$g.resolve(CACHE_DIR, 'npm_cache_file.json');
406
+ const NPM_CACHE_FILE$1 = path$h.resolve(CACHE_DIR, 'npm_cache_file.json');
407
407
 
408
408
  // 脚手架模板代码所在目录
409
- const TEMPLATE_DIR$1 = path$g.resolve(CACHE_DIR, 'template');
409
+ const TEMPLATE_DIR$1 = path$h.resolve(CACHE_DIR, 'template');
410
410
 
411
411
  // 第三方模块源码存放的临时缓存目录
412
- const MODULE_CODE_DIR$2 = path$g.resolve(CACHE_DIR, 'modules_code');
412
+ const MODULE_CODE_DIR$2 = path$h.resolve(CACHE_DIR, 'modules_code');
413
413
 
414
414
  // 缓存分包node_modules的目录
415
- const NODE_MODULES_DIR$2 = path$g.resolve(CACHE_DIR, 'node_modules');
415
+ const NODE_MODULES_DIR$2 = path$h.resolve(CACHE_DIR, 'node_modules');
416
416
 
417
417
  // 扩展命令源码的存放处
418
- const EXTEND_CMD$1 = path$g.resolve(CACHE_DIR, 'cmd');
418
+ const EXTEND_CMD$1 = path$h.resolve(CACHE_DIR, 'cmd');
419
419
 
420
420
  // 创建模板的名称
421
421
  const TEMPLATE_NAME$1 = 'tmskit-template';
@@ -441,7 +441,7 @@ const MODULE_CONFIG_FILENAME = 'module.config.json';
441
441
 
442
442
  // 默认的webpack entry
443
443
  const DEFAULT_WEBPACK_ENTRY = {
444
- app: path$g.resolve(process.cwd(), 'app')
444
+ app: path$h.resolve(process.cwd(), 'app')
445
445
  };
446
446
 
447
447
  // 默认从源码拷贝到编译后的配置
@@ -828,6 +828,7 @@ var global_1 = {
828
828
  * @returns
829
829
  */
830
830
  const getModulesByMergeDepModules = (tmsConfig, modules, errorIsQuit = false) => {
831
+ const devStrictMode = !!tmsConfig.devStrictModulesInclude;
831
832
  const allModules = new Map();
832
833
  function dfs(tmsConfig, modules) {
833
834
  modules.forEach(moduleItem => {
@@ -847,9 +848,13 @@ var global_1 = {
847
848
  const [moduleConfig = {}] = getModulesConfig([moduleItem], tmsConfig);
848
849
  if (!allModules.has(moduleItem.moduleName)) {
849
850
  allModules.set(moduleItem.moduleName, checkModuleItem(tmsConfig, moduleItem, moduleConfig));
850
- const dependenciesModules = getModulesByModuleNames(tmsConfig, moduleConfig === null || moduleConfig === void 0 ? void 0 : moduleConfig.dependencies);
851
- if (dependenciesModules.length) {
852
- dfs(tmsConfig, dependenciesModules);
851
+
852
+ // devStrictModulesInclude 模式下忽略 dependencies,不递归加载依赖模块
853
+ if (!devStrictMode) {
854
+ const dependenciesModules = getModulesByModuleNames(tmsConfig, moduleConfig === null || moduleConfig === void 0 ? void 0 : moduleConfig.dependencies);
855
+ if (dependenciesModules.length) {
856
+ dfs(tmsConfig, dependenciesModules);
857
+ }
853
858
  }
854
859
  }
855
860
  });
@@ -873,9 +878,9 @@ var global_1 = {
873
878
  })(tmsMpconfig);
874
879
 
875
880
  const fs$i = require$$0__default$1;
876
- const path$f = require$$1__default$1;
881
+ const path$g = require$$1__default$1;
877
882
  const {
878
- info: info$i
883
+ info: info$j
879
884
  } = log$1;
880
885
  const {
881
886
  relativeCwdPath
@@ -914,7 +919,7 @@ const copyFile = function (src, dest) {
914
919
  if (fs$i.existsSync(dest)) {
915
920
  fs$i.unlinkSync(dest);
916
921
  }
917
- const dir = path$f.dirname(dest);
922
+ const dir = path$g.dirname(dest);
918
923
  ensureDirExist$6(dir);
919
924
  fs$i.copyFileSync(src, dest);
920
925
  };
@@ -925,11 +930,11 @@ function diffContentCopyFile(originFile, destFile) {
925
930
  const depDestContent = fs$i.readFileSync(destFile, 'utf8');
926
931
  const depOriginContent = fs$i.readFileSync(originFile, 'utf8');
927
932
  if (depDestContent !== depOriginContent) {
928
- info$i(`拷贝${relativeCwdPath(originFile)}内容到${relativeCwdPath(destFile)}`);
933
+ info$j(`拷贝${relativeCwdPath(originFile)}内容到${relativeCwdPath(destFile)}`);
929
934
  copyFile(originFile, destFile);
930
935
  }
931
936
  } else {
932
- info$i(`拷贝${relativeCwdPath(originFile)}内容到${relativeCwdPath(destFile)}`);
937
+ info$j(`拷贝${relativeCwdPath(originFile)}内容到${relativeCwdPath(destFile)}`);
933
938
  copyFile(originFile, destFile);
934
939
  }
935
940
  }
@@ -968,7 +973,7 @@ const fileInDir = (dir, file) => {
968
973
  if (!fs$i.existsSync(dir) || !fs$i.existsSync(file)) {
969
974
  return false;
970
975
  }
971
- const relativePath = path$f.relative(dir, file);
976
+ const relativePath = path$g.relative(dir, file);
972
977
  if (relativePath.startsWith('..')) {
973
978
  return false;
974
979
  }
@@ -979,7 +984,7 @@ function findAllFilesOfDir(dir) {
979
984
  function listFile(dir) {
980
985
  const arr = fs$i.readdirSync(dir);
981
986
  arr.forEach(item => {
982
- const fullPath = path$f.join(dir, item);
987
+ const fullPath = path$g.join(dir, item);
983
988
  const stats = fs$i.statSync(fullPath);
984
989
  if (stats.isDirectory()) {
985
990
  listFile(fullPath);
@@ -1131,7 +1136,7 @@ const report$b = (name, attrs = {}) => {
1131
1136
  };
1132
1137
  var report_1 = report$b;
1133
1138
 
1134
- const path$e = require$$1__default$1;
1139
+ const path$f = require$$1__default$1;
1135
1140
  const fs$g = require$$0__default$1;
1136
1141
  const shelljs$6 = require$$0__default$2;
1137
1142
  const inquirer = require$$1__default$5;
@@ -1149,7 +1154,7 @@ const io$2 = io$3;
1149
1154
  const {
1150
1155
  fail: fail$9,
1151
1156
  succeed: succeed$1,
1152
- info: info$h
1157
+ info: info$i
1153
1158
  } = log$1;
1154
1159
  const generator = generator_1;
1155
1160
  const request = require$$0__default$6;
@@ -1209,7 +1214,7 @@ function downloadAndUnZipTemplate(templateDir, templateUrl, templateName) {
1209
1214
  */
1210
1215
  async function create(projectName) {
1211
1216
  const cwd = process.cwd();
1212
- const targetDir = path$e.resolve(cwd, projectName);
1217
+ const targetDir = path$f.resolve(cwd, projectName);
1213
1218
  const {
1214
1219
  projectType
1215
1220
  } = await inquirer.prompt(CREATE_TEMPLATE_QUESTION);
@@ -1232,7 +1237,7 @@ async function create(projectName) {
1232
1237
  await downloadAndUnZipTemplate(TEMPLATE_DIR, TEMPLATE_URL, TEMPLATE_NAME);
1233
1238
 
1234
1239
  // 生成模板(1. 询问问题, 2. ejs生成模板 3.生成到目标目录)
1235
- generator(path$e.join(TEMPLATE_DIR, TEMPLATE_NAME, projectType), targetDir).then(() => {
1240
+ generator(path$f.join(TEMPLATE_DIR, TEMPLATE_NAME, projectType), targetDir).then(() => {
1236
1241
  shelljs$6.cd(projectName);
1237
1242
  const hookFilePath = resolve$i(projectName, TEMPLATE_TKIT_DIR, 'hooks.js');
1238
1243
  if (fs$g.existsSync(hookFilePath)) {
@@ -1256,13 +1261,13 @@ async function create(projectName) {
1256
1261
  succeed$1('项目创建完成.');
1257
1262
  }).catch(err => {
1258
1263
  fail$9(err.message);
1259
- info$h('详细的错误信息:', err);
1264
+ info$i('详细的错误信息:', err);
1260
1265
  });
1261
1266
  }
1262
1267
  var create_1 = create;
1263
1268
 
1264
1269
  const fs$f = require$$0__default$1;
1265
- const path$d = require$$1__default$1;
1270
+ const path$e = require$$1__default$1;
1266
1271
  const shellJs$3 = require$$0__default$2;
1267
1272
  const {
1268
1273
  ensureDirExist: ensureDirExist$5
@@ -1274,7 +1279,7 @@ const {
1274
1279
  createTask: createTask$6
1275
1280
  } = widgets;
1276
1281
  const {
1277
- info: info$g,
1282
+ info: info$h,
1278
1283
  fail: fail$8
1279
1284
  } = log$1;
1280
1285
 
@@ -1307,7 +1312,7 @@ async function installCmd(npmName, cmd) {
1307
1312
  }), `开始下载${npmName}`, `下载${npmName}完成`)(npmName);
1308
1313
  } catch (e) {
1309
1314
  fail$8('构建出现错误:');
1310
- info$g(e);
1315
+ info$h(e);
1311
1316
  process.exit(1);
1312
1317
  }
1313
1318
  }
@@ -1327,7 +1332,7 @@ function loadExtendCmd$1() {
1327
1332
  Object.keys(deps).forEach(name => {
1328
1333
  // 检索cmd的npm包
1329
1334
  if (!/^tmskit-cmd-|^@[^/]+\/tmskit-cmd-/.test(name)) return false;
1330
- const cmdConfig = path$d.join(cmdNpmDir, name, 'tms.config.js');
1335
+ const cmdConfig = path$e.join(cmdNpmDir, name, 'tms.config.js');
1331
1336
  if (fs$f.existsSync(cmdConfig)) {
1332
1337
  cmdConfigs.push(cmdConfig);
1333
1338
  }
@@ -1378,7 +1383,7 @@ const {
1378
1383
  } = tmsMpconfig.exports;
1379
1384
  const {
1380
1385
  fail: fail$6,
1381
- info: info$f
1386
+ info: info$g
1382
1387
  } = log$1;
1383
1388
  const {
1384
1389
  resolve: resolve$h,
@@ -1534,7 +1539,7 @@ function mergeSubPackages(existingPackages, newPackages) {
1534
1539
 
1535
1540
  if (rootMap[newPkg.root] !== undefined) {
1536
1541
  // 如果已存在相同root的分包,则不覆盖保留原有配置
1537
- info$f(`保留已有分包配置, root: ${newPkg.root}, name: ${newPkg.name || '未命名'}`);
1542
+ info$g(`保留已有分包配置, root: ${newPkg.root}, name: ${newPkg.name || '未命名'}`);
1538
1543
  } else {
1539
1544
  // 如果不存在,则添加新分包
1540
1545
  resultPackages.push(newPkg);
@@ -1543,6 +1548,52 @@ function mergeSubPackages(existingPackages, newPackages) {
1543
1548
  return resultPackages;
1544
1549
  }
1545
1550
 
1551
+ /**
1552
+ * 清理 preloadRule 中引用了不存在分包的条目
1553
+ */
1554
+ function cleanPreloadRule(appJson) {
1555
+ if (!appJson.preloadRule) return;
1556
+ const subpackages = appJson.subpackages || [];
1557
+ const existingSubpackageNames = new Set(subpackages.map(sub => sub.name).filter(Boolean));
1558
+ const existingSubpackageRoots = new Set(subpackages.map(sub => sub.root).filter(Boolean));
1559
+ Object.keys(appJson.preloadRule).forEach(pageKey => {
1560
+ const rule = appJson.preloadRule[pageKey];
1561
+ if (rule.packages) {
1562
+ rule.packages = rule.packages.filter(pkg => existingSubpackageNames.has(pkg) || existingSubpackageRoots.has(pkg));
1563
+ if (rule.packages.length === 0) {
1564
+ delete appJson.preloadRule[pageKey];
1565
+ }
1566
+ }
1567
+ });
1568
+ if (Object.keys(appJson.preloadRule).length === 0) {
1569
+ delete appJson.preloadRule;
1570
+ }
1571
+ }
1572
+
1573
+ /**
1574
+ * 清理 entranceDeclare 中引用了不存在页面的条目
1575
+ */
1576
+ function cleanEntranceDeclare(appJson) {
1577
+ // 收集所有有效页面路径(主包 pages + 分包 pages)
1578
+ const allValidPages = new Set(appJson.pages || []);
1579
+ (appJson.subpackages || []).forEach(sub => {
1580
+ (sub.pages || []).forEach(page => {
1581
+ allValidPages.add(`${sub.root}/${page}`);
1582
+ });
1583
+ });
1584
+ if (!appJson.entranceDeclare) return;
1585
+ Object.keys(appJson.entranceDeclare).forEach(key => {
1586
+ const entry = appJson.entranceDeclare[key];
1587
+ if (entry && entry.path && !allValidPages.has(entry.path)) {
1588
+ info$g(`[devStrictModulesInclude] 移除 entranceDeclare.${key},页面 ${entry.path} 不存在`);
1589
+ delete appJson.entranceDeclare[key];
1590
+ }
1591
+ });
1592
+ if (Object.keys(appJson.entranceDeclare).length === 0) {
1593
+ delete appJson.entranceDeclare;
1594
+ }
1595
+ }
1596
+
1546
1597
  /**
1547
1598
  * 动态生成编译后的app.json
1548
1599
  * @param {object} tmsConfig
@@ -1569,6 +1620,12 @@ async function buildOutputAppJson$3(tmsConfig, modules) {
1569
1620
  // 更新主包,需在subpackages处理完成后执行, pages/
1570
1621
  updateMainPackages(appJson, tmsConfig.mainPackages);
1571
1622
 
1623
+ // devStrictModulesInclude 模式下,清理无效引用
1624
+ if (tmsConfig.devStrictModulesInclude) {
1625
+ cleanPreloadRule(appJson);
1626
+ cleanEntranceDeclare(appJson);
1627
+ }
1628
+
1572
1629
  // 模板渲染:先将 app.json 转为字符串,然后通过 preprocess 渲染
1573
1630
  const appJsonStr = JSON.stringify(appJson, null, 2);
1574
1631
  const preprocessedStr = pp$1.preprocess(appJsonStr, tmsConfig.templateVars || {}, 'json');
@@ -1588,7 +1645,7 @@ async function buildOutputAppJson$3(tmsConfig, modules) {
1588
1645
  return appJson;
1589
1646
  } catch (e) {
1590
1647
  handleError$8(`生成app.json出现错误: ${e}`);
1591
- info$f(e);
1648
+ info$g(e);
1592
1649
  }
1593
1650
  }
1594
1651
  var buildAppJson = {
@@ -1607,7 +1664,7 @@ const {
1607
1664
  } = widgets;
1608
1665
  const {
1609
1666
  fail: fail$5,
1610
- info: info$e
1667
+ info: info$f
1611
1668
  } = log$1;
1612
1669
  const fs$d = require$$0__default$1;
1613
1670
  const shelljs$5 = require$$0__default$2;
@@ -1775,15 +1832,15 @@ function collectDownLoadTasksMap(sourceDir, targetDir, modules) {
1775
1832
  let promiseTask;
1776
1833
  if (fs$d.existsSync(sourcePath) && fs$d.existsSync(`${sourcePath}/.git`)) {
1777
1834
  promiseTask = (gitUrl, sourcePath, branch, httpRepoUrl) => {
1778
- info$e(`git pull:${httpRepoUrl} --branch: ${branch}`);
1835
+ info$f(`git pull:${httpRepoUrl} --branch: ${branch}`);
1779
1836
  return pullRepoForGit(sourcePath, branch).catch(e => {
1780
- info$e(`pull代码失败:${e}, 开始git clone: ${httpRepoUrl}:${branch}`);
1837
+ info$f(`pull代码失败:${e}, 开始git clone: ${httpRepoUrl}:${branch}`);
1781
1838
  return downloadRepoForGit(gitUrl, sourcePath, branch);
1782
1839
  });
1783
1840
  };
1784
1841
  } else {
1785
1842
  promiseTask = (gitUrl, sourcePath, branch, httpRepoUrl) => {
1786
- info$e(`git clone: ${httpRepoUrl}`);
1843
+ info$f(`git clone: ${httpRepoUrl}`);
1787
1844
  return downloadRepoForGit(gitUrl, sourcePath, branch);
1788
1845
  };
1789
1846
  }
@@ -1832,7 +1889,7 @@ var cloneModules_1 = {
1832
1889
  };
1833
1890
 
1834
1891
  const ci = require$$0__default$7;
1835
- const path$c = require$$1__default$1;
1892
+ const path$d = require$$1__default$1;
1836
1893
 
1837
1894
  /**
1838
1895
  * 获取小程序ci的Project对象
@@ -1845,7 +1902,7 @@ const getMpCi = ({
1845
1902
  privateKey = 'TODO'
1846
1903
  }) => {
1847
1904
  var _projectCg$packOption, _projectCg$packOption2;
1848
- const projectCg = require(path$c.join(projectPath, 'project.config.json'));
1905
+ const projectCg = require(path$d.join(projectPath, 'project.config.json'));
1849
1906
  const ignores = (projectCg === null || projectCg === void 0 ? void 0 : (_projectCg$packOption = projectCg.packOptions) === null || _projectCg$packOption === void 0 ? void 0 : (_projectCg$packOption2 = _projectCg$packOption.ignore) === null || _projectCg$packOption2 === void 0 ? void 0 : _projectCg$packOption2.map(({
1850
1907
  value
1851
1908
  }) => value)) || [];
@@ -1991,7 +2048,7 @@ var mpCi$3 = {
1991
2048
  };
1992
2049
 
1993
2050
  const fs$c = require$$0__default$1;
1994
- const path$b = require$$1__default$1;
2051
+ const path$c = require$$1__default$1;
1995
2052
  const {
1996
2053
  NPM_CACHE_FILE
1997
2054
  } = constant;
@@ -2010,7 +2067,7 @@ function getCache$1(projectDir, type) {
2010
2067
  function setCache$1(projectDir, type = 'miniprogram_npm', data) {
2011
2068
  const filePath = NPM_CACHE_FILE;
2012
2069
  if (!fs$c.existsSync(filePath)) {
2013
- const dir = path$b.dirname(filePath);
2070
+ const dir = path$c.dirname(filePath);
2014
2071
  ensureDirExist$4(dir);
2015
2072
  fs$c.writeFileSync(filePath, '{}');
2016
2073
  }
@@ -2034,7 +2091,7 @@ var cache = {
2034
2091
  const fs$b = require$$0__default$1;
2035
2092
  const fsExtra = require$$1__default$7;
2036
2093
  const crypto$1 = require$$1__default$6;
2037
- const path$a = require$$1__default$1;
2094
+ const path$b = require$$1__default$1;
2038
2095
  const shell = require$$0__default$2;
2039
2096
  const log = log$1;
2040
2097
  const {
@@ -2079,15 +2136,15 @@ const collectNpmTasksMap = (packageJsonFiles, cacheDir) => {
2079
2136
  };
2080
2137
  if (Object.keys(md5Obj.dependencies).length !== 0) {
2081
2138
  const md5Key = crypto$1.createHash('md5').update(JSON.stringify(md5Obj)).digest('hex');
2082
- const cacheNMPath = path$a.join(cacheDir, md5Key);
2083
- const cacheNMTarFile = path$a.join(cacheNMPath, 'node_modules.tar.gz');
2139
+ const cacheNMPath = path$b.join(cacheDir, md5Key);
2140
+ const cacheNMTarFile = path$b.join(cacheNMPath, 'node_modules.tar.gz');
2084
2141
 
2085
2142
  // 下载后,添加回调函数 (拷贝node_modules.tar.gz到编译目录并解压)
2086
2143
  const callback = {
2087
2144
  params: {
2088
2145
  cacheNMPath,
2089
2146
  cacheNMTarFile,
2090
- packageJsonDir: path$a.dirname(packageJsonPath),
2147
+ packageJsonDir: path$b.dirname(packageJsonPath),
2091
2148
  shell
2092
2149
  },
2093
2150
  fn: async (cacheNMPath, cacheNMTarFile, packageJsonDir, shell) => {
@@ -2200,7 +2257,7 @@ const findFilesByFilter = (startPath, filter) => {
2200
2257
  }
2201
2258
  const files = fs$b.readdirSync(startPath);
2202
2259
  files.forEach(file => {
2203
- const filename = path$a.join(startPath, file);
2260
+ const filename = path$b.join(startPath, file);
2204
2261
  const stat = fs$b.lstatSync(filename);
2205
2262
  // 当前文件是文件夹类型,继续递归
2206
2263
  if (stat.isDirectory()) {
@@ -2224,10 +2281,10 @@ const findFilesByFilter = (startPath, filter) => {
2224
2281
  const findAllPackageJson = (subRoots = [], contextDir) => {
2225
2282
  const packageJsonName = 'package.json'; // 查找文件名
2226
2283
  const cwd = contextDir || dirPath;
2227
- const result = [path$a.join(cwd, packageJsonName)]; // 默认填充根目录下的package.json
2284
+ const result = [path$b.join(cwd, packageJsonName)]; // 默认填充根目录下的package.json
2228
2285
 
2229
2286
  subRoots.forEach(subRoot => {
2230
- const toppath = path$a.join(cwd, subRoot.root); // 从该目录开始查找package.json文件
2287
+ const toppath = path$b.join(cwd, subRoot.root); // 从该目录开始查找package.json文件
2231
2288
  const list = findFilesByFilter(toppath, packageJsonName);
2232
2289
  result.push(...list);
2233
2290
  });
@@ -2267,7 +2324,7 @@ const {
2267
2324
  resolve: resolve$f,
2268
2325
  getAbsolutePath: getAbsolutePath$5
2269
2326
  } = widgets;
2270
- const path$9 = require$$1__default$1;
2327
+ const path$a = require$$1__default$1;
2271
2328
  const shelljs$4 = require$$0__default$2;
2272
2329
  const {
2273
2330
  handleError: handleError$5
@@ -2285,7 +2342,7 @@ function collectPackageJson(subPackages, cwd, outputDir) {
2285
2342
  const packageJsonName = 'package.json'; // 查找文件名
2286
2343
  // 1.1根目录的package.json
2287
2344
  const packageArr = [{
2288
- srcPackageDir: path$9.join(cwd, packageJsonName),
2345
+ srcPackageDir: path$a.join(cwd, packageJsonName),
2289
2346
  destNpmDir: resolve$f(outputDir, 'node_modules')
2290
2347
  }];
2291
2348
  // 1.2模块的package.json
@@ -2334,11 +2391,11 @@ const checkPackageVersion$1 = packageArr => {
2334
2391
  const dependencies = readPackageDependencies(item.srcPackageDir);
2335
2392
  const dependenciesKeys = Object.keys(dependencies);
2336
2393
  for (const key of dependenciesKeys) {
2337
- const depPath = path$9.join(item.destNpmDir, key);
2394
+ const depPath = path$a.join(item.destNpmDir, key);
2338
2395
  if (!fs$9.existsSync(depPath)) {
2339
2396
  return true;
2340
2397
  }
2341
- const depPackagePath = path$9.join(depPath, 'package.json');
2398
+ const depPackagePath = path$a.join(depPath, 'package.json');
2342
2399
  if (fs$9.existsSync(depPackagePath)) {
2343
2400
  const packageData = require(depPackagePath);
2344
2401
  if (dependencies[key] === 'latest') {
@@ -2362,7 +2419,7 @@ var checkDependencies = {
2362
2419
 
2363
2420
  const shelljs$3 = require$$0__default$2;
2364
2421
  const fs$8 = require$$0__default$1;
2365
- const path$8 = require$$1__default$1;
2422
+ const path$9 = require$$1__default$1;
2366
2423
  const io$1 = io$3;
2367
2424
  const {
2368
2425
  createTask: createTask$5,
@@ -2387,7 +2444,7 @@ const {
2387
2444
  npmInstallAll
2388
2445
  } = npm;
2389
2446
  const {
2390
- info: info$d
2447
+ info: info$e
2391
2448
  } = log$1;
2392
2449
  const {
2393
2450
  fileMd5
@@ -2401,12 +2458,12 @@ async function install$3(tmsConfig, subPackages, useCache = true) {
2401
2458
  // 加npm install之前的钩子
2402
2459
  if (typeof (tmsConfig === null || tmsConfig === void 0 ? void 0 : (_tmsConfig$hooks = tmsConfig.hooks) === null || _tmsConfig$hooks === void 0 ? void 0 : _tmsConfig$hooks.beforeNpmInstall) === 'function') {
2403
2460
  var _tmsConfig$hooks2;
2404
- info$d('—————— 执行beforeNpmInstall ————');
2461
+ info$e('—————— 执行beforeNpmInstall ————');
2405
2462
  await (tmsConfig === null || tmsConfig === void 0 ? void 0 : (_tmsConfig$hooks2 = tmsConfig.hooks) === null || _tmsConfig$hooks2 === void 0 ? void 0 : _tmsConfig$hooks2.beforeNpmInstall({
2406
2463
  tmsConfig: filterField$6(tmsConfig, ['gitAccount']),
2407
2464
  cmdOptions: global$7.getData('cmdOptions')
2408
2465
  }));
2409
- info$d('—————— 执行beforeNpmInstall 完成 ————');
2466
+ info$e('—————— 执行beforeNpmInstall 完成 ————');
2410
2467
  }
2411
2468
  const npmInstallRes = await createTask$5(npmInstall$1, '小程序 开始npm install', '小程序npm install 完成')(tmsConfig, subPackages, useCache);
2412
2469
 
@@ -2423,7 +2480,7 @@ async function install$3(tmsConfig, subPackages, useCache = true) {
2423
2480
  async function npmInstall$1(tmsConfig, subPackages, useCache) {
2424
2481
  // 如果依赖没有更新和使用缓存数据(则命中缓存)
2425
2482
  if (!isDependenciesUpdate(subPackages, resolve$e('./'), tmsConfig.outputDir) && useCache) {
2426
- info$d('node_modules命中缓存');
2483
+ info$e('node_modules命中缓存');
2427
2484
  return {
2428
2485
  isCache: true
2429
2486
  };
@@ -2462,7 +2519,7 @@ async function mpCiInstall(tmsConfig, subPackages, useCache) {
2462
2519
  if (useCache) {
2463
2520
  let flag = true;
2464
2521
  await Promise.all(packageJsonFiles.map(async item => {
2465
- const packageDir = path$8.dirname(item);
2522
+ const packageDir = path$9.dirname(item);
2466
2523
  const mpDir = resolve$e(`${packageDir}/miniprogram_npm`);
2467
2524
  const md5Value = await getMNPMd5(packageDir);
2468
2525
  const preCache = getCache(mpDir, 'miniprogram_npm');
@@ -2475,13 +2532,13 @@ async function mpCiInstall(tmsConfig, subPackages, useCache) {
2475
2532
  isCache = flag;
2476
2533
  }
2477
2534
  if (isCache) {
2478
- info$d('miniprogram_npm命中缓存');
2535
+ info$e('miniprogram_npm命中缓存');
2479
2536
  return;
2480
2537
  }
2481
2538
 
2482
2539
  // 即将构建,在cache中标记开始
2483
2540
  await Promise.all(packageJsonFiles.map(async item => {
2484
- const packageDir = path$8.dirname(item);
2541
+ const packageDir = path$9.dirname(item);
2485
2542
  const mpDir = resolve$e(`${packageDir}/miniprogram_npm`);
2486
2543
  setCache(mpDir, 'miniprogram_npm', {
2487
2544
  md5: '',
@@ -2496,7 +2553,7 @@ async function mpCiInstall(tmsConfig, subPackages, useCache) {
2496
2553
 
2497
2554
  // 构建成功后,计算md5写入cache
2498
2555
  await Promise.all(packageJsonFiles.map(async item => {
2499
- const packageDir = path$8.dirname(item);
2556
+ const packageDir = path$9.dirname(item);
2500
2557
  const mpDir = resolve$e(`${packageDir}/miniprogram_npm`);
2501
2558
  const md5Value = await getMNPMd5(packageDir);
2502
2559
  setCache(mpDir, 'miniprogram_npm', {
@@ -2518,7 +2575,7 @@ async function getMNPMd5(cwd) {
2518
2575
  cwd,
2519
2576
  ...shellJsOption
2520
2577
  });
2521
- const tarDir = path$8.join(cwd, './miniprogram_npm.tar.gz');
2578
+ const tarDir = path$9.join(cwd, './miniprogram_npm.tar.gz');
2522
2579
  const md5Value = await fileMd5(tarDir);
2523
2580
  shelljs$3.rm('-rf', tarDir);
2524
2581
  return md5Value;
@@ -2550,7 +2607,7 @@ const {
2550
2607
  } = tmsMpconfig.exports;
2551
2608
  const {
2552
2609
  fail: fail$4,
2553
- info: info$c
2610
+ info: info$d
2554
2611
  } = log$1;
2555
2612
  const install$2 = install_1;
2556
2613
 
@@ -2599,7 +2656,7 @@ async function init$3(tmsConfig, targetModules) {
2599
2656
  } catch (error) {
2600
2657
  const errMsg = typeof error === 'object' ? error.message : error;
2601
2658
  fail$4(`初始化流程出现错误: ${errMsg}`);
2602
- info$c('详细的错误信息', error);
2659
+ info$d('详细的错误信息', error);
2603
2660
  process.exit(1);
2604
2661
  }
2605
2662
  }
@@ -2621,6 +2678,195 @@ function mpProjectJson$1() {
2621
2678
  }
2622
2679
  var mpProjectJson_1 = mpProjectJson$1;
2623
2680
 
2681
+ /**
2682
+ * 严格模块引用过滤插件
2683
+ * 当 devStrictModulesInclude 开启时,过滤 JSON 文件中 usingComponents 里
2684
+ * 指向当前编译模块集合之外的组件引用
2685
+ *
2686
+ * 判断逻辑:
2687
+ * 1. 优先判断组件是否在当前模块的输出目录内(短路)
2688
+ * 2. 否则检查是否落在其他已编译模块的 modulePath 下
2689
+ * 3. 都不满足则移除
2690
+ */
2691
+ const through$2 = require$$0__default$8;
2692
+ const path$8 = require$$1__default$1;
2693
+ const {
2694
+ info: info$c
2695
+ } = log$1;
2696
+
2697
+ /**
2698
+ * 统一路径分隔符为 /(兼容 Windows)
2699
+ */
2700
+ function normalizePath(p) {
2701
+ return p.replace(/\\/g, '/');
2702
+ }
2703
+
2704
+ /**
2705
+ * 将组件路径 resolve 为 dist 中的绝对路径
2706
+ */
2707
+ function resolveComponentPath(componentPath, currentFileDestPath, outputDir) {
2708
+ if (componentPath.startsWith('/')) {
2709
+ return path$8.resolve(outputDir, componentPath.slice(1));
2710
+ }
2711
+ const currentDir = path$8.dirname(currentFileDestPath);
2712
+ return path$8.resolve(currentDir, componentPath);
2713
+ }
2714
+
2715
+ /**
2716
+ * 检查组件路径是否属于某个已编译模块
2717
+ */
2718
+ function isInValidModule(relativeToOutput, validModulePaths) {
2719
+ for (const modulePath of validModulePaths) {
2720
+ if (relativeToOutput === modulePath || relativeToOutput.startsWith(`${modulePath}/`)) {
2721
+ return true;
2722
+ }
2723
+ }
2724
+ return false;
2725
+ }
2726
+
2727
+ /**
2728
+ * 判断组件路径是否应该被移除
2729
+ * @param {string} componentPath usingComponents 中的路径
2730
+ * @param {string} currentFileDestPath 当前文件的编译输出绝对路径
2731
+ * @param {string} outputDir 编译输出根目录的绝对路径
2732
+ * @param {string} moduleDestPath 当前模块的编译输出绝对路径
2733
+ * @param {Set<string>} validModulePaths 所有已编译模块的 modulePath 集合(相对于 outputDir,/ 分隔)
2734
+ * @returns {boolean} true 表示应该移除该引用
2735
+ */
2736
+ function shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths) {
2737
+ // 插件引用 (plugin:// / plugin-private://) 不做处理
2738
+ if (componentPath.startsWith('plugin://') || componentPath.startsWith('plugin-private://')) {
2739
+ return false;
2740
+ }
2741
+
2742
+ // 非相对路径且非小程序绝对路径不处理(npm 包如 @tmsfe/tms-ui 等)
2743
+ if (!componentPath.startsWith('.') && !componentPath.startsWith('/')) {
2744
+ return false;
2745
+ }
2746
+ const resolvedPath = resolveComponentPath(componentPath, currentFileDestPath, outputDir);
2747
+
2748
+ // 优先判断:组件是否在当前模块的输出目录内
2749
+ const relativeToModule = normalizePath(path$8.relative(moduleDestPath, resolvedPath));
2750
+ if (!relativeToModule.startsWith('..')) {
2751
+ return false;
2752
+ }
2753
+
2754
+ // 组件在当前模块外,检查是否属于其他已编译模块
2755
+ const relativeToOutput = normalizePath(path$8.relative(outputDir, resolvedPath));
2756
+
2757
+ // 路径离开了 outputDir(以 .. 开头),保留不处理
2758
+ if (relativeToOutput.startsWith('..')) {
2759
+ return false;
2760
+ }
2761
+
2762
+ // 不属于任何已编译模块 → 移除
2763
+ return !isInValidModule(relativeToOutput, validModulePaths);
2764
+ }
2765
+
2766
+ /**
2767
+ * 获取所有有效的模块输出路径集合
2768
+ */
2769
+ function getValidModulePaths(tmsConfig) {
2770
+ if (tmsConfig._validModulePaths) return tmsConfig._validModulePaths;
2771
+ const paths = new Set();
2772
+ const compiledModules = tmsConfig._compiledModules || [];
2773
+ compiledModules.forEach(m => {
2774
+ if (m.modulePath) {
2775
+ paths.add(normalizePath(m.modulePath));
2776
+ }
2777
+ if (m.subPackages) {
2778
+ m.subPackages.forEach(sub => {
2779
+ if (sub.root) {
2780
+ paths.add(normalizePath(sub.root));
2781
+ }
2782
+ });
2783
+ }
2784
+ });
2785
+ const outputDir = path$8.resolve(tmsConfig.outputDir);
2786
+ const staticDirs = tmsConfig.static || [];
2787
+ staticDirs.forEach(item => {
2788
+ if (item.to) {
2789
+ const toAbsolute = path$8.resolve(item.to);
2790
+ const rel = normalizePath(path$8.relative(outputDir, toAbsolute));
2791
+ if (!rel.startsWith('..')) {
2792
+ paths.add(rel);
2793
+ }
2794
+ }
2795
+ });
2796
+
2797
+ // eslint-disable-next-line no-param-reassign
2798
+ tmsConfig._validModulePaths = paths;
2799
+ return paths;
2800
+ }
2801
+
2802
+ /**
2803
+ * 处理单个 JSON 文件,移除无效组件引用
2804
+ */
2805
+ function processJsonFile(file, moduleDestPath, moduleFromPath, outputDir, validModulePaths) {
2806
+ let json;
2807
+ try {
2808
+ json = JSON.parse(String(file.contents));
2809
+ } catch (e) {
2810
+ return file;
2811
+ }
2812
+ if (!json.usingComponents || typeof json.usingComponents !== 'object') {
2813
+ return file;
2814
+ }
2815
+ const currentFileSrcPath = file.history[0] || file.path;
2816
+ const relativeToModuleSrc = path$8.relative(moduleFromPath, currentFileSrcPath);
2817
+ const currentFileDestPath = path$8.join(moduleDestPath, relativeToModuleSrc);
2818
+ const keysToRemove = [];
2819
+ Object.keys(json.usingComponents).forEach(componentKey => {
2820
+ const componentPath = json.usingComponents[componentKey];
2821
+ if (shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths)) {
2822
+ keysToRemove.push(componentKey);
2823
+ }
2824
+ });
2825
+ if (keysToRemove.length > 0) {
2826
+ keysToRemove.forEach(key => {
2827
+ info$c(`[strictModulesFilter] 移除 ${path$8.basename(currentFileSrcPath)} 中的组件引用: ${key} -> ${json.usingComponents[key]}`);
2828
+ delete json.usingComponents[key];
2829
+ if (json.componentPlaceholder && json.componentPlaceholder[key]) {
2830
+ delete json.componentPlaceholder[key];
2831
+ }
2832
+ });
2833
+ // eslint-disable-next-line no-param-reassign
2834
+ file.contents = Buffer.from(JSON.stringify(json, null, 2));
2835
+ }
2836
+ return file;
2837
+ }
2838
+
2839
+ /**
2840
+ * 严格模块过滤 gulp 插件
2841
+ * @param {Object} tmsConfig 配置对象
2842
+ * @param {Object} module 当前编译模块信息 { from, to }
2843
+ * @returns {Object} through2 转换流
2844
+ */
2845
+ function strictModulesFilter$1(tmsConfig, module) {
2846
+ if (!tmsConfig.devStrictModulesInclude) {
2847
+ return through$2.obj();
2848
+ }
2849
+ const moduleDestPath = module.to ? path$8.resolve(module.to) : null;
2850
+ const moduleFromPath = module.from ? path$8.resolve(module.from) : null;
2851
+ const outputDir = path$8.resolve(tmsConfig.outputDir);
2852
+ return through$2.obj(function (file, enc, cb) {
2853
+ if (!file.isBuffer() || !file.path.endsWith('.json')) {
2854
+ this.push(file);
2855
+ return cb();
2856
+ }
2857
+ if (module.custom || !moduleDestPath || !moduleFromPath || moduleDestPath === outputDir) {
2858
+ this.push(file);
2859
+ return cb();
2860
+ }
2861
+ const validModulePaths = getValidModulePaths(tmsConfig);
2862
+ this.push(processJsonFile(file, moduleDestPath, moduleFromPath, outputDir, validModulePaths));
2863
+ return cb();
2864
+ });
2865
+ }
2866
+ var strictModulesFilter_1 = {
2867
+ strictModulesFilter: strictModulesFilter$1
2868
+ };
2869
+
2624
2870
  /* eslint-disable @typescript-eslint/no-require-imports */
2625
2871
  const through$1 = require$$0__default$8;
2626
2872
  const pp = require$$1__default$3;
@@ -2724,6 +2970,9 @@ const path$6 = require$$1__default$1;
2724
2970
  const minimatch = require$$2__default;
2725
2971
  const gulpif = require$$3__default$1;
2726
2972
  const mpProjectJson = mpProjectJson_1;
2973
+ const {
2974
+ strictModulesFilter
2975
+ } = strictModulesFilter_1;
2727
2976
  const {
2728
2977
  resolve: resolve$c
2729
2978
  } = widgets;
@@ -2778,6 +3027,9 @@ var compile$1 = function (tmsConfig, {
2778
3027
  const templateRender = tmsTemplateRender;
2779
3028
  srcPipe = srcPipe.pipe(templateRender(tmsConfig));
2780
3029
 
3030
+ // 严格模块过滤:移除 usingComponents 中不在编译模块内的引用
3031
+ srcPipe = srcPipe.pipe(strictModulesFilter(tmsConfig, module));
3032
+
2781
3033
  // 后续步骤继续执行其他插件
2782
3034
  const pluginParams = {
2783
3035
  module,
@@ -4072,6 +4324,9 @@ function otherCommands(tmsConfig, commandName, cmdOptions) {
4072
4324
  const newModules = getModulesByMergeDepModules(tmsConfig, modules, false);
4073
4325
  // 获取所有的分包
4074
4326
  const subPackages = getSubPackages(newModules);
4327
+
4328
+ // 将已编译模块列表注入 tmsConfig,供 strictModulesFilter 插件使用
4329
+ tmsConfig._compiledModules = newModules;
4075
4330
  switch (commandName) {
4076
4331
  case 'init':
4077
4332
  init(tmsConfig, newModules);
@@ -4206,7 +4461,7 @@ var entry = [{
4206
4461
 
4207
4462
  var require$$12 = {
4208
4463
  name: "@tmsfe/tmskit",
4209
- version: "0.0.65",
4464
+ version: "0.0.67",
4210
4465
  description: "tmskit",
4211
4466
  main: "dist/index.cjs",
4212
4467
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmsfe/tmskit",
3
- "version": "0.0.65",
3
+ "version": "0.0.67",
4
4
  "description": "tmskit",
5
5
  "main": "dist/index.cjs",
6
6
  "bin": {
@@ -3,6 +3,7 @@ const path = require('path');
3
3
  const minimatch = require('minimatch');
4
4
  const gulpif = require('gulp-if');
5
5
  const mpProjectJson = require('./plugins/mpProjectJson');
6
+ const { strictModulesFilter } = require('./plugins/strictModulesFilter');
6
7
  const { resolve } = require('../utils/widgets');
7
8
  const through = require('through2');
8
9
  const { fail } = require('../utils/log');
@@ -60,6 +61,9 @@ module.exports = function (
60
61
  const templateRender = require('./plugins/tmsTemplateRender');
61
62
  srcPipe = srcPipe.pipe(templateRender(tmsConfig));
62
63
 
64
+ // 严格模块过滤:移除 usingComponents 中不在编译模块内的引用
65
+ srcPipe = srcPipe.pipe(strictModulesFilter(tmsConfig, module));
66
+
63
67
  // 后续步骤继续执行其他插件
64
68
  const pluginParams = { module, isDev };
65
69
  srcPipe = addPlugins(tmsConfig, srcPipe, pluginParams);
@@ -0,0 +1,199 @@
1
+ /**
2
+ * 严格模块引用过滤插件
3
+ * 当 devStrictModulesInclude 开启时,过滤 JSON 文件中 usingComponents 里
4
+ * 指向当前编译模块集合之外的组件引用
5
+ *
6
+ * 判断逻辑:
7
+ * 1. 优先判断组件是否在当前模块的输出目录内(短路)
8
+ * 2. 否则检查是否落在其他已编译模块的 modulePath 下
9
+ * 3. 都不满足则移除
10
+ */
11
+ const through = require('through2');
12
+ const path = require('path');
13
+ const { info } = require('../../utils/log');
14
+
15
+ /**
16
+ * 统一路径分隔符为 /(兼容 Windows)
17
+ */
18
+ function normalizePath(p) {
19
+ return p.replace(/\\/g, '/');
20
+ }
21
+
22
+ /**
23
+ * 将组件路径 resolve 为 dist 中的绝对路径
24
+ */
25
+ function resolveComponentPath(componentPath, currentFileDestPath, outputDir) {
26
+ if (componentPath.startsWith('/')) {
27
+ return path.resolve(outputDir, componentPath.slice(1));
28
+ }
29
+ const currentDir = path.dirname(currentFileDestPath);
30
+ return path.resolve(currentDir, componentPath);
31
+ }
32
+
33
+ /**
34
+ * 检查组件路径是否属于某个已编译模块
35
+ */
36
+ function isInValidModule(relativeToOutput, validModulePaths) {
37
+ for (const modulePath of validModulePaths) {
38
+ if (relativeToOutput === modulePath || relativeToOutput.startsWith(`${modulePath}/`)) {
39
+ return true;
40
+ }
41
+ }
42
+ return false;
43
+ }
44
+
45
+ /**
46
+ * 判断组件路径是否应该被移除
47
+ * @param {string} componentPath usingComponents 中的路径
48
+ * @param {string} currentFileDestPath 当前文件的编译输出绝对路径
49
+ * @param {string} outputDir 编译输出根目录的绝对路径
50
+ * @param {string} moduleDestPath 当前模块的编译输出绝对路径
51
+ * @param {Set<string>} validModulePaths 所有已编译模块的 modulePath 集合(相对于 outputDir,/ 分隔)
52
+ * @returns {boolean} true 表示应该移除该引用
53
+ */
54
+ function shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths) {
55
+ // 插件引用 (plugin:// / plugin-private://) 不做处理
56
+ if (componentPath.startsWith('plugin://') || componentPath.startsWith('plugin-private://')) {
57
+ return false;
58
+ }
59
+
60
+ // 非相对路径且非小程序绝对路径不处理(npm 包如 @tmsfe/tms-ui 等)
61
+ if (!componentPath.startsWith('.') && !componentPath.startsWith('/')) {
62
+ return false;
63
+ }
64
+
65
+ const resolvedPath = resolveComponentPath(componentPath, currentFileDestPath, outputDir);
66
+
67
+ // 优先判断:组件是否在当前模块的输出目录内
68
+ const relativeToModule = normalizePath(path.relative(moduleDestPath, resolvedPath));
69
+ if (!relativeToModule.startsWith('..')) {
70
+ return false;
71
+ }
72
+
73
+ // 组件在当前模块外,检查是否属于其他已编译模块
74
+ const relativeToOutput = normalizePath(path.relative(outputDir, resolvedPath));
75
+
76
+ // 路径离开了 outputDir(以 .. 开头),保留不处理
77
+ if (relativeToOutput.startsWith('..')) {
78
+ return false;
79
+ }
80
+
81
+ // 不属于任何已编译模块 → 移除
82
+ return !isInValidModule(relativeToOutput, validModulePaths);
83
+ }
84
+
85
+ /**
86
+ * 获取所有有效的模块输出路径集合
87
+ */
88
+ function getValidModulePaths(tmsConfig) {
89
+ if (tmsConfig._validModulePaths) return tmsConfig._validModulePaths;
90
+
91
+ const paths = new Set();
92
+ const compiledModules = tmsConfig._compiledModules || [];
93
+ compiledModules.forEach((m) => {
94
+ if (m.modulePath) {
95
+ paths.add(normalizePath(m.modulePath));
96
+ }
97
+ if (m.subPackages) {
98
+ m.subPackages.forEach((sub) => {
99
+ if (sub.root) {
100
+ paths.add(normalizePath(sub.root));
101
+ }
102
+ });
103
+ }
104
+ });
105
+
106
+ const outputDir = path.resolve(tmsConfig.outputDir);
107
+ const staticDirs = tmsConfig.static || [];
108
+ staticDirs.forEach((item) => {
109
+ if (item.to) {
110
+ const toAbsolute = path.resolve(item.to);
111
+ const rel = normalizePath(path.relative(outputDir, toAbsolute));
112
+ if (!rel.startsWith('..')) {
113
+ paths.add(rel);
114
+ }
115
+ }
116
+ });
117
+
118
+ // eslint-disable-next-line no-param-reassign
119
+ tmsConfig._validModulePaths = paths;
120
+ return paths;
121
+ }
122
+
123
+ /**
124
+ * 处理单个 JSON 文件,移除无效组件引用
125
+ */
126
+ function processJsonFile(file, moduleDestPath, moduleFromPath, outputDir, validModulePaths) {
127
+ let json;
128
+ try {
129
+ json = JSON.parse(String(file.contents));
130
+ } catch (e) {
131
+ return file;
132
+ }
133
+
134
+ if (!json.usingComponents || typeof json.usingComponents !== 'object') {
135
+ return file;
136
+ }
137
+
138
+ const currentFileSrcPath = file.history[0] || file.path;
139
+ const relativeToModuleSrc = path.relative(moduleFromPath, currentFileSrcPath);
140
+ const currentFileDestPath = path.join(moduleDestPath, relativeToModuleSrc);
141
+
142
+ const keysToRemove = [];
143
+ Object.keys(json.usingComponents).forEach((componentKey) => {
144
+ const componentPath = json.usingComponents[componentKey];
145
+ if (shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths)) {
146
+ keysToRemove.push(componentKey);
147
+ }
148
+ });
149
+
150
+ if (keysToRemove.length > 0) {
151
+ keysToRemove.forEach((key) => {
152
+ info(`[strictModulesFilter] 移除 ${path.basename(currentFileSrcPath)} 中的组件引用: ${key} -> ${json.usingComponents[key]}`);
153
+ delete json.usingComponents[key];
154
+ if (json.componentPlaceholder && json.componentPlaceholder[key]) {
155
+ delete json.componentPlaceholder[key];
156
+ }
157
+ });
158
+ // eslint-disable-next-line no-param-reassign
159
+ file.contents = Buffer.from(JSON.stringify(json, null, 2));
160
+ }
161
+
162
+ return file;
163
+ }
164
+
165
+ /**
166
+ * 严格模块过滤 gulp 插件
167
+ * @param {Object} tmsConfig 配置对象
168
+ * @param {Object} module 当前编译模块信息 { from, to }
169
+ * @returns {Object} through2 转换流
170
+ */
171
+ function strictModulesFilter(tmsConfig, module) {
172
+ if (!tmsConfig.devStrictModulesInclude) {
173
+ return through.obj();
174
+ }
175
+
176
+ const moduleDestPath = module.to ? path.resolve(module.to) : null;
177
+ const moduleFromPath = module.from ? path.resolve(module.from) : null;
178
+ const outputDir = path.resolve(tmsConfig.outputDir);
179
+
180
+ return through.obj(function (file, enc, cb) {
181
+ if (!file.isBuffer() || !file.path.endsWith('.json')) {
182
+ this.push(file);
183
+ return cb();
184
+ }
185
+
186
+ if (module.custom || !moduleDestPath || !moduleFromPath || moduleDestPath === outputDir) {
187
+ this.push(file);
188
+ return cb();
189
+ }
190
+
191
+ const validModulePaths = getValidModulePaths(tmsConfig);
192
+ this.push(processJsonFile(file, moduleDestPath, moduleFromPath, outputDir, validModulePaths));
193
+ return cb();
194
+ });
195
+ }
196
+
197
+ module.exports = {
198
+ strictModulesFilter,
199
+ };
@@ -168,6 +168,58 @@ function mergeSubPackages(existingPackages, newPackages) {
168
168
  return resultPackages;
169
169
  }
170
170
 
171
+ /**
172
+ * 清理 preloadRule 中引用了不存在分包的条目
173
+ */
174
+ function cleanPreloadRule(appJson) {
175
+ if (!appJson.preloadRule) return;
176
+
177
+ const subpackages = appJson.subpackages || [];
178
+ const existingSubpackageNames = new Set(subpackages.map(sub => sub.name).filter(Boolean));
179
+ const existingSubpackageRoots = new Set(subpackages.map(sub => sub.root).filter(Boolean));
180
+
181
+ Object.keys(appJson.preloadRule).forEach((pageKey) => {
182
+ const rule = appJson.preloadRule[pageKey];
183
+ if (rule.packages) {
184
+ rule.packages = rule.packages.filter(pkg => existingSubpackageNames.has(pkg) || existingSubpackageRoots.has(pkg));
185
+ if (rule.packages.length === 0) {
186
+ delete appJson.preloadRule[pageKey];
187
+ }
188
+ }
189
+ });
190
+
191
+ if (Object.keys(appJson.preloadRule).length === 0) {
192
+ delete appJson.preloadRule;
193
+ }
194
+ }
195
+
196
+ /**
197
+ * 清理 entranceDeclare 中引用了不存在页面的条目
198
+ */
199
+ function cleanEntranceDeclare(appJson) {
200
+ // 收集所有有效页面路径(主包 pages + 分包 pages)
201
+ const allValidPages = new Set(appJson.pages || []);
202
+ (appJson.subpackages || []).forEach((sub) => {
203
+ (sub.pages || []).forEach((page) => {
204
+ allValidPages.add(`${sub.root}/${page}`);
205
+ });
206
+ });
207
+
208
+ if (!appJson.entranceDeclare) return;
209
+
210
+ Object.keys(appJson.entranceDeclare).forEach((key) => {
211
+ const entry = appJson.entranceDeclare[key];
212
+ if (entry && entry.path && !allValidPages.has(entry.path)) {
213
+ info(`[devStrictModulesInclude] 移除 entranceDeclare.${key},页面 ${entry.path} 不存在`);
214
+ delete appJson.entranceDeclare[key];
215
+ }
216
+ });
217
+
218
+ if (Object.keys(appJson.entranceDeclare).length === 0) {
219
+ delete appJson.entranceDeclare;
220
+ }
221
+ }
222
+
171
223
  /**
172
224
  * 动态生成编译后的app.json
173
225
  * @param {object} tmsConfig
@@ -193,6 +245,12 @@ async function buildOutputAppJson(tmsConfig, modules) {
193
245
  // 更新主包,需在subpackages处理完成后执行, pages/
194
246
  updateMainPackages(appJson, tmsConfig.mainPackages);
195
247
 
248
+ // devStrictModulesInclude 模式下,清理无效引用
249
+ if (tmsConfig.devStrictModulesInclude) {
250
+ cleanPreloadRule(appJson);
251
+ cleanEntranceDeclare(appJson);
252
+ }
253
+
196
254
  // 模板渲染:先将 app.json 转为字符串,然后通过 preprocess 渲染
197
255
  const appJsonStr = JSON.stringify(appJson, null, 2);
198
256
  const preprocessedStr = pp.preprocess(appJsonStr, tmsConfig.templateVars || {}, 'json');
@@ -245,6 +245,7 @@ const checkModuleItem = (tmsConfig, tmsModuleItem, moduleConfig) => {
245
245
  * @returns
246
246
  */
247
247
  const getModulesByMergeDepModules = (tmsConfig, modules, errorIsQuit = false) => {
248
+ const devStrictMode = !!tmsConfig.devStrictModulesInclude;
248
249
  const allModules = new Map();
249
250
  function dfs(tmsConfig, modules) {
250
251
  modules.forEach((moduleItem) => {
@@ -266,9 +267,12 @@ const getModulesByMergeDepModules = (tmsConfig, modules, errorIsQuit = false) =>
266
267
  if (!allModules.has(moduleItem.moduleName)) {
267
268
  allModules.set(moduleItem.moduleName, checkModuleItem(tmsConfig, moduleItem, moduleConfig));
268
269
 
269
- const dependenciesModules = getModulesByModuleNames(tmsConfig, moduleConfig?.dependencies);
270
- if (dependenciesModules.length) {
271
- dfs(tmsConfig, dependenciesModules);
270
+ // devStrictModulesInclude 模式下忽略 dependencies,不递归加载依赖模块
271
+ if (!devStrictMode) {
272
+ const dependenciesModules = getModulesByModuleNames(tmsConfig, moduleConfig?.dependencies);
273
+ if (dependenciesModules.length) {
274
+ dfs(tmsConfig, dependenciesModules);
275
+ }
272
276
  }
273
277
  }
274
278
  });
@@ -96,6 +96,9 @@ function otherCommands(tmsConfig, commandName, cmdOptions) {
96
96
  // 获取所有的分包
97
97
  const subPackages = getSubPackages(newModules);
98
98
 
99
+ // 将已编译模块列表注入 tmsConfig,供 strictModulesFilter 插件使用
100
+ tmsConfig._compiledModules = newModules;
101
+
99
102
  switch (commandName) {
100
103
  case 'init':
101
104
  init(tmsConfig, newModules);