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

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 = {
@@ -1404,10 +1691,27 @@ class TaroMiniPlugin {
1404
1691
  const runtimeChunks = ['app', ...commonChunks];
1405
1692
  mainPackageRoots.forEach(mainPackageRoot => {
1406
1693
  runtimeChunks.forEach(chunkName => {
1694
+ var _a, _b, _c;
1407
1695
  // 复制 JS 文件
1408
1696
  const jsFile = `${chunkName}.js`;
1409
1697
  if (compilation.assets[jsFile]) {
1410
- compilation.assets[`${mainPackageRoot}/${jsFile}`] = compilation.assets[jsFile];
1698
+ let jsContent = compilation.assets[jsFile];
1699
+ // 对 app.js 注入递归组件全局初始化代码(subpackageindie 模式)
1700
+ // 这里必须注入到 webpack 模块上下文中,避免在文件顶层使用小程序原生 require('@tarojs/runtime') 导致运行时异常
1701
+ if (chunkName === 'app') {
1702
+ const { RawSource } = ((_b = (_a = compilation.compiler) === null || _a === void 0 ? void 0 : _a.webpack) === null || _b === void 0 ? void 0 : _b.sources) || require('webpack').sources;
1703
+ const originalSource = String(((_c = jsContent.source) === null || _c === void 0 ? void 0 : _c.call(jsContent)) || jsContent.toString());
1704
+ const registrarExpr = `(typeof globalThis.__taroRegisterRecursiveComponent==="function"||(globalThis.__taroRegisterRecursiveComponent=function(componentName){const cache=__webpack_require__.c||{};let createRecursiveComponentConfig;for(const key in cache){const exports=cache[key]&&cache[key].exports;if(exports&&typeof exports.createRecursiveComponentConfig==="function"){createRecursiveComponentConfig=exports.createRecursiveComponentConfig;break;}}if(typeof createRecursiveComponentConfig!=="function"){const modules=__webpack_require__.m||{};for(const moduleId in modules){const moduleFactory=modules[moduleId];if(!moduleFactory||typeof moduleFactory!=="function")continue;const source=String(moduleFactory);if(source.indexOf("createRecursiveComponentConfig")===-1)continue;const exports=__webpack_require__(moduleId);if(exports&&typeof exports.createRecursiveComponentConfig==="function"){createRecursiveComponentConfig=exports.createRecursiveComponentConfig;break;}}}if(typeof createRecursiveComponentConfig!=="function"){throw new Error("Cannot find createRecursiveComponentConfig in webpack modules");}Component(createRecursiveComponentConfig(componentName));}))`;
1705
+ let patchedSource = originalSource;
1706
+ if (/,\s*exports\.taroApp\s*=/.test(patchedSource)) {
1707
+ patchedSource = patchedSource.replace(/,\s*exports\.taroApp\s*=/, `,${registrarExpr},exports.taroApp=`);
1708
+ }
1709
+ else {
1710
+ patchedSource = patchedSource.replace(/exports\.taroApp\s*=/, `;${registrarExpr};exports.taroApp=`);
1711
+ }
1712
+ jsContent = new RawSource(patchedSource);
1713
+ }
1714
+ compilation.assets[`${mainPackageRoot}/${jsFile}`] = jsContent;
1411
1715
  }
1412
1716
  // 复制 wxss 文件
1413
1717
  const cssFile = `${chunkName}${styleExt}`;
@@ -1583,10 +1887,11 @@ class TaroMiniPlugin {
1583
1887
  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
1888
  config.content.usingComponents = Object.assign({}, config.content.usingComponents);
1585
1889
  const isRootUsingCustomWrapper = subPackageIndieCustomWrapperRoots.has(indieMatch.root);
1586
- if (isRootUsingCustomWrapper && !config.content.usingComponents[customWrapperName]) {
1890
+ const isRootRecursiveDisabled = this.isRecursiveComponentDisabledForRoot(indieMatch.root);
1891
+ if (isRootUsingCustomWrapper && !isRootRecursiveDisabled && !config.content.usingComponents[customWrapperName]) {
1587
1892
  config.content.usingComponents[customWrapperName] = importCustomWrapperPath;
1588
1893
  }
1589
- if (!template.isSupportRecursive && !config.content.usingComponents[baseCompName]) {
1894
+ if (!template.isSupportRecursive && !isRootRecursiveDisabled && !config.content.usingComponents[baseCompName]) {
1590
1895
  config.content.usingComponents[baseCompName] = importBaseCompPath;
1591
1896
  }
1592
1897
  }
@@ -1631,13 +1936,16 @@ class TaroMiniPlugin {
1631
1936
  importCustomWrapperPath = (0, helper_1.promoteRelativePath)(node_path_1.default.relative(page.path, node_path_1.default.join(sourceDir, isBuildPlugin ? 'plugin' : '', this.getTargetFilePath(customWrapperName, ''))));
1632
1937
  }
1633
1938
  config.content.usingComponents = Object.assign({}, config.content.usingComponents);
1939
+ const isPageRecursiveDisabled = subPackageIndieRoot
1940
+ ? this.isRecursiveComponentDisabledForRoot(subPackageIndieRoot)
1941
+ : false;
1634
1942
  const shouldUseCustomWrapper = subPackageIndieRoot
1635
- ? subPackageIndieCustomWrapperRoots.has(subPackageIndieRoot)
1943
+ ? subPackageIndieCustomWrapperRoots.has(subPackageIndieRoot) && !isPageRecursiveDisabled
1636
1944
  : isUsingCustomWrapper;
1637
1945
  if (shouldUseCustomWrapper) {
1638
1946
  config.content.usingComponents[customWrapperName] = importCustomWrapperPath;
1639
1947
  }
1640
- if (!template.isSupportRecursive && !page.isNative) {
1948
+ if (!template.isSupportRecursive && !page.isNative && !isPageRecursiveDisabled) {
1641
1949
  config.content.usingComponents[baseCompName] = importBaseCompPath;
1642
1950
  }
1643
1951
  this.generateConfigFile(compilation, compiler, page.path, config.content);
@@ -1688,6 +1996,17 @@ class TaroMiniPlugin {
1688
1996
  });
1689
1997
  if (this.options.newBlended) {
1690
1998
  this.getAllIndieRoots().forEach(root => {
1999
+ // ★ 禁用递归组件的 root,清理所有 comp/custom-wrapper/recursive-component 残留产物
2000
+ if (this.isRecursiveComponentDisabledForRoot(root)) {
2001
+ delete compilation.assets[`${root}/${baseCompName}.js`];
2002
+ delete compilation.assets[`${root}/${baseCompName}${this.options.fileType.config}`];
2003
+ delete compilation.assets[`${root}/${baseCompName}${this.options.fileType.templ}`];
2004
+ delete compilation.assets[`${root}/${customWrapperName}.js`];
2005
+ delete compilation.assets[`${root}/${customWrapperName}${this.options.fileType.config}`];
2006
+ delete compilation.assets[`${root}/${customWrapperName}${this.options.fileType.templ}`];
2007
+ delete compilation.assets[`${root}/${recursiveComponentName}.js`];
2008
+ return;
2009
+ }
1691
2010
  const isRootUsingCustomWrapper = hasSubPackageIndieCustomWrapperRoots
1692
2011
  ? subPackageIndieCustomWrapperRoots.has(root)
1693
2012
  : this.isSubPackageIndieRootUsingCustomWrapper(compilation, root, this.getScopedSubPackageIndieComponentConfig(compilation, root).thirdPartyComponents);
@@ -1749,10 +2068,8 @@ class TaroMiniPlugin {
1749
2068
  compilation.assets[this.getTargetFilePath(filePath, '.js')] = new RawSource(content);
1750
2069
  }
1751
2070
  createRecursiveComponentWrapperSource(componentName) {
1752
- const requirePath = JSON.stringify(`./${recursiveComponentName}`);
1753
2071
  const args = componentName ? JSON.stringify(componentName) : '';
1754
- return `require(${requirePath})
1755
- const registerRecursiveComponent = globalThis.__taroRegisterRecursiveComponent
2072
+ return `const registerRecursiveComponent = globalThis.__taroRegisterRecursiveComponent
1756
2073
 
1757
2074
  if (typeof registerRecursiveComponent !== 'function') {
1758
2075
  throw new Error('globalThis.__taroRegisterRecursiveComponent is not a function')