@tmsfe/tmskit 0.0.65 → 0.0.66

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);
@@ -1569,6 +1574,49 @@ async function buildOutputAppJson$3(tmsConfig, modules) {
1569
1574
  // 更新主包,需在subpackages处理完成后执行, pages/
1570
1575
  updateMainPackages(appJson, tmsConfig.mainPackages);
1571
1576
 
1577
+ // devStrictModulesInclude 模式下,清理 preloadRule 中引用了不存在分包的条目
1578
+ if (tmsConfig.devStrictModulesInclude && appJson.preloadRule) {
1579
+ const existingSubpackageNames = new Set((appJson.subpackages || []).map(sub => sub.name).filter(Boolean));
1580
+ const existingSubpackageRoots = new Set((appJson.subpackages || []).map(sub => sub.root).filter(Boolean));
1581
+ Object.keys(appJson.preloadRule).forEach(pageKey => {
1582
+ const rule = appJson.preloadRule[pageKey];
1583
+ if (rule.packages) {
1584
+ rule.packages = rule.packages.filter(pkg => existingSubpackageNames.has(pkg) || existingSubpackageRoots.has(pkg));
1585
+ if (rule.packages.length === 0) {
1586
+ delete appJson.preloadRule[pageKey];
1587
+ }
1588
+ }
1589
+ });
1590
+ if (Object.keys(appJson.preloadRule).length === 0) {
1591
+ delete appJson.preloadRule;
1592
+ }
1593
+ }
1594
+
1595
+ // devStrictModulesInclude 模式下,清理引用了不存在页面路径的字段
1596
+ if (tmsConfig.devStrictModulesInclude) {
1597
+ // 收集所有有效页面路径(主包 pages + 分包 pages)
1598
+ const allValidPages = new Set(appJson.pages || []);
1599
+ (appJson.subpackages || []).forEach(sub => {
1600
+ (sub.pages || []).forEach(page => {
1601
+ allValidPages.add(`${sub.root}/${page}`);
1602
+ });
1603
+ });
1604
+
1605
+ // 清理 entranceDeclare 中引用了不存在页面的条目
1606
+ if (appJson.entranceDeclare) {
1607
+ Object.keys(appJson.entranceDeclare).forEach(key => {
1608
+ const entry = appJson.entranceDeclare[key];
1609
+ if (entry && entry.path && !allValidPages.has(entry.path)) {
1610
+ info$g(`[devStrictModulesInclude] 移除 entranceDeclare.${key},页面 ${entry.path} 不存在`);
1611
+ delete appJson.entranceDeclare[key];
1612
+ }
1613
+ });
1614
+ if (Object.keys(appJson.entranceDeclare).length === 0) {
1615
+ delete appJson.entranceDeclare;
1616
+ }
1617
+ }
1618
+ }
1619
+
1572
1620
  // 模板渲染:先将 app.json 转为字符串,然后通过 preprocess 渲染
1573
1621
  const appJsonStr = JSON.stringify(appJson, null, 2);
1574
1622
  const preprocessedStr = pp$1.preprocess(appJsonStr, tmsConfig.templateVars || {}, 'json');
@@ -1588,7 +1636,7 @@ async function buildOutputAppJson$3(tmsConfig, modules) {
1588
1636
  return appJson;
1589
1637
  } catch (e) {
1590
1638
  handleError$8(`生成app.json出现错误: ${e}`);
1591
- info$f(e);
1639
+ info$g(e);
1592
1640
  }
1593
1641
  }
