@tarojs/webpack5-runner 4.1.12-beta.26 → 4.1.12-beta.27

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.
@@ -51,6 +51,7 @@ class TaroMiniPlugin {
51
51
  this.dependencies = new Map();
52
52
  this.pageLoaderName = '@tarojs/taro-loader/lib/page';
53
53
  this.independentPackages = new Map();
54
+ this.moduleRequestMap = new Map();
54
55
  const { combination } = options;
55
56
  const miniBuildConfig = combination.config;
56
57
  const { template, baseLevel = 16, experimental } = miniBuildConfig;
@@ -153,6 +154,44 @@ class TaroMiniPlugin {
153
154
  /** For Webpack compilation get factory from compilation.dependencyFactories by denpendence's constructor */
154
155
  compilation.dependencyFactories.set(EntryDependency_1.default, normalModuleFactory);
155
156
  compilation.dependencyFactories.set(TaroSingleEntryDependency_1.default, normalModuleFactory);
157
+ if (this.options.newBlended) {
158
+ normalModuleFactory.hooks.afterResolve.tap(PLUGIN_NAME, (resolveData) => {
159
+ var _a, _b;
160
+ const issuer = (_a = resolveData.contextInfo) === null || _a === void 0 ? void 0 : _a.issuer;
161
+ const request = resolveData.request;
162
+ const resource = ((_b = resolveData.createData) === null || _b === void 0 ? void 0 : _b.resource) || resolveData.resource;
163
+ if (!issuer || !request || !resource)
164
+ return;
165
+ this.setResolvedRequestResource(issuer, request, resource);
166
+ });
167
+ }
168
+ // 在 afterResolve 阶段收集每个 subPackageIndieRoot 实际使用的组件
169
+ if (this.options.newBlended) {
170
+ normalModuleFactory.hooks.afterResolve.tap(PLUGIN_NAME, (resolveData) => {
171
+ var _a;
172
+ if (resolveData.request !== helper_1.taroJsComponents)
173
+ return;
174
+ const issuer = (_a = resolveData.contextInfo) === null || _a === void 0 ? void 0 : _a.issuer;
175
+ if (!issuer || !issuer.startsWith(this.options.sourceDir))
176
+ return;
177
+ const componentName = this.getComponentName(issuer);
178
+ const root = this.isInSubPackageIndieRoot(componentName);
179
+ if (!root)
180
+ return;
181
+ resolveData.dependencies.forEach((dependency) => {
182
+ var _a;
183
+ if (((_a = dependency.ids) === null || _a === void 0 ? void 0 : _a.length) > 0) {
184
+ dependency.ids.forEach((id) => {
185
+ const dashedName = this.toDashedComponentName(id);
186
+ if (!component_1.componentConfig.scopedIncludes.has(root)) {
187
+ component_1.componentConfig.scopedIncludes.set(root, new Set());
188
+ }
189
+ component_1.componentConfig.scopedIncludes.get(root).add(dashedName);
190
+ });
191
+ }
192
+ });
193
+ });
194
+ }
156
195
  /**
157
196
  * webpack NormalModule 在 runLoaders 真正解析资源的前一刻,
158
197
  * 往 NormalModule.loaders 中插入对应的 Taro Loader
@@ -618,15 +657,47 @@ class TaroMiniPlugin {
618
657
  /**
619
658
  * 获取子分包独立模板配置列表(已规范化)
620
659
  */
660
+ /**
661
+ * 解析 SubPackageIndieRootConfig 联合类型,返回归一化后的路径和是否禁用递归组件
662
+ */
663
+ parseIndieRootConfig(rootConfig) {
664
+ if (typeof rootConfig === 'string') {
665
+ return { path: this.normalizeIndieRoot(rootConfig), disableRecursiveComponent: false };
666
+ }
667
+ return {
668
+ path: this.normalizeIndieRoot(rootConfig.path),
669
+ disableRecursiveComponent: !!rootConfig.disableRecursiveComponent
670
+ };
671
+ }
621
672
  getSubPackageIndieConfigs() {
622
673
  var _a;
623
674
  const subPackageIndie = (_a = this.appConfig) === null || _a === void 0 ? void 0 : _a.subPackageIndie;
624
675
  if (!Array.isArray(subPackageIndie))
625
676
  return [];
626
- return subPackageIndie.map(({ mainPackageRoot, subPackageRoots = [] }) => ({
627
- mainPackageRoot: this.normalizeIndieRoot(mainPackageRoot),
628
- subPackageRoots: Array.from(new Set(subPackageRoots.map(root => this.normalizeIndieRoot(root))))
629
- }));
677
+ return subPackageIndie.map(({ mainPackageRoot, subPackageRoots = [] }) => {
678
+ const mainParsed = this.parseIndieRootConfig(mainPackageRoot);
679
+ const subParsedList = subPackageRoots.map(root => this.parseIndieRootConfig(root));
680
+ const disableRecursiveComponentRoots = new Set();
681
+ if (mainParsed.disableRecursiveComponent) {
682
+ disableRecursiveComponentRoots.add(mainParsed.path);
683
+ }
684
+ subParsedList.forEach(sub => {
685
+ if (sub.disableRecursiveComponent) {
686
+ disableRecursiveComponentRoots.add(sub.path);
687
+ }
688
+ });
689
+ return {
690
+ mainPackageRoot: mainParsed.path,
691
+ subPackageRoots: Array.from(new Set(subParsedList.map(sub => sub.path))),
692
+ disableRecursiveComponentRoots
693
+ };
694
+ });
695
+ }
696
+ /**
697
+ * 判断给定的 indie root 是否禁用了递归组件(comp/custom-wrapper/recursive-component)
698
+ */
699
+ isRecursiveComponentDisabledForRoot(root) {
700
+ return this.getSubPackageIndieConfigs().some(config => config.disableRecursiveComponentRoots.has(root));
630
701
  }
631
702
  getAllMainPackageRoots() {
632
703
  return Array.from(new Set(this.getSubPackageIndieConfigs().map(item => item.mainPackageRoot)));
@@ -641,7 +712,8 @@ class TaroMiniPlugin {
641
712
  const { newBlended } = this.options;
642
713
  if (!newBlended)
643
714
  return null;
644
- for (const config of this.getSubPackageIndieConfigs()) {
715
+ const configs = this.getSubPackageIndieConfigs();
716
+ for (const config of configs) {
645
717
  if (pageName.startsWith(config.mainPackageRoot + '/') || pageName === config.mainPackageRoot) {
646
718
  return {
647
719
  config,
@@ -1015,6 +1087,9 @@ class TaroMiniPlugin {
1015
1087
  const JsonpTemplatePlugin = require('webpack/lib/web/JsonpTemplatePlugin');
1016
1088
  const NaturalChunkIdsPlugin = require('webpack/lib/ids/NaturalChunkIdsPlugin');
1017
1089
  indieRoots.forEach(root => {
1090
+ // ★ 禁用递归组件的 root 不需要编译 recursive-component
1091
+ if (this.isRecursiveComponentDisabledForRoot(root))
1092
+ return;
1018
1093
  const childCompiler = compilation.createChildCompiler(PLUGIN_NAME, {
1019
1094
  path: compiler.options.output.path,
1020
1095
  filename: '[name].js',
@@ -1151,27 +1226,239 @@ class TaroMiniPlugin {
1151
1226
  return '';
1152
1227
  }
1153
1228
  }
1154
- isSubPackageIndieRootUsingCustomWrapperByModules(compilation, root) {
1229
+ getModuleResource(module) {
1230
+ var _a;
1231
+ const resource = (module === null || module === void 0 ? void 0 : module.resource) || ((_a = module === null || module === void 0 ? void 0 : module.rootModule) === null || _a === void 0 ? void 0 : _a.resource);
1232
+ return typeof resource === 'string' ? resource : undefined;
1233
+ }
1234
+ collectFlattenedModules(module, collected, visited = new Set()) {
1235
+ if (!module || visited.has(module))
1236
+ return;
1237
+ visited.add(module);
1238
+ collected.add(module);
1239
+ const nestedModuleCollections = [module.rootModule, module.modules, module._modules];
1240
+ nestedModuleCollections.forEach(item => {
1241
+ if (!item)
1242
+ return;
1243
+ if (item && typeof item[Symbol.iterator] === 'function') {
1244
+ for (const nested of item) {
1245
+ this.collectFlattenedModules(nested, collected, visited);
1246
+ }
1247
+ }
1248
+ else {
1249
+ this.collectFlattenedModules(item, collected, visited);
1250
+ }
1251
+ });
1252
+ }
1253
+ getCompilationModuleResourceMap(compilation) {
1254
+ const moduleMap = new Map();
1255
+ for (const module of compilation.modules) {
1256
+ const flattenedModules = new Set();
1257
+ this.collectFlattenedModules(module, flattenedModules);
1258
+ flattenedModules.forEach(flattenedModule => {
1259
+ const resource = this.getModuleResource(flattenedModule);
1260
+ if (resource) {
1261
+ moduleMap.set(resource, flattenedModule);
1262
+ }
1263
+ });
1264
+ }
1265
+ return moduleMap;
1266
+ }
1267
+ getSubPackageIndieModules(compilation, root) {
1268
+ const modules = new Set();
1269
+ this.getChunksBySubPackageIndieRoot(compilation, root).forEach(chunk => {
1270
+ for (const module of compilation.chunkGraph.getChunkModulesIterable(chunk)) {
1271
+ this.collectFlattenedModules(module, modules);
1272
+ }
1273
+ });
1274
+ return modules;
1275
+ }
1276
+ normalizeModuleRequestMapKey(resource) {
1277
+ if (!resource || typeof resource !== 'string')
1278
+ return null;
1279
+ const resourceWithoutLoader = resource.split('!').pop();
1280
+ if (!resourceWithoutLoader)
1281
+ return null;
1282
+ const resourcePath = resourceWithoutLoader.split('?')[0];
1283
+ if (!resourcePath)
1284
+ return null;
1285
+ return node_path_1.default.normalize(resourcePath);
1286
+ }
1287
+ getModuleRequestMapKeys(resource) {
1288
+ const keys = new Set();
1289
+ if (resource && typeof resource === 'string') {
1290
+ keys.add(resource);
1291
+ }
1292
+ const normalizedResource = this.normalizeModuleRequestMapKey(resource);
1293
+ if (normalizedResource) {
1294
+ keys.add(normalizedResource);
1295
+ }
1296
+ return Array.from(keys);
1297
+ }
1298
+ setResolvedRequestResource(issuer, request, resource) {
1299
+ this.getModuleRequestMapKeys(issuer).forEach(key => {
1300
+ if (!this.moduleRequestMap.has(key)) {
1301
+ this.moduleRequestMap.set(key, new Map());
1302
+ }
1303
+ this.moduleRequestMap.get(key).set(request, resource);
1304
+ });
1305
+ }
1306
+ getResolvedRequestResource(issuerResource, request) {
1155
1307
  var _a;
1156
- const chunks = this.getChunksBySubPackageIndieRoot(compilation, root);
1157
- for (const chunk of chunks) {
1158
- const modules = chunk === null || chunk === void 0 ? void 0 : chunk.modulesIterable;
1159
- if (!modules)
1308
+ for (const key of this.getModuleRequestMapKeys(issuerResource)) {
1309
+ const resolvedResource = (_a = this.moduleRequestMap.get(key)) === null || _a === void 0 ? void 0 : _a.get(request);
1310
+ if (resolvedResource)
1311
+ return resolvedResource;
1312
+ }
1313
+ }
1314
+ getResolvedModuleByResource(moduleResourceMap, resource) {
1315
+ const exactModule = moduleResourceMap.get(resource);
1316
+ if (exactModule)
1317
+ return exactModule;
1318
+ const normalizedResource = this.normalizeModuleRequestMapKey(resource);
1319
+ if (!normalizedResource)
1320
+ return null;
1321
+ const normalizedModule = moduleResourceMap.get(normalizedResource);
1322
+ if (normalizedModule)
1323
+ return normalizedModule;
1324
+ for (const [moduleResource, module] of moduleResourceMap.entries()) {
1325
+ if (this.normalizeModuleRequestMapKey(moduleResource) === normalizedResource) {
1326
+ return module;
1327
+ }
1328
+ }
1329
+ return null;
1330
+ }
1331
+ resolveRequestedModule(moduleResourceMap, issuerModule, request) {
1332
+ const issuerResource = this.getModuleResource(issuerModule);
1333
+ const resolvedResource = this.getResolvedRequestResource(issuerResource, request);
1334
+ if (resolvedResource) {
1335
+ const resolvedModule = this.getResolvedModuleByResource(moduleResourceMap, resolvedResource);
1336
+ if (resolvedModule)
1337
+ return resolvedModule;
1338
+ }
1339
+ if (issuerResource && /^[.\\/]/.test(request)) {
1340
+ const requestPath = node_path_1.default.resolve(node_path_1.default.dirname(issuerResource), request);
1341
+ const resolvedPath = (0, helper_1.resolveMainFilePath)(requestPath);
1342
+ const requestModule = this.getResolvedModuleByResource(moduleResourceMap, resolvedPath);
1343
+ if (requestModule)
1344
+ return requestModule;
1345
+ }
1346
+ for (const module of moduleResourceMap.values()) {
1347
+ if (!module)
1160
1348
  continue;
1161
- for (const module of modules) {
1162
- if (this.shouldSkipSubPackageIndieModule(module, root))
1163
- continue;
1164
- const resource = (module === null || module === void 0 ? void 0 : module.resource) || ((_a = module === null || module === void 0 ? void 0 : module.rootModule) === null || _a === void 0 ? void 0 : _a.resource);
1165
- if (typeof resource !== 'string' || !resource.startsWith(this.options.sourceDir))
1166
- continue;
1167
- const source = this.getModuleSourceContent(module);
1168
- if (!source)
1169
- continue;
1170
- // 仅识别真实组件使用,避免被字符串文案中的 “CustomWrapper” 误判
1171
- const isJsxUsage = /<\s*CustomWrapper(?:\s|>)/.test(source);
1172
- const isImportUsage = /import\s*{[^}]*\bCustomWrapper\b[^}]*}\s*from\s*['"]@tarojs\/components['"]/.test(source);
1173
- const isCompiledUsage = /components-react/.test(source) && /\.(?:CustomWrapper|RW)\b/.test(source);
1174
- if (isJsxUsage || isImportUsage || isCompiledUsage) {
1349
+ if (module.rawRequest === request || module.userRequest === request || module.request === request) {
1350
+ return module;
1351
+ }
1352
+ }
1353
+ return null;
1354
+ }
1355
+ resolveImportBindingToTaroComponentName(moduleResourceMap, issuerModule, binding, propertyName, visited = new Set()) {
1356
+ if (!(binding === null || binding === void 0 ? void 0 : binding.source))
1357
+ return null;
1358
+ if (binding.kind === 'namespace') {
1359
+ if (!propertyName)
1360
+ return null;
1361
+ if (binding.source === helper_1.taroJsComponents) {
1362
+ return propertyName;
1363
+ }
1364
+ const targetModule = this.resolveRequestedModule(moduleResourceMap, issuerModule, binding.source);
1365
+ if (!targetModule) {
1366
+ if (!/^[.\\/]/.test(binding.source)) {
1367
+ return propertyName;
1368
+ }
1369
+ return null;
1370
+ }
1371
+ return this.resolveModuleExportToTaroComponentName(moduleResourceMap, targetModule, propertyName, visited);
1372
+ }
1373
+ const importedName = binding.imported || propertyName;
1374
+ if (!importedName || importedName === 'default')
1375
+ return null;
1376
+ if (binding.source === helper_1.taroJsComponents) {
1377
+ return importedName;
1378
+ }
1379
+ const targetModule = this.resolveRequestedModule(moduleResourceMap, issuerModule, binding.source);
1380
+ if (!targetModule) {
1381
+ if (!/^[.\\/]/.test(binding.source)) {
1382
+ return importedName;
1383
+ }
1384
+ return null;
1385
+ }
1386
+ return this.resolveModuleExportToTaroComponentName(moduleResourceMap, targetModule, importedName, visited);
1387
+ }
1388
+ resolveModuleExportToTaroComponentName(moduleResourceMap, module, exportName, visited = new Set()) {
1389
+ var _a, _b;
1390
+ const moduleResource = this.getModuleResource(module);
1391
+ if (!moduleResource)
1392
+ return null;
1393
+ const visitKey = `${moduleResource}::${exportName}`;
1394
+ if (visited.has(visitKey))
1395
+ return null;
1396
+ visited.add(visitKey);
1397
+ const exportBinding = (_a = module === null || module === void 0 ? void 0 : module.exportBindings) === null || _a === void 0 ? void 0 : _a[exportName];
1398
+ if (exportBinding) {
1399
+ if (exportBinding.kind === 'reexport' && exportBinding.source) {
1400
+ if (exportBinding.source === helper_1.taroJsComponents) {
1401
+ return exportBinding.imported || exportName;
1402
+ }
1403
+ const targetModule = this.resolveRequestedModule(moduleResourceMap, module, exportBinding.source);
1404
+ if (targetModule) {
1405
+ const resolvedName = this.resolveModuleExportToTaroComponentName(moduleResourceMap, targetModule, exportBinding.imported || exportName, visited);
1406
+ if (resolvedName)
1407
+ return resolvedName;
1408
+ }
1409
+ }
1410
+ if (exportBinding.kind === 'local' && exportBinding.local) {
1411
+ const importedBinding = (_b = module === null || module === void 0 ? void 0 : module.importedBindings) === null || _b === void 0 ? void 0 : _b[exportBinding.local];
1412
+ if (importedBinding) {
1413
+ const resolvedName = this.resolveImportBindingToTaroComponentName(moduleResourceMap, module, importedBinding, undefined, visited);
1414
+ if (resolvedName)
1415
+ return resolvedName;
1416
+ }
1417
+ }
1418
+ }
1419
+ for (const source of (module === null || module === void 0 ? void 0 : module.exportAllSources) || []) {
1420
+ if (source === helper_1.taroJsComponents) {
1421
+ return exportName;
1422
+ }
1423
+ const targetModule = this.resolveRequestedModule(moduleResourceMap, module, source);
1424
+ if (!targetModule)
1425
+ continue;
1426
+ const resolvedName = this.resolveModuleExportToTaroComponentName(moduleResourceMap, targetModule, exportName, visited);
1427
+ if (resolvedName)
1428
+ return resolvedName;
1429
+ }
1430
+ return null;
1431
+ }
1432
+ resolveUsedComponentRefToTaroComponentName(moduleResourceMap, module, componentRef) {
1433
+ var _a, _b;
1434
+ if (!componentRef)
1435
+ return null;
1436
+ if (componentRef.kind === 'identifier') {
1437
+ const binding = (_a = module === null || module === void 0 ? void 0 : module.importedBindings) === null || _a === void 0 ? void 0 : _a[componentRef.name];
1438
+ if (!binding) {
1439
+ return componentRef.name;
1440
+ }
1441
+ const resolvedName = this.resolveImportBindingToTaroComponentName(moduleResourceMap, module, binding);
1442
+ return resolvedName || componentRef.name;
1443
+ }
1444
+ if (componentRef.kind === 'member') {
1445
+ const binding = (_b = module === null || module === void 0 ? void 0 : module.importedBindings) === null || _b === void 0 ? void 0 : _b[componentRef.object];
1446
+ if (!binding) {
1447
+ return componentRef.property || null;
1448
+ }
1449
+ const resolvedName = this.resolveImportBindingToTaroComponentName(moduleResourceMap, module, binding, componentRef.property);
1450
+ return resolvedName || componentRef.property || null;
1451
+ }
1452
+ return null;
1453
+ }
1454
+ isSubPackageIndieRootUsingCustomWrapperByModules(compilation, root) {
1455
+ const moduleResourceMap = this.getCompilationModuleResourceMap(compilation);
1456
+ for (const module of this.getSubPackageIndieModules(compilation, root)) {
1457
+ if (this.shouldSkipSubPackageIndieModule(module, root))
1458
+ continue;
1459
+ for (const componentRef of (module === null || module === void 0 ? void 0 : module.usedComponentRefs) || []) {
1460
+ const resolvedComponentName = this.resolveUsedComponentRefToTaroComponentName(moduleResourceMap, module, componentRef);
1461
+ if (resolvedComponentName === 'CustomWrapper') {
1175
1462
  return true;
1176
1463
  }
1177
1464
  }
@@ -1179,8 +1466,7 @@ class TaroMiniPlugin {
1179
1466
  return false;
1180
1467
  }
1181
1468
  shouldSkipSubPackageIndieModule(module, root) {
1182
- var _a;
1183
- const resource = (module === null || module === void 0 ? void 0 : module.resource) || ((_a = module === null || module === void 0 ? void 0 : module.rootModule) === null || _a === void 0 ? void 0 : _a.resource);
1469
+ const resource = this.getModuleResource(module);
1184
1470
  if (typeof resource !== 'string' || !resource.startsWith(this.options.sourceDir)) {
1185
1471
  return false;
1186
1472
  }
@@ -1188,6 +1474,38 @@ class TaroMiniPlugin {
1188
1474
  const targetRoot = this.isInSubPackageIndieRoot(componentName);
1189
1475
  return !!targetRoot && targetRoot !== root;
1190
1476
  }
1477
+ collectModuleResolvedComponentIncludes(compilation, root) {
1478
+ const includes = new Set();
1479
+ const moduleResourceMap = this.getCompilationModuleResourceMap(compilation);
1480
+ for (const module of this.getSubPackageIndieModules(compilation, root)) {
1481
+ if (this.shouldSkipSubPackageIndieModule(module, root))
1482
+ continue;
1483
+ for (const elementName of (module === null || module === void 0 ? void 0 : module.elementNameSet) || []) {
1484
+ if (!component_1.componentConfig.thirdPartyComponents.has(elementName)) {
1485
+ includes.add(elementName);
1486
+ }
1487
+ }
1488
+ for (const binding of Object.values((module === null || module === void 0 ? void 0 : module.importedBindings) || {})) {
1489
+ const resolvedComponentName = this.resolveImportBindingToTaroComponentName(moduleResourceMap, module, binding);
1490
+ if (!resolvedComponentName)
1491
+ continue;
1492
+ const dashedName = this.toDashedComponentName(resolvedComponentName);
1493
+ if (!component_1.componentConfig.thirdPartyComponents.has(dashedName)) {
1494
+ includes.add(dashedName);
1495
+ }
1496
+ }
1497
+ for (const componentRef of (module === null || module === void 0 ? void 0 : module.usedComponentRefs) || []) {
1498
+ const resolvedComponentName = this.resolveUsedComponentRefToTaroComponentName(moduleResourceMap, module, componentRef);
1499
+ if (!resolvedComponentName)
1500
+ continue;
1501
+ const dashedName = this.toDashedComponentName(resolvedComponentName);
1502
+ if (!component_1.componentConfig.thirdPartyComponents.has(dashedName)) {
1503
+ includes.add(dashedName);
1504
+ }
1505
+ }
1506
+ }
1507
+ return includes;
1508
+ }
1191
1509
  expandScopedIncludes(includes) {
1192
1510
  const scopedIncludes = new Set(includes);
1193
1511
  if (scopedIncludes.has('view')) {
@@ -1209,32 +1527,15 @@ class TaroMiniPlugin {
1209
1527
  }
1210
1528
  collectScopedInnerComponents(compilation, root) {
1211
1529
  const includes = new Set();
1212
- const assetNames = new Set();
1213
- this.getChunksBySubPackageIndieRoot(compilation, root).forEach(chunk => {
1214
- chunk.files.forEach(file => {
1215
- if (typeof file === 'string' && file.endsWith('.js')) {
1216
- assetNames.add(file);
1217
- }
1218
- });
1219
- });
1220
- assetNames.forEach(assetName => {
1221
- const asset = compilation.assets[assetName];
1222
- if (!asset)
1223
- return;
1224
- const source = asset.source().toString();
1225
- const componentImportReg = /var\s+([A-Za-z0-9_$]+)\s*=\s*__webpack_require__\([^)]*?@tarojs\/components[^)]*?components-react\.js"\);/g;
1226
- const importMatches = Array.from(source.matchAll(componentImportReg));
1227
- importMatches.forEach(([, alias]) => {
1228
- const usageReg = new RegExp(`${alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\.([A-Z][A-Za-z0-9_$]+)`, 'g');
1229
- Array.from(source.matchAll(usageReg)).forEach(([, componentName]) => {
1230
- const dashedName = this.toDashedComponentName(componentName);
1231
- if (!component_1.componentConfig.thirdPartyComponents.has(dashedName)) {
1232
- includes.add(dashedName);
1233
- }
1234
- });
1235
- });
1236
- });
1237
- return this.expandScopedIncludes(includes);
1530
+ const scopedIncludes = component_1.componentConfig.scopedIncludes.get(root);
1531
+ if (scopedIncludes && scopedIncludes.size > 0) {
1532
+ scopedIncludes.forEach(name => includes.add(name));
1533
+ }
1534
+ this.collectModuleResolvedComponentIncludes(compilation, root).forEach(name => includes.add(name));
1535
+ const finalIncludes = includes.size > 0
1536
+ ? includes
1537
+ : new Set(component_1.componentConfig.includes);
1538
+ return this.expandScopedIncludes(finalIncludes);
1238
1539
  }
1239
1540
  isSubPackageIndieRootUsingCustomWrapper(compilation, root, scopedThirdPartyComponents) {
1240
1541
  if (scopedThirdPartyComponents === null || scopedThirdPartyComponents === void 0 ? void 0 : scopedThirdPartyComponents.has(customWrapperName)) {
@@ -1243,28 +1544,6 @@ class TaroMiniPlugin {
1243
1544
  if (this.isSubPackageIndieRootUsingCustomWrapperByModules(compilation, root)) {
1244
1545
  return true;
1245
1546
  }
1246
- const assetNames = new Set();
1247
- this.getChunksBySubPackageIndieRoot(compilation, root).forEach(chunk => {
1248
- chunk.files.forEach(file => {
1249
- if (typeof file === 'string' && file.endsWith('.js')) {
1250
- assetNames.add(file);
1251
- }
1252
- });
1253
- });
1254
- for (const assetName of assetNames) {
1255
- const asset = compilation.assets[assetName];
1256
- if (!asset)
1257
- continue;
1258
- const source = asset.source().toString();
1259
- const componentImportReg = /var\s+([A-Za-z0-9_$]+)\s*=\s*__webpack_require__\([^)]*?@tarojs\/components[^)]*?components-react\.js"\);/g;
1260
- const importMatches = Array.from(source.matchAll(componentImportReg));
1261
- for (const [, alias] of importMatches) {
1262
- const usageReg = new RegExp(`${alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\.CustomWrapper\\b`, 'g');
1263
- if (usageReg.test(source)) {
1264
- return true;
1265
- }
1266
- }
1267
- }
1268
1547
  return false;
1269
1548
  }
1270
1549
  resolveUsingComponentTarget(filePath, componentPath) {
@@ -1326,7 +1605,8 @@ class TaroMiniPlugin {
1326
1605
  includes: this.collectScopedInnerComponents(compilation, root),
1327
1606
  exclude: new Set(component_1.componentConfig.exclude),
1328
1607
  thirdPartyComponents,
1329
- includeAll: false
1608
+ includeAll: false,
1609
+ skipRecursiveComponent: false
1330
1610
  };
1331
1611
  }
1332
1612
  /**
@@ -1344,7 +1624,14 @@ class TaroMiniPlugin {
1344
1624
  const allIndieRoots = this.getAllIndieRoots();
1345
1625
  allIndieRoots.forEach(root => {
1346
1626
  const scopedComponentConfig = this.getScopedSubPackageIndieComponentConfig(compilation, root);
1347
- const isRootUsingCustomWrapper = this.isSubPackageIndieRootUsingCustomWrapper(compilation, root, scopedComponentConfig.thirdPartyComponents);
1627
+ // 检查该 root 是否禁用了递归组件
1628
+ const isRecursiveDisabled = this.isRecursiveComponentDisabledForRoot(root);
1629
+ if (isRecursiveDisabled) {
1630
+ scopedComponentConfig.skipRecursiveComponent = true;
1631
+ }
1632
+ const isRootUsingCustomWrapper = isRecursiveDisabled
1633
+ ? false
1634
+ : this.isSubPackageIndieRootUsingCustomWrapper(compilation, root, scopedComponentConfig.thirdPartyComponents);
1348
1635
  if (isRootUsingCustomWrapper) {
1349
1636
  customWrapperRoots.add(root);
1350
1637
  // base.wxml 模板生成依赖 thirdPartyComponents,确保 custom-wrapper 模板不会漏掉
@@ -1357,8 +1644,8 @@ class TaroMiniPlugin {
1357
1644
  this.generateTemplateFile(compilation, compiler, `${root}/${baseTemplateName}`, template.buildTemplate, scopedComponentConfig);
1358
1645
  // 2. 生成 utils.wxs
1359
1646
  this.generateXSFile(compilation, compiler, `${root}/utils`);
1360
- // 3. 生成 comp.wxml 和 comp.json(如果不支持递归模板)
1361
- if (!template.isSupportRecursive) {
1647
+ // 3. 生成 comp.wxml 和 comp.json(如果不支持递归模板且未禁用递归组件)
1648
+ if (!template.isSupportRecursive && !isRecursiveDisabled) {
1362
1649
  this.generateSubPackageIndieScriptFile(compilation, compiler, `${root}/${baseCompName}`, this.createRecursiveComponentWrapperSource());
1363
1650
  this.generateTemplateFile(compilation, compiler, `${root}/${baseCompName}`, template.buildBaseComponentTemplate, this.options.fileType.templ);
1364
1651
  const compConfig = {
@@ -1583,10 +1870,11 @@ class TaroMiniPlugin {
1583
1870
  const importCustomWrapperPath = (0, helper_1.promoteRelativePath)(node_path_1.default.relative(component.path, node_path_1.default.join(sourceDir, indieMatch.root, this.getTargetFilePath(customWrapperName, ''))));
1584
1871
  config.content.usingComponents = Object.assign({}, config.content.usingComponents);
1585
1872
  const isRootUsingCustomWrapper = subPackageIndieCustomWrapperRoots.has(indieMatch.root);
1586
- if (isRootUsingCustomWrapper && !config.content.usingComponents[customWrapperName]) {
1873
+ const isRootRecursiveDisabled = this.isRecursiveComponentDisabledForRoot(indieMatch.root);
1874
+ if (isRootUsingCustomWrapper && !isRootRecursiveDisabled && !config.content.usingComponents[customWrapperName]) {
1587
1875
  config.content.usingComponents[customWrapperName] = importCustomWrapperPath;
1588
1876
  }
1589
- if (!template.isSupportRecursive && !config.content.usingComponents[baseCompName]) {
1877
+ if (!template.isSupportRecursive && !isRootRecursiveDisabled && !config.content.usingComponents[baseCompName]) {
1590
1878
  config.content.usingComponents[baseCompName] = importBaseCompPath;
1591
1879
  }
1592
1880
  }
@@ -1631,13 +1919,16 @@ class TaroMiniPlugin {
1631
1919
  importCustomWrapperPath = (0, helper_1.promoteRelativePath)(node_path_1.default.relative(page.path, node_path_1.default.join(sourceDir, isBuildPlugin ? 'plugin' : '', this.getTargetFilePath(customWrapperName, ''))));
1632
1920
  }
1633
1921
  config.content.usingComponents = Object.assign({}, config.content.usingComponents);
1922
+ const isPageRecursiveDisabled = subPackageIndieRoot
1923
+ ? this.isRecursiveComponentDisabledForRoot(subPackageIndieRoot)
1924
+ : false;
1634
1925
  const shouldUseCustomWrapper = subPackageIndieRoot
1635
- ? subPackageIndieCustomWrapperRoots.has(subPackageIndieRoot)
1926
+ ? subPackageIndieCustomWrapperRoots.has(subPackageIndieRoot) && !isPageRecursiveDisabled
1636
1927
  : isUsingCustomWrapper;
1637
1928
  if (shouldUseCustomWrapper) {
1638
1929
  config.content.usingComponents[customWrapperName] = importCustomWrapperPath;
1639
1930
  }
1640
- if (!template.isSupportRecursive && !page.isNative) {
1931
+ if (!template.isSupportRecursive && !page.isNative && !isPageRecursiveDisabled) {
1641
1932
  config.content.usingComponents[baseCompName] = importBaseCompPath;
1642
1933
  }
1643
1934
  this.generateConfigFile(compilation, compiler, page.path, config.content);
@@ -1688,6 +1979,17 @@ class TaroMiniPlugin {
1688
1979
  });
1689
1980
  if (this.options.newBlended) {
1690
1981
  this.getAllIndieRoots().forEach(root => {
1982
+ // ★ 禁用递归组件的 root,清理所有 comp/custom-wrapper/recursive-component 残留产物
1983
+ if (this.isRecursiveComponentDisabledForRoot(root)) {
1984
+ delete compilation.assets[`${root}/${baseCompName}.js`];
1985
+ delete compilation.assets[`${root}/${baseCompName}${this.options.fileType.config}`];
1986
+ delete compilation.assets[`${root}/${baseCompName}${this.options.fileType.templ}`];
1987
+ delete compilation.assets[`${root}/${customWrapperName}.js`];
1988
+ delete compilation.assets[`${root}/${customWrapperName}${this.options.fileType.config}`];
1989
+ delete compilation.assets[`${root}/${customWrapperName}${this.options.fileType.templ}`];
1990
+ delete compilation.assets[`${root}/${recursiveComponentName}.js`];
1991
+ return;
1992
+ }
1691
1993
  const isRootUsingCustomWrapper = hasSubPackageIndieCustomWrapperRoots
1692
1994
  ? subPackageIndieCustomWrapperRoots.has(root)
1693
1995
  : this.isSubPackageIndieRootUsingCustomWrapper(compilation, root, this.getScopedSubPackageIndieComponentConfig(compilation, root).thirdPartyComponents);