1594
1642
  var buildAppJson = {
@@ -1607,7 +1655,7 @@ const {
1607
1655
  } = widgets;
1608
1656
  const {
1609
1657
  fail: fail$5,
1610
- info: info$e
1658
+ info: info$f
1611
1659
  } = log$1;
1612
1660
  const fs$d = require$$0__default$1;
1613
1661
  const shelljs$5 = require$$0__default$2;
@@ -1775,15 +1823,15 @@ function collectDownLoadTasksMap(sourceDir, targetDir, modules) {
1775
1823
  let promiseTask;
1776
1824
  if (fs$d.existsSync(sourcePath) && fs$d.existsSync(`${sourcePath}/.git`)) {
1777
1825
  promiseTask = (gitUrl, sourcePath, branch, httpRepoUrl) => {
1778
- info$e(`git pull:${httpRepoUrl} --branch: ${branch}`);
1826
+ info$f(`git pull:${httpRepoUrl} --branch: ${branch}`);
1779
1827
  return pullRepoForGit(sourcePath, branch).catch(e => {
1780
- info$e(`pull代码失败:${e}, 开始git clone: ${httpRepoUrl}:${branch}`);
1828
+ info$f(`pull代码失败:${e}, 开始git clone: ${httpRepoUrl}:${branch}`);
1781
1829
  return downloadRepoForGit(gitUrl, sourcePath, branch);
1782
1830
  });
1783
1831
  };
1784
1832
  } else {
1785
1833
  promiseTask = (gitUrl, sourcePath, branch, httpRepoUrl) => {
1786
- info$e(`git clone: ${httpRepoUrl}`);
1834
+ info$f(`git clone: ${httpRepoUrl}`);
1787
1835
  return downloadRepoForGit(gitUrl, sourcePath, branch);
1788
1836
  };
1789
1837
  }
@@ -1832,7 +1880,7 @@ var cloneModules_1 = {
1832
1880
  };
1833
1881
 
1834
1882
  const ci = require$$0__default$7;
1835
- const path$c = require$$1__default$1;
1883
+ const path$d = require$$1__default$1;
1836
1884
 
1837
1885
  /**
1838
1886
  * 获取小程序ci的Project对象
@@ -1845,7 +1893,7 @@ const getMpCi = ({
1845
1893
  privateKey = 'TODO'
1846
1894
  }) => {
1847
1895
  var _projectCg$packOption, _projectCg$packOption2;
1848
- const projectCg = require(path$c.join(projectPath, 'project.config.json'));
1896
+ const projectCg = require(path$d.join(projectPath, 'project.config.json'));
1849
1897
  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
1898
  value
1851
1899
  }) => value)) || [];
@@ -1991,7 +2039,7 @@ var mpCi$3 = {
1991
2039
  };
1992
2040
 
1993
2041
  const fs$c = require$$0__default$1;
1994
- const path$b = require$$1__default$1;
2042
+ const path$c = require$$1__default$1;
1995
2043
  const {
1996
2044
  NPM_CACHE_FILE
1997
2045
  } = constant;
@@ -2010,7 +2058,7 @@ function getCache$1(projectDir, type) {
2010
2058
  function setCache$1(projectDir, type = 'miniprogram_npm', data) {
2011
2059
  const filePath = NPM_CACHE_FILE;
2012
2060
  if (!fs$c.existsSync(filePath)) {
2013
- const dir = path$b.dirname(filePath);
2061
+ const dir = path$c.dirname(filePath);
2014
2062
  ensureDirExist$4(dir);
2015
2063
  fs$c.writeFileSync(filePath, '{}');
2016
2064
  }
@@ -2034,7 +2082,7 @@ var cache = {
2034
2082
  const fs$b = require$$0__default$1;
2035
2083
  const fsExtra = require$$1__default$7;
2036
2084
  const crypto$1 = require$$1__default$6;
2037
- const path$a = require$$1__default$1;
2085
+ const path$b = require$$1__default$1;
2038
2086
  const shell = require$$0__default$2;
2039
2087
  const log = log$1;
2040
2088
  const {
@@ -2079,15 +2127,15 @@ const collectNpmTasksMap = (packageJsonFiles, cacheDir) => {
2079
2127
  };
2080
2128
  if (Object.keys(md5Obj.dependencies).length !== 0) {
2081
2129
  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');
2130
+ const cacheNMPath = path$b.join(cacheDir, md5Key);
2131
+ const cacheNMTarFile = path$b.join(cacheNMPath, 'node_modules.tar.gz');
2084
2132
 
2085
2133
  // 下载后,添加回调函数 (拷贝node_modules.tar.gz到编译目录并解压)
2086
2134
  const callback = {
2087
2135
  params: {
2088
2136
  cacheNMPath,
2089
2137
  cacheNMTarFile,
2090
- packageJsonDir: path$a.dirname(packageJsonPath),
2138
+ packageJsonDir: path$b.dirname(packageJsonPath),
2091
2139
  shell
2092
2140
  },
2093
2141
  fn: async (cacheNMPath, cacheNMTarFile, packageJsonDir, shell) => {
@@ -2200,7 +2248,7 @@ const findFilesByFilter = (startPath, filter) => {
2200
2248
  }
2201
2249
  const files = fs$b.readdirSync(startPath);
2202
2250
  files.forEach(file => {
2203
- const filename = path$a.join(startPath, file);
2251
+ const filename = path$b.join(startPath, file);
2204
2252
  const stat = fs$b.lstatSync(filename);
2205
2253
  // 当前文件是文件夹类型,继续递归
2206
2254
  if (stat.isDirectory()) {
@@ -2224,10 +2272,10 @@ const findFilesByFilter = (startPath, filter) => {
2224
2272
  const findAllPackageJson = (subRoots = [], contextDir) => {
2225
2273
  const packageJsonName = 'package.json'; // 查找文件名
2226
2274
  const cwd = contextDir || dirPath;
2227
- const result = [path$a.join(cwd, packageJsonName)]; // 默认填充根目录下的package.json
2275
+ const result = [path$b.join(cwd, packageJsonName)]; // 默认填充根目录下的package.json
2228
2276
 
2229
2277
  subRoots.forEach(subRoot => {
2230
- const toppath = path$a.join(cwd, subRoot.root); // 从该目录开始查找package.json文件
2278
+ const toppath = path$b.join(cwd, subRoot.root); // 从该目录开始查找package.json文件
2231
2279
  const list = findFilesByFilter(toppath, packageJsonName);
2232
2280
  result.push(...list);
2233
2281
  });
@@ -2267,7 +2315,7 @@ const {
2267
2315
  resolve: resolve$f,
2268
2316
  getAbsolutePath: getAbsolutePath$5
2269
2317
  } = widgets;
2270
- const path$9 = require$$1__default$1;
2318
+ const path$a = require$$1__default$1;
2271
2319
  const shelljs$4 = require$$0__default$2;
2272
2320
  const {
2273
2321
  handleError: handleError$5
@@ -2285,7 +2333,7 @@ function collectPackageJson(subPackages, cwd, outputDir) {
2285
2333
  const packageJsonName = 'package.json'; // 查找文件名
2286
2334
  // 1.1根目录的package.json
2287
2335
  const packageArr = [{
2288
- srcPackageDir: path$9.join(cwd, packageJsonName),
2336
+ srcPackageDir: path$a.join(cwd, packageJsonName),
2289
2337
  destNpmDir: resolve$f(outputDir, 'node_modules')
2290
2338
  }];
2291
2339
  // 1.2模块的package.json
@@ -2334,11 +2382,11 @@ const checkPackageVersion$1 = packageArr => {
2334
2382
  const dependencies = readPackageDependencies(item.srcPackageDir);
2335
2383
  const dependenciesKeys = Object.keys(dependencies);
2336
2384
  for (const key of dependenciesKeys) {
2337
- const depPath = path$9.join(item.destNpmDir, key);
2385
+ const depPath = path$a.join(item.destNpmDir, key);
2338
2386
  if (!fs$9.existsSync(depPath)) {
2339
2387
  return true;
2340
2388
  }
2341
- const depPackagePath = path$9.join(depPath, 'package.json');
2389
+ const depPackagePath = path$a.join(depPath, 'package.json');
2342
2390
  if (fs$9.existsSync(depPackagePath)) {
2343
2391
  const packageData = require(depPackagePath);
2344
2392
  if (dependencies[key] === 'latest') {
@@ -2362,7 +2410,7 @@ var checkDependencies = {
2362
2410
 
2363
2411
  const shelljs$3 = require$$0__default$2;
2364
2412
  const fs$8 = require$$0__default$1;
2365
- const path$8 = require$$1__default$1;
2413
+ const path$9 = require$$1__default$1;
2366
2414
  const io$1 = io$3;
2367
2415
  const {
2368
2416
  createTask: createTask$5,
@@ -2387,7 +2435,7 @@ const {
2387
2435
  npmInstallAll
2388
2436
  } = npm;
2389
2437
  const {
2390
- info: info$d
2438
+ info: info$e
2391
2439
  } = log$1;
2392
2440
  const {
2393
2441
  fileMd5
@@ -2401,12 +2449,12 @@ async function install$3(tmsConfig, subPackages, useCache = true) {
2401
2449
  // 加npm install之前的钩子
2402
2450
  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
2451
  var _tmsConfig$hooks2;
2404
- info$d('—————— 执行beforeNpmInstall ————');
2452
+ info$e('—————— 执行beforeNpmInstall ————');
2405
2453
  await (tmsConfig === null || tmsConfig === void 0 ? void 0 : (_tmsConfig$hooks2 = tmsConfig.hooks) === null || _tmsConfig$hooks2 === void 0 ? void 0 : _tmsConfig$hooks2.beforeNpmInstall({
2406
2454
  tmsConfig: filterField$6(tmsConfig, ['gitAccount']),
2407
2455
  cmdOptions: global$7.getData('cmdOptions')
2408
2456
  }));
2409
- info$d('—————— 执行beforeNpmInstall 完成 ————');
2457
+ info$e('—————— 执行beforeNpmInstall 完成 ————');
2410
2458
  }
2411
2459
  const npmInstallRes = await createTask$5(npmInstall$1, '小程序 开始npm install', '小程序npm install 完成')(tmsConfig, subPackages, useCache);
2412
2460
 
@@ -2423,7 +2471,7 @@ async function install$3(tmsConfig, subPackages, useCache = true) {
2423
2471
  async function npmInstall$1(tmsConfig, subPackages, useCache) {
2424
2472
  // 如果依赖没有更新和使用缓存数据(则命中缓存)
2425
2473
  if (!isDependenciesUpdate(subPackages, resolve$e('./'), tmsConfig.outputDir) && useCache) {
2426
- info$d('node_modules命中缓存');
2474
+ info$e('node_modules命中缓存');
2427
2475
  return {
2428
2476
  isCache: true
2429
2477
  };
@@ -2462,7 +2510,7 @@ async function mpCiInstall(tmsConfig, subPackages, useCache) {
2462
2510
  if (useCache) {
2463
2511
  let flag = true;
2464
2512
  await Promise.all(packageJsonFiles.map(async item => {
2465
- const packageDir = path$8.dirname(item);
2513
+ const packageDir = path$9.dirname(item);
2466
2514
  const mpDir = resolve$e(`${packageDir}/miniprogram_npm`);
2467
2515
  const md5Value = await getMNPMd5(packageDir);
2468
2516
  const preCache = getCache(mpDir, 'miniprogram_npm');
@@ -2475,13 +2523,13 @@ async function mpCiInstall(tmsConfig, subPackages, useCache) {
2475
2523
  isCache = flag;
2476
2524
  }
2477
2525
  if (isCache) {
2478
- info$d('miniprogram_npm命中缓存');
2526
+ info$e('miniprogram_npm命中缓存');
2479
2527
  return;
2480
2528
  }
2481
2529
 
2482
2530
  // 即将构建,在cache中标记开始
2483
2531
  await Promise.all(packageJsonFiles.map(async item => {
2484
- const packageDir = path$8.dirname(item);
2532
+ const packageDir = path$9.dirname(item);
2485
2533
  const mpDir = resolve$e(`${packageDir}/miniprogram_npm`);
2486
2534
  setCache(mpDir, 'miniprogram_npm', {
2487
2535
  md5: '',
@@ -2496,7 +2544,7 @@ async function mpCiInstall(tmsConfig, subPackages, useCache) {
2496
2544
 
2497
2545
  // 构建成功后,计算md5写入cache
2498
2546
  await Promise.all(packageJsonFiles.map(async item => {
2499
- const packageDir = path$8.dirname(item);
2547
+ const packageDir = path$9.dirname(item);
2500
2548
  const mpDir = resolve$e(`${packageDir}/miniprogram_npm`);
2501
2549
  const md5Value = await getMNPMd5(packageDir);
2502
2550
  setCache(mpDir, 'miniprogram_npm', {
@@ -2518,7 +2566,7 @@ async function getMNPMd5(cwd) {
2518
2566
  cwd,
2519
2567
  ...shellJsOption
2520
2568
  });
2521
- const tarDir = path$8.join(cwd, './miniprogram_npm.tar.gz');
2569
+ const tarDir = path$9.join(cwd, './miniprogram_npm.tar.gz');
2522
2570
  const md5Value = await fileMd5(tarDir);
2523
2571
  shelljs$3.rm('-rf', tarDir);
2524
2572
  return md5Value;
@@ -2550,7 +2598,7 @@ const {
2550
2598
  } = tmsMpconfig.exports;
2551
2599
  const {
2552
2600
  fail: fail$4,
2553
- info: info$c
2601
+ info: info$d
2554
2602
  } = log$1;
2555
2603
  const install$2 = install_1;
2556
2604
 
@@ -2599,7 +2647,7 @@ async function init$3(tmsConfig, targetModules) {
2599
2647
  } catch (error) {
2600
2648
  const errMsg = typeof error === 'object' ? error.message : error;
2601
2649
  fail$4(`初始化流程出现错误: ${errMsg}`);
2602
- info$c('详细的错误信息', error);
2650
+ info$d('详细的错误信息', error);
2603
2651
  process.exit(1);
2604
2652
  }
2605
2653
  }
@@ -2621,6 +2669,193 @@ function mpProjectJson$1() {
2621
2669
  }
2622
2670
  var mpProjectJson_1 = mpProjectJson$1;
2623
2671
 
2672
+ /**
2673
+ * 严格模块引用过滤插件
2674
+ * 当 devStrictModulesInclude 开启时,过滤 JSON 文件中 usingComponents 里
2675
+ * 指向当前编译模块集合之外的组件引用
2676
+ *
2677
+ * 判断逻辑:
2678
+ * 1. 优先判断组件是否在当前模块的输出目录内(短路)
2679
+ * 2. 否则检查是否落在其他已编译模块的 modulePath 下
2680
+ * 3. 都不满足则移除
2681
+ */
2682
+ const through$2 = require$$0__default$8;
2683
+ const path$8 = require$$1__default$1;
2684
+ const {
2685
+ info: info$c
2686
+ } = log$1;
2687
+
2688
+ /**
2689
+ * 统一路径分隔符为 /(兼容 Windows)
2690
+ */
2691
+ function normalizePath(p) {
2692
+ return p.replace(/\\/g, '/');
2693
+ }
2694
+
2695
+ /**
2696
+ * 判断组件路径是否应该被移除
2697
+ * @param {string} componentPath usingComponents 中的路径
2698
+ * @param {string} currentFileDestPath 当前文件的编译输出绝对路径
2699
+ * @param {string} outputDir 编译输出根目录的绝对路径
2700
+ * @param {string} moduleDestPath 当前模块的编译输出绝对路径
2701
+ * @param {Set<string>} validModulePaths 所有已编译模块的 modulePath 集合(相对于 outputDir,/ 分隔)
2702
+ * @returns {boolean} true 表示应该移除该引用
2703
+ */
2704
+ function shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths) {
2705
+ // 插件引用 (plugin:// / plugin-private://) 不做处理
2706
+ if (componentPath.startsWith('plugin://') || componentPath.startsWith('plugin-private://')) {
2707
+ return false;
2708
+ }
2709
+
2710
+ // 非相对路径且非小程序绝对路径不处理(npm 包如 @tmsfe/tms-ui 等)
2711
+ if (!componentPath.startsWith('.') && !componentPath.startsWith('/')) {
2712
+ return false;
2713
+ }
2714
+
2715
+ // 统一计算组件在 dist 中的绝对路径
2716
+ let resolvedComponentPath;
2717
+ if (componentPath.startsWith('/')) {
2718
+ // 小程序绝对路径(如 /modules/xxx),相对于 dist 根目录
2719
+ resolvedComponentPath = path$8.resolve(outputDir, componentPath.slice(1));
2720
+ } else {
2721
+ // 相对路径,相对于当前文件在 dist 中的位置
2722
+ const currentDir = path$8.dirname(currentFileDestPath);
2723
+ resolvedComponentPath = path$8.resolve(currentDir, componentPath);
2724
+ }
2725
+
2726
+ // 优先判断:组件是否在当前模块的输出目录内
2727
+ const relativeToModule = normalizePath(path$8.relative(moduleDestPath, resolvedComponentPath));
2728
+ if (!relativeToModule.startsWith('..')) {
2729
+ return false;
2730
+ }
2731
+
2732
+ // 组件在当前模块外,检查是否属于其他已编译模块
2733
+ const relativeToOutput = normalizePath(path$8.relative(outputDir, resolvedComponentPath));
2734
+
2735
+ // 路径离开了 outputDir(以 .. 开头),保留不处理
2736
+ if (relativeToOutput.startsWith('..')) {
2737
+ return false;
2738
+ }
2739
+ for (const modulePath of validModulePaths) {
2740
+ if (relativeToOutput === modulePath || relativeToOutput.startsWith(modulePath + '/')) {
2741
+ return false;
2742
+ }
2743
+ }
2744
+
2745
+ // 不属于任何已编译模块 → 移除
2746
+ return true;
2747
+ }
2748
+
2749
+ /**
2750
+ * 获取所有有效的模块输出路径集合
2751
+ */
2752
+ function getValidModulePaths(tmsConfig) {
2753
+ if (tmsConfig._validModulePaths) return tmsConfig._validModulePaths;
2754
+ const paths = new Set();
2755
+ const compiledModules = tmsConfig._compiledModules || [];
2756
+ compiledModules.forEach(m => {
2757
+ if (m.modulePath) {
2758
+ paths.add(normalizePath(m.modulePath));
2759
+ }
2760
+ if (m.subPackages) {
2761
+ m.subPackages.forEach(sub => {
2762
+ if (sub.root) {
2763
+ paths.add(normalizePath(sub.root));
2764
+ }
2765
+ });
2766
+ }
2767
+ });
2768
+ const outputDir = path$8.resolve(tmsConfig.outputDir);
2769
+ const staticDirs = tmsConfig.static || [];
2770
+ staticDirs.forEach(item => {
2771
+ if (item.to) {
2772
+ const toAbsolute = path$8.resolve(item.to);
2773
+ const rel = normalizePath(path$8.relative(outputDir, toAbsolute));
2774
+ if (!rel.startsWith('..')) {
2775
+ paths.add(rel);
2776
+ }
2777
+ }
2778
+ });
2779
+ tmsConfig._validModulePaths = paths;
2780
+ return paths;
2781
+ }
2782
+
2783
+ /**
2784
+ * 严格模块过滤 gulp 插件
2785
+ * @param {Object} tmsConfig 配置对象
2786
+ * @param {Object} module 当前编译模块信息 { from, to }
2787
+ * @returns {Object} through2 转换流
2788
+ */
2789
+ function strictModulesFilter$1(tmsConfig, module) {
2790
+ // 不在严格模式下直接透传
2791
+ if (!tmsConfig.devStrictModulesInclude) {
2792
+ return through$2.obj();
2793
+ }
2794
+ const moduleDestPath = module.to ? path$8.resolve(module.to) : null;
2795
+ const moduleFromPath = module.from ? path$8.resolve(module.from) : null;
2796
+ const outputDir = path$8.resolve(tmsConfig.outputDir);
2797
+ return through$2.obj(function (file, enc, cb) {
2798
+ if (!file.isBuffer() || !file.path.endsWith('.json')) {
2799
+ this.push(file);
2800
+ return cb();
2801
+ }
2802
+
2803
+ // 自定义模块(如 watchExtendFiles)或根目录文件不处理
2804
+ if (module.custom || !moduleDestPath || !moduleFromPath) {
2805
+ this.push(file);
2806
+ return cb();
2807
+ }
2808
+
2809
+ // 根目录编译任务(from === outputDir 的父目录)不处理
2810
+ if (moduleDestPath === outputDir) {
2811
+ this.push(file);
2812
+ return cb();
2813
+ }
2814
+ let json;
2815
+ try {
2816
+ json = JSON.parse(String(file.contents));
2817
+ } catch (e) {
2818
+ this.push(file);
2819
+ return cb();
2820
+ }
2821
+ if (!json.usingComponents || typeof json.usingComponents !== 'object') {
2822
+ this.push(file);
2823
+ return cb();
2824
+ }
2825
+
2826
+ // 计算当前文件的编译输出路径
2827
+ const currentFileSrcPath = file.history[0] || file.path;
2828
+ const relativeToModuleSrc = path$8.relative(moduleFromPath, currentFileSrcPath);
2829
+ const currentFileDestPath = path$8.join(moduleDestPath, relativeToModuleSrc);
2830
+
2831
+ // 延迟获取有效模块路径集合(首次文件处理时计算并缓存)
2832
+ const validModulePaths = getValidModulePaths(tmsConfig);
2833
+ const keysToRemove = [];
2834
+ Object.keys(json.usingComponents).forEach(componentKey => {
2835
+ const componentPath = json.usingComponents[componentKey];
2836
+ if (shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths)) {
2837
+ keysToRemove.push(componentKey);
2838
+ }
2839
+ });
2840
+ if (keysToRemove.length > 0) {
2841
+ keysToRemove.forEach(key => {
2842
+ info$c(`[strictModulesFilter] 移除 ${path$8.basename(currentFileSrcPath)} 中的组件引用: ${key} -> ${json.usingComponents[key]}`);
2843
+ delete json.usingComponents[key];
2844
+ // 同步清理 componentPlaceholder
2845
+ if (json.componentPlaceholder && json.componentPlaceholder[key]) {
2846
+ delete json.componentPlaceholder[key];
2847
+ }
2848
+ });
2849
+ file.contents = Buffer.from(JSON.stringify(json, null, 2));
2850
+ }
2851
+ this.push(file);
2852
+ cb();
2853
+ });
2854
+ }
2855
+ var strictModulesFilter_1 = {
2856
+ strictModulesFilter: strictModulesFilter$1
2857
+ };
2858
+
2624
2859
  /* eslint-disable @typescript-eslint/no-require-imports */
2625
2860
  const through$1 = require$$0__default$8;
2626
2861
  const pp = require$$1__default$3;
@@ -2724,6 +2959,9 @@ const path$6 = require$$1__default$1;
2724
2959
  const minimatch = require$$2__default;
2725
2960
  const gulpif = require$$3__default$1;
2726
2961
  const mpProjectJson = mpProjectJson_1;
2962
+ const {
2963
+ strictModulesFilter
2964
+ } = strictModulesFilter_1;
2727
2965
  const {
2728
2966
  resolve: resolve$c
2729
2967
  } = widgets;
@@ -2778,6 +3016,9 @@ var compile$1 = function (tmsConfig, {
2778
3016
  const templateRender = tmsTemplateRender;
2779
3017
  srcPipe = srcPipe.pipe(templateRender(tmsConfig));
2780
3018
 
3019
+ // 严格模块过滤:移除 usingComponents 中不在编译模块内的引用
3020
+ srcPipe = srcPipe.pipe(strictModulesFilter(tmsConfig, module));
3021
+
2781
3022
  // 后续步骤继续执行其他插件
2782
3023
  const pluginParams = {
2783
3024
  module,
@@ -4072,6 +4313,9 @@ function otherCommands(tmsConfig, commandName, cmdOptions) {
4072
4313
  const newModules = getModulesByMergeDepModules(tmsConfig, modules, false);
4073
4314
  // 获取所有的分包
4074
4315
  const subPackages = getSubPackages(newModules);
4316
+
4317
+ // 将已编译模块列表注入 tmsConfig,供 strictModulesFilter 插件使用
4318
+ tmsConfig._compiledModules = newModules;
4075
4319
  switch (commandName) {
4076
4320
  case 'init':
4077
4321
  init(tmsConfig, newModules);
@@ -4206,7 +4450,7 @@ var entry = [{
4206
4450
 
4207
4451
  var require$$12 = {
4208
4452
  name: "@tmsfe/tmskit",
4209
- version: "0.0.65",
4453
+ version: "0.0.66",
4210
4454
  description: "tmskit",
4211
4455
  main: "dist/index.cjs",
4212
4456
  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.66",
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,197 @@
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
+ * 判断组件路径是否应该被移除
24
+ * @param {string} componentPath usingComponents 中的路径
25
+ * @param {string} currentFileDestPath 当前文件的编译输出绝对路径
26
+ * @param {string} outputDir 编译输出根目录的绝对路径
27
+ * @param {string} moduleDestPath 当前模块的编译输出绝对路径
28
+ * @param {Set<string>} validModulePaths 所有已编译模块的 modulePath 集合(相对于 outputDir,/ 分隔)
29
+ * @returns {boolean} true 表示应该移除该引用
30
+ */
31
+ function shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths) {
32
+ // 插件引用 (plugin:// / plugin-private://) 不做处理
33
+ if (componentPath.startsWith('plugin://') || componentPath.startsWith('plugin-private://')) {
34
+ return false;
35
+ }
36
+
37
+ // 非相对路径且非小程序绝对路径不处理(npm 包如 @tmsfe/tms-ui 等)
38
+ if (!componentPath.startsWith('.') && !componentPath.startsWith('/')) {
39
+ return false;
40
+ }
41
+
42
+ // 统一计算组件在 dist 中的绝对路径
43
+ let resolvedComponentPath;
44
+ if (componentPath.startsWith('/')) {
45
+ // 小程序绝对路径(如 /modules/xxx),相对于 dist 根目录
46
+ resolvedComponentPath = path.resolve(outputDir, componentPath.slice(1));
47
+ } else {
48
+ // 相对路径,相对于当前文件在 dist 中的位置
49
+ const currentDir = path.dirname(currentFileDestPath);
50
+ resolvedComponentPath = path.resolve(currentDir, componentPath);
51
+ }
52
+
53
+ // 优先判断:组件是否在当前模块的输出目录内
54
+ const relativeToModule = normalizePath(path.relative(moduleDestPath, resolvedComponentPath));
55
+ if (!relativeToModule.startsWith('..')) {
56
+ return false;
57
+ }
58
+
59
+ // 组件在当前模块外,检查是否属于其他已编译模块
60
+ const relativeToOutput = normalizePath(path.relative(outputDir, resolvedComponentPath));
61
+
62
+ // 路径离开了 outputDir(以 .. 开头),保留不处理
63
+ if (relativeToOutput.startsWith('..')) {
64
+ return false;
65
+ }
66
+
67
+ for (const modulePath of validModulePaths) {
68
+ if (relativeToOutput === modulePath || relativeToOutput.startsWith(modulePath + '/')) {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ // 不属于任何已编译模块 → 移除
74
+ return true;
75
+ }
76
+
77
+ /**
78
+ * 获取所有有效的模块输出路径集合
79
+ */
80
+ function getValidModulePaths(tmsConfig) {
81
+ if (tmsConfig._validModulePaths) return tmsConfig._validModulePaths;
82
+
83
+ const paths = new Set();
84
+ const compiledModules = tmsConfig._compiledModules || [];
85
+ compiledModules.forEach((m) => {
86
+ if (m.modulePath) {
87
+ paths.add(normalizePath(m.modulePath));
88
+ }
89
+ if (m.subPackages) {
90
+ m.subPackages.forEach((sub) => {
91
+ if (sub.root) {
92
+ paths.add(normalizePath(sub.root));
93
+ }
94
+ });
95
+ }
96
+ });
97
+
98
+ const outputDir = path.resolve(tmsConfig.outputDir);
99
+ const staticDirs = tmsConfig.static || [];
100
+ staticDirs.forEach((item) => {
101
+ if (item.to) {
102
+ const toAbsolute = path.resolve(item.to);
103
+ const rel = normalizePath(path.relative(outputDir, toAbsolute));
104
+ if (!rel.startsWith('..')) {
105
+ paths.add(rel);
106
+ }
107
+ }
108
+ });
109
+
110
+ tmsConfig._validModulePaths = paths;
111
+ return paths;
112
+ }
113
+
114
+ /**
115
+ * 严格模块过滤 gulp 插件
116
+ * @param {Object} tmsConfig 配置对象
117
+ * @param {Object} module 当前编译模块信息 { from, to }
118
+ * @returns {Object} through2 转换流
119
+ */
120
+ function strictModulesFilter(tmsConfig, module) {
121
+ // 不在严格模式下直接透传
122
+ if (!tmsConfig.devStrictModulesInclude) {
123
+ return through.obj();
124
+ }
125
+
126
+ const moduleDestPath = module.to ? path.resolve(module.to) : null;
127
+ const moduleFromPath = module.from ? path.resolve(module.from) : null;
128
+ const outputDir = path.resolve(tmsConfig.outputDir);
129
+
130
+ return through.obj(function (file, enc, cb) {
131
+ if (!file.isBuffer() || !file.path.endsWith('.json')) {
132
+ this.push(file);
133
+ return cb();
134
+ }
135
+
136
+ // 自定义模块(如 watchExtendFiles)或根目录文件不处理
137
+ if (module.custom || !moduleDestPath || !moduleFromPath) {
138
+ this.push(file);
139
+ return cb();
140
+ }
141
+
142
+ // 根目录编译任务(from === outputDir 的父目录)不处理
143
+ if (moduleDestPath === outputDir) {
144
+ this.push(file);
145
+ return cb();
146
+ }
147
+
148
+ let json;
149
+ try {
150
+ json = JSON.parse(String(file.contents));
151
+ } catch (e) {
152
+ this.push(file);
153
+ return cb();
154
+ }
155
+
156
+ if (!json.usingComponents || typeof json.usingComponents !== 'object') {
157
+ this.push(file);
158
+ return cb();
159
+ }
160
+
161
+ // 计算当前文件的编译输出路径
162
+ const currentFileSrcPath = file.history[0] || file.path;
163
+ const relativeToModuleSrc = path.relative(moduleFromPath, currentFileSrcPath);
164
+ const currentFileDestPath = path.join(moduleDestPath, relativeToModuleSrc);
165
+
166
+ // 延迟获取有效模块路径集合(首次文件处理时计算并缓存)
167
+ const validModulePaths = getValidModulePaths(tmsConfig);
168
+
169
+ const keysToRemove = [];
170
+ Object.keys(json.usingComponents).forEach((componentKey) => {
171
+ const componentPath = json.usingComponents[componentKey];
172
+ if (shouldRemoveComponent(componentPath, currentFileDestPath, outputDir, moduleDestPath, validModulePaths)) {
173
+ keysToRemove.push(componentKey);
174
+ }
175
+ });
176
+
177
+ if (keysToRemove.length > 0) {
178
+ keysToRemove.forEach((key) => {
179
+ info(`[strictModulesFilter] 移除 ${path.basename(currentFileSrcPath)} 中的组件引用: ${key} -> ${json.usingComponents[key]}`);
180
+ delete json.usingComponents[key];
181
+ // 同步清理 componentPlaceholder
182
+ if (json.componentPlaceholder && json.componentPlaceholder[key]) {
183
+ delete json.componentPlaceholder[key];
184
+ }
185
+ });
186
+
187
+ file.contents = Buffer.from(JSON.stringify(json, null, 2));
188
+ }
189
+
190
+ this.push(file);
191
+ cb();
192
+ });
193
+ }
194
+
195
+ module.exports = {
196
+ strictModulesFilter,
197
+ };
@@ -193,6 +193,55 @@ async function buildOutputAppJson(tmsConfig, modules) {
193
193
  // 更新主包,需在subpackages处理完成后执行, pages/
194
194
  updateMainPackages(appJson, tmsConfig.mainPackages);
195
195
 
196
+ // devStrictModulesInclude 模式下,清理 preloadRule 中引用了不存在分包的条目
197
+ if (tmsConfig.devStrictModulesInclude && appJson.preloadRule) {
198
+ const existingSubpackageNames = new Set(
199
+ (appJson.subpackages || []).map(sub => sub.name).filter(Boolean),
200
+ );
201
+ const existingSubpackageRoots = new Set(
202
+ (appJson.subpackages || []).map(sub => sub.root).filter(Boolean),
203
+ );
204
+ Object.keys(appJson.preloadRule).forEach((pageKey) => {
205
+ const rule = appJson.preloadRule[pageKey];
206
+ if (rule.packages) {
207
+ rule.packages = rule.packages.filter(
208
+ pkg => existingSubpackageNames.has(pkg) || existingSubpackageRoots.has(pkg),
209
+ );
210
+ if (rule.packages.length === 0) {
211
+ delete appJson.preloadRule[pageKey];
212
+ }
213
+ }
214
+ });
215
+ if (Object.keys(appJson.preloadRule).length === 0) {
216
+ delete appJson.preloadRule;
217
+ }
218
+ }
219
+
220
+ // devStrictModulesInclude 模式下,清理引用了不存在页面路径的字段
221
+ if (tmsConfig.devStrictModulesInclude) {
222
+ // 收集所有有效页面路径(主包 pages + 分包 pages)
223
+ const allValidPages = new Set(appJson.pages || []);
224
+ (appJson.subpackages || []).forEach((sub) => {
225
+ (sub.pages || []).forEach((page) => {
226
+ allValidPages.add(`${sub.root}/${page}`);
227
+ });
228
+ });
229
+
230
+ // 清理 entranceDeclare 中引用了不存在页面的条目
231
+ if (appJson.entranceDeclare) {
232
+ Object.keys(appJson.entranceDeclare).forEach((key) => {
233
+ const entry = appJson.entranceDeclare[key];
234
+ if (entry && entry.path && !allValidPages.has(entry.path)) {
235
+ info(`[devStrictModulesInclude] 移除 entranceDeclare.${key},页面 ${entry.path} 不存在`);
236
+ delete appJson.entranceDeclare[key];
237
+ }
238
+ });
239
+ if (Object.keys(appJson.entranceDeclare).length === 0) {
240
+ delete appJson.entranceDeclare;
241
+ }
242
+ }
243
+ }
244
+
196
245
  // 模板渲染:先将 app.json 转为字符串,然后通过 preprocess 渲染
197
246
  const appJsonStr = JSON.stringify(appJson, null, 2);
198
247
  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);