weapp-tailwindcss 5.0.0-next.1 → 5.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/bundlers/shared/generator-css.d.ts +3 -1
  2. package/dist/bundlers/vite/css-finalizer.d.ts +3 -0
  3. package/dist/bundlers/vite/generate-bundle.d.ts +14 -1
  4. package/dist/bundlers/vite/source-candidates.d.ts +15 -0
  5. package/dist/cli.js +1 -1
  6. package/dist/cli.mjs +1 -1
  7. package/dist/core.js +1 -1
  8. package/dist/core.mjs +1 -1
  9. package/dist/generator/options.d.ts +2 -0
  10. package/dist/generator/types.d.ts +1 -0
  11. package/dist/generator-Y-Ikv4Fu.mjs +1177 -0
  12. package/dist/{generator-css-DhPFjSzK.mjs → generator-css-B5ejWUMv.mjs} +60 -19
  13. package/dist/{generator-css-CnYjiMrD.js → generator-css-D3OdPRiS.js} +60 -19
  14. package/dist/{generator-CZ-JXw6T.js → generator-mmhXzZnv.js} +797 -13
  15. package/dist/generator.js +1 -1
  16. package/dist/generator.mjs +1 -1
  17. package/dist/gulp.js +2 -2
  18. package/dist/gulp.mjs +2 -2
  19. package/dist/index.js +3 -3
  20. package/dist/index.mjs +3 -3
  21. package/dist/{loader-anchors-cprm4Klq.js → loader-anchors-CNkWT8hx.js} +1 -1
  22. package/dist/{loader-anchors-DvwgIYdA.mjs → loader-anchors-TrU7EUr7.mjs} +1 -1
  23. package/dist/postcss.js +3 -1
  24. package/dist/postcss.mjs +3 -1
  25. package/dist/{recorder-rn_2v_nd.js → recorder-gYSNLfOP.js} +1 -1
  26. package/dist/{recorder-B_XyZ576.mjs → recorder-zsgatmkB.mjs} +1 -1
  27. package/dist/tailwindcss/v4-engine/candidates.d.ts +2 -0
  28. package/dist/tailwindcss/v4-engine/miniprogram.d.ts +1 -0
  29. package/dist/tailwindcss/v4-engine/tailwind-v3-compatibility.d.ts +1 -0
  30. package/dist/tailwindcss/v4-engine/tailwind-v3-default-colors.d.ts +1 -0
  31. package/dist/tailwindcss/v4-engine/tailwind-v4-default-colors.d.ts +1 -0
  32. package/dist/tailwindcss/v4-engine/types.d.ts +2 -0
  33. package/dist/{vite-BHpAqldo.js → vite-BC9U7ahn.js} +403 -156
  34. package/dist/{vite-C8JlHiyR.mjs → vite-CrlzCNqz.mjs} +407 -161
  35. package/dist/vite.js +1 -1
  36. package/dist/vite.mjs +1 -1
  37. package/dist/{webpack-CABjKGGQ.mjs → webpack-Bu6M-Hbw.mjs} +3 -3
  38. package/dist/{webpack-DNIJ0ysE.js → webpack-DD7A6V0u.js} +3 -3
  39. package/dist/webpack.js +1 -1
  40. package/dist/webpack.mjs +1 -1
  41. package/dist/webpack4.js +3 -3
  42. package/dist/webpack4.mjs +3 -3
  43. package/package.json +2 -5
  44. package/dist/generator-Dwxgra97.mjs +0 -399
@@ -1,10 +1,10 @@
1
1
  const require_chunk = require("./chunk-8l464Juk.js");
2
- const require_generator = require("./generator-CZ-JXw6T.js");
2
+ const require_generator = require("./generator-mmhXzZnv.js");
3
3
  const require_patcher_options = require("./patcher-options-6gJN2EXy.js");
4
- const require_recorder = require("./recorder-rn_2v_nd.js");
4
+ const require_recorder = require("./recorder-gYSNLfOP.js");
5
5
  const require_utils = require("./utils-DmC9_In3.js");
6
6
  const require_logger = require("./logger-BZ45DZJT.js");
7
- const require_generator_css = require("./generator-css-CnYjiMrD.js");
7
+ const require_generator_css = require("./generator-css-D3OdPRiS.js");
8
8
  const require_css_imports = require("./css-imports-BbrbluP9.js");
9
9
  let node_path = require("node:path");
10
10
  node_path = require_chunk.__toESM(node_path);
@@ -14,12 +14,15 @@ let tailwindcss_patch = require("tailwindcss-patch");
14
14
  let node_buffer = require("node:buffer");
15
15
  let node_fs = require("node:fs");
16
16
  node_fs = require_chunk.__toESM(node_fs);
17
+ let node_fs_promises = require("node:fs/promises");
17
18
  let _weapp_tailwindcss_logger = require("@weapp-tailwindcss/logger");
18
19
  let _weapp_tailwindcss_shared = require("@weapp-tailwindcss/shared");
19
20
  let magic_string = require("magic-string");
20
21
  magic_string = require_chunk.__toESM(magic_string);
21
22
  let _weapp_tailwindcss_shared_extractors = require("@weapp-tailwindcss/shared/extractors");
22
23
  let htmlparser2 = require("htmlparser2");
24
+ let fast_glob = require("fast-glob");
25
+ fast_glob = require_chunk.__toESM(fast_glob);
23
26
  let _weapp_tailwindcss_postcss_html_transform = require("@weapp-tailwindcss/postcss/html-transform");
24
27
  _weapp_tailwindcss_postcss_html_transform = require_chunk.__toESM(_weapp_tailwindcss_postcss_html_transform);
25
28
  let postcss_load_config = require("postcss-load-config");
@@ -508,19 +511,6 @@ function createUniAppXAssetTask(file, originalSource, outDir, options) {
508
511
  };
509
512
  }
510
513
  //#endregion
511
- //#region src/bundlers/shared/generator-candidates.ts
512
- async function collectGeneratorCandidatesFromSources(sources, baseCandidates = []) {
513
- const candidates = new Set(baseCandidates);
514
- await Promise.all(sources.map(async (source) => {
515
- const matches = await (0, tailwindcss_patch.extractRawCandidatesWithPositions)(source.content, source.extension);
516
- for (const match of matches) {
517
- const candidate = match.rawCandidate;
518
- if (typeof candidate === "string" && candidate.length > 0) candidates.add(candidate);
519
- }
520
- }));
521
- return candidates;
522
- }
523
- //#endregion
524
514
  //#region src/bundlers/vite/css-finalizer.ts
525
515
  function createCssHandlerOptions(opts, majorVersion, file) {
526
516
  return {
@@ -542,16 +532,16 @@ function createViteCssFinalizerOutputPlugin(context) {
542
532
  generateBundle: {
543
533
  order: "post",
544
534
  async handler(_options, bundle) {
545
- const { opts, runtimeState, ensureRuntimeClassSet, isCssAssetProcessed, markCssAssetProcessed, debug, getResolvedConfig, recordCssAssetResult, getRecordedGeneratorCandidates } = context;
535
+ const { opts, runtimeState, ensureRuntimeClassSet, isCssAssetProcessed, markCssAssetProcessed, debug, getResolvedConfig, recordCssAssetResult, getRecordedGeneratorCandidates, getSourceCandidates, waitForSourceCandidateSyncs, rememberMainCssSource } = context;
546
536
  if (getResolvedConfig()?.command !== "build") return;
547
537
  const entries = Object.entries(bundle).filter(([, output]) => output.type === "asset" && opts.cssMatcher(output.fileName) && (!isCssAssetProcessed(output, output.fileName) || shouldFinalizeProcessedCssAsset(opts, output.fileName)));
548
538
  if (entries.length === 0) return;
549
539
  await runtimeState.patchPromise;
550
- const runtime = getRecordedGeneratorCandidates?.() ?? await ensureRuntimeClassSet();
551
- const generatorRuntime = await collectGeneratorCandidatesFromSources(Object.entries(bundle).filter(([, output]) => output.type === "asset" || output.type === "chunk").filter(([file]) => opts.htmlMatcher(file) || opts.jsMatcher(file) || opts.wxsMatcher(file)).map(([file, output]) => ({
552
- content: output.type === "chunk" ? output.code : output.source.toString(),
553
- extension: node_path.default.extname(file).replace(/^\./, "") || (opts.htmlMatcher(file) ? "html" : "js")
554
- })), runtime);
540
+ await waitForSourceCandidateSyncs?.();
541
+ const generatorOptions = require_generator.normalizeWeappTailwindcssGeneratorOptions(opts.generator);
542
+ const runtime = getRecordedGeneratorCandidates?.() ?? getSourceCandidates?.() ?? await ensureRuntimeClassSet();
543
+ const collectedGeneratorCandidates = new Set([...runtime, ...getSourceCandidates?.() ?? []]);
544
+ const generatorRuntime = runtimeState.twPatcher.majorVersion === 4 && generatorOptions.target === "weapp" ? require_generator.filterUnsupportedMiniProgramTailwindV4Candidates(collectedGeneratorCandidates) : collectedGeneratorCandidates;
555
545
  await Promise.all(entries.map(async ([bundleFile, output]) => {
556
546
  const file = output.fileName || bundleFile;
557
547
  const rawSource = output.source.toString();
@@ -575,6 +565,7 @@ function createViteCssFinalizerOutputPlugin(context) {
575
565
  if (generated) {
576
566
  debug("css finalizer generated result: %s bytes=%d", file, nextCss.length);
577
567
  recordCssAssetResult?.(file, nextCss);
568
+ if (cssHandlerOptions.isMainChunk) rememberMainCssSource?.(file, rawSource);
578
569
  }
579
570
  output.source = nextCss;
580
571
  markCssAssetProcessed(output, file);
@@ -899,6 +890,18 @@ function createJsHashSalt(runtimeSignature, linkedImpactSignature) {
899
890
  if (!linkedImpactSignature) return runtimeSignature;
900
891
  return `${runtimeSignature}:linked:${linkedImpactSignature}`;
901
892
  }
893
+ function createStableTextSignature(input) {
894
+ let hash = 2166136261;
895
+ for (let i = 0; i < input.length; i++) {
896
+ hash ^= input.charCodeAt(i);
897
+ hash = Math.imul(hash, 16777619);
898
+ }
899
+ return (hash >>> 0).toString(36);
900
+ }
901
+ function createCandidateSignature(candidates) {
902
+ if (candidates.size === 0) return "empty";
903
+ return createStableTextSignature([...candidates].sort().join("\n"));
904
+ }
902
905
  function getSnapshotHash(snapshotMap, file, fallback) {
903
906
  return snapshotMap.get(file) ?? fallback;
904
907
  }
@@ -929,6 +932,21 @@ function createCssTransformShareScopeKey(opts, file, rawSource) {
929
932
  if (require_generator.normalizeWeappTailwindcssGeneratorOptions(opts.generator).mode === "force" && opts.mainCssChunkMatcher(file, opts.appType)) return `main:${require_css_imports.normalizeOutputPathKey(file)}`;
930
933
  return createCssTransformShareScope(file, rawSource);
931
934
  }
935
+ function createCssRuntimeSignature(runtimeSignature, generatorCandidateSignature) {
936
+ return `${runtimeSignature}:${generatorCandidateSignature}`;
937
+ }
938
+ function createReplayCssAsset(fileName, source) {
939
+ return {
940
+ type: "asset",
941
+ fileName,
942
+ name: void 0,
943
+ source,
944
+ needsCodeReference: false,
945
+ names: [],
946
+ originalFileName: null,
947
+ originalFileNames: []
948
+ };
949
+ }
932
950
  function hasOmittedKnownBundleFiles(currentBundleFiles, previousBundleFiles) {
933
951
  const currentFileSet = new Set(currentBundleFiles);
934
952
  for (const file of previousBundleFiles) if (!currentFileSet.has(file)) return true;
@@ -956,36 +974,17 @@ function collectUnescapedDynamicCandidates(source) {
956
974
  }
957
975
  return [...matches];
958
976
  }
959
- function collectLegacyContainerCompatCandidates(sources, runtime) {
960
- if (runtime.has("container")) return runtime;
961
- if (!sources.some((source) => /\bcontainer\b/.test(source.content))) return runtime;
962
- return new Set([...runtime, "container"]);
963
- }
964
- async function collectTailwindV4ContentCandidates(runtimeState, runtime, generatorMode, debug) {
965
- const collectContentTokens = runtimeState.twPatcher.collectContentTokens;
966
- if (generatorMode !== "force" || runtimeState.twPatcher.majorVersion !== 4 || typeof collectContentTokens !== "function") return runtime;
967
- try {
968
- const generator = require_generator.createWeappTailwindcssGenerator(await require_generator.resolveTailwindV4SourceFromPatcher(runtimeState.twPatcher));
969
- const report = await collectContentTokens.call(runtimeState.twPatcher);
970
- const rawCandidates = new Set(report.entries.map((entry) => entry.rawCandidate));
971
- const validCandidates = await generator.validateCandidates(rawCandidates);
972
- if (rawCandidates.size === 0 && validCandidates.size === 0) return runtime;
973
- return new Set([
974
- ...runtime,
975
- ...rawCandidates,
976
- ...validCandidates
977
- ]);
978
- } catch (error) {
979
- debug("collect Tailwind v4 content candidates for generator failed: %O", error);
980
- return runtime;
981
- }
977
+ function collectLegacyContainerCompatCandidates(sourceCandidates, candidates) {
978
+ if (candidates.has("container")) return candidates;
979
+ if (!sourceCandidates.has("container")) return candidates;
980
+ return new Set([...candidates, "container"]);
982
981
  }
983
982
  function createGenerateBundleHook(context) {
984
983
  const state = createBundleBuildState();
985
984
  const cssHandlerOptionsCache = /* @__PURE__ */ new Map();
986
985
  const cssUserHandlerOptionsCache = /* @__PURE__ */ new Map();
987
986
  return async function generateBundle(_opt, bundle) {
988
- const { opts, runtimeState, ensureBundleRuntimeClassSet, debug, getResolvedConfig, markCssAssetProcessed, recordCssAssetResult, recordGeneratorCandidates } = context;
987
+ const { opts, runtimeState, ensureBundleRuntimeClassSet, debug, getResolvedConfig, markCssAssetProcessed, recordCssAssetResult, getSourceCandidates, waitForSourceCandidateSyncs, rememberMainCssSource, getRememberedMainCssSources, getRememberedMainCssSignature, setRememberedMainCssSignature, recordGeneratorCandidates } = context;
989
988
  const { appType, cache, mainCssChunkMatcher, onEnd, onStart, onUpdate, styleHandler, templateHandler, jsHandler, uniAppX } = opts;
990
989
  const generatorOptions = require_generator.normalizeWeappTailwindcssGeneratorOptions(opts.generator);
991
990
  const getCssHandlerOptions = (file) => {
@@ -1041,12 +1040,12 @@ function createGenerateBundleHook(context) {
1041
1040
  const moduleGraphOptions = createBundleModuleGraphOptions(outDir, jsEntries);
1042
1041
  const runtimeStart = performance.now();
1043
1042
  const runtime = useBundleRuntimeClassSet ? await ensureBundleRuntimeClassSet(snapshot, forceRuntimeRefreshByEnv) : await context.ensureRuntimeClassSet(forceRuntimeRefreshByEnv);
1044
- const generatorBaseRuntime = await collectTailwindV4ContentCandidates(runtimeState, runtime, generatorOptions.mode, debug);
1045
- const generatorCandidateSources = snapshot.entries.filter((entry) => entry.type === "html" || entry.type === "js").map((entry) => ({
1046
- content: entry.source,
1047
- extension: node_path.default.extname(entry.file).replace(/^\./, "") || (entry.type === "html" ? "html" : "js")
1048
- }));
1049
- const generatorRuntime = collectLegacyContainerCompatCandidates(generatorCandidateSources, await collectGeneratorCandidatesFromSources(generatorCandidateSources, generatorBaseRuntime));
1043
+ const shouldFilterTailwindV4MiniProgramCandidates = runtimeState.twPatcher.majorVersion === 4 && generatorOptions.target === "weapp";
1044
+ await waitForSourceCandidateSyncs?.();
1045
+ const sourceCandidates = getSourceCandidates?.() ?? /* @__PURE__ */ new Set();
1046
+ const collectedGeneratorCandidates = generatorOptions.mode === "force" ? new Set(sourceCandidates) : new Set([...runtime, ...sourceCandidates]);
1047
+ const generatorRuntime = collectLegacyContainerCompatCandidates(sourceCandidates, shouldFilterTailwindV4MiniProgramCandidates ? require_generator.filterUnsupportedMiniProgramTailwindV4Candidates(collectedGeneratorCandidates) : collectedGeneratorCandidates);
1048
+ const generatorCandidateSignature = createCandidateSignature(generatorRuntime);
1050
1049
  recordGeneratorCandidates?.(generatorRuntime);
1051
1050
  const defaultTemplateHandlerOptions = { runtimeSet: runtime };
1052
1051
  metrics.runtimeSet = measureElapsed(runtimeStart);
@@ -1124,15 +1123,17 @@ function createGenerateBundleHook(context) {
1124
1123
  const cssRuntimeAffectingSignature = snapshot.runtimeAffectingSignatureByFile.get(file) ?? rawSource;
1125
1124
  const cssShareScope = createCssTransformShareScopeKey(opts, file, rawSource);
1126
1125
  const cssHandlerOptions = getCssHandlerOptions(file);
1127
- const cssSharedCacheKey = `${cssShareScope}:${runtimeSignature}:${runtimeState.twPatcher.majorVersion ?? "unknown"}:${cssHandlerOptions.isMainChunk ? "1" : "0"}:${cssRuntimeAffectingSignature}`;
1126
+ const cssRuntimeSignature = createCssRuntimeSignature(runtimeSignature, generatorCandidateSignature);
1127
+ const cssSharedCacheKey = `${cssShareScope}:${cssRuntimeSignature}:${runtimeState.twPatcher.majorVersion ?? "unknown"}:${cssHandlerOptions.isMainChunk ? "1" : "0"}:${cssRuntimeAffectingSignature}`;
1128
1128
  tasks.push(require_generator_css.processCachedTask({
1129
1129
  cache,
1130
1130
  cacheKey: file,
1131
- hashKey: `${file}:css:${runtimeSignature}:${runtimeState.twPatcher.majorVersion ?? "unknown"}`,
1132
- hash: getSnapshotHash(snapshot.runtimeAffectingHashByFile, file, cssRuntimeAffectingSignature),
1131
+ hashKey: `${file}:css:${cssRuntimeSignature}:${runtimeState.twPatcher.majorVersion ?? "unknown"}`,
1132
+ hash: `${getSnapshotHash(snapshot.runtimeAffectingHashByFile, file, cssRuntimeAffectingSignature)}:${generatorCandidateSignature}`,
1133
1133
  applyResult(source) {
1134
1134
  originalSource.source = source;
1135
1135
  markCssAssetProcessed?.(originalSource, file);
1136
+ if (cssHandlerOptions.isMainChunk) rememberMainCssSource?.(file, rawSource, cssRuntimeSignature);
1136
1137
  },
1137
1138
  onCacheHit() {
1138
1139
  metrics.css.cacheHits++;
@@ -1286,6 +1287,43 @@ function createGenerateBundleHook(context) {
1286
1287
  });
1287
1288
  }
1288
1289
  }
1290
+ const cssRuntimeSignature = createCssRuntimeSignature(runtimeSignature, generatorCandidateSignature);
1291
+ if (useIncrementalMode && generatorOptions.mode === "force") for (const [file, rawSource] of getRememberedMainCssSources?.() ?? []) {
1292
+ if (bundleFiles.includes(file) || getRememberedMainCssSignature?.(file) === cssRuntimeSignature) continue;
1293
+ tasks.push((async () => {
1294
+ const start = performance.now();
1295
+ const cssHandlerOptions = getCssHandlerOptions(file);
1296
+ const generated = await require_generator_css.generateCssByGenerator({
1297
+ opts,
1298
+ runtimeState,
1299
+ runtime: generatorRuntime,
1300
+ rawSource,
1301
+ file,
1302
+ cssHandlerOptions,
1303
+ cssUserHandlerOptions: getCssUserHandlerOptions(file),
1304
+ styleHandler,
1305
+ debug
1306
+ });
1307
+ const css = generated?.css ?? (await styleHandler(rawSource, cssHandlerOptions)).css;
1308
+ setRememberedMainCssSignature?.(file, cssRuntimeSignature);
1309
+ if (generated) {
1310
+ recordCssAssetResult?.(file, generated.css);
1311
+ debug("css replay generated result: %s bytes=%d", file, css.length);
1312
+ }
1313
+ const replayAsset = createReplayCssAsset(file, css);
1314
+ if (typeof this.emitFile === "function") this.emitFile({
1315
+ type: "asset",
1316
+ fileName: file,
1317
+ source: css
1318
+ });
1319
+ else bundle[file] = replayAsset;
1320
+ markCssAssetProcessed?.(replayAsset, file);
1321
+ metrics.css.elapsed += measureElapsed(start);
1322
+ metrics.css.transformed++;
1323
+ onUpdate(file, rawSource, css);
1324
+ debug("css replay handle: %s", file);
1325
+ })());
1326
+ }
1289
1327
  require_css_imports.pushConcurrentTaskFactories(tasks, jsTaskFactories);
1290
1328
  await Promise.all(tasks);
1291
1329
  for (const apply of pendingLinkedUpdates) apply();
@@ -1323,7 +1361,7 @@ function resolveEntryExtension(entry) {
1323
1361
  function createCandidateValidationSource(candidates) {
1324
1362
  return [...new Set(candidates)].sort().join("\n");
1325
1363
  }
1326
- function removeCandidateSet(candidateCountByClass, runtimeSet, candidates) {
1364
+ function removeCandidateSet$1(candidateCountByClass, runtimeSet, candidates) {
1327
1365
  for (const className of candidates) {
1328
1366
  const count = candidateCountByClass.get(className);
1329
1367
  if (count == null) continue;
@@ -1335,7 +1373,7 @@ function removeCandidateSet(candidateCountByClass, runtimeSet, candidates) {
1335
1373
  candidateCountByClass.set(className, count - 1);
1336
1374
  }
1337
1375
  }
1338
- function addCandidateSet(candidateCountByClass, runtimeSet, candidates) {
1376
+ function addCandidateSet$1(candidateCountByClass, runtimeSet, candidates) {
1339
1377
  for (const className of candidates) {
1340
1378
  const nextCount = (candidateCountByClass.get(className) ?? 0) + 1;
1341
1379
  candidateCountByClass.set(className, nextCount);
@@ -1418,7 +1456,7 @@ function createBundleRuntimeClassSetManager(options = {}) {
1418
1456
  runtimeSignature = nextSignature;
1419
1457
  for (const [file, previousCandidates] of candidatesByFile) {
1420
1458
  if (currentRuntimeFiles.has(file)) continue;
1421
- removeCandidateSet(candidateCountByClass, runtimeSet, previousCandidates);
1459
+ removeCandidateSet$1(candidateCountByClass, runtimeSet, previousCandidates);
1422
1460
  candidatesByFile.delete(file);
1423
1461
  }
1424
1462
  const changedRuntimeFiles = fullRebuild ? [...runtimeEntriesByFile.keys()] : [...collectChangedRuntimeFiles(snapshot)];
@@ -1437,7 +1475,7 @@ function createBundleRuntimeClassSetManager(options = {}) {
1437
1475
  for (const file of changedRuntimeFiles) {
1438
1476
  const nextRawCandidates = rawCandidatesByFile.get(file);
1439
1477
  const previousCandidates = candidatesByFile.get(file);
1440
- if (previousCandidates) removeCandidateSet(candidateCountByClass, runtimeSet, previousCandidates);
1478
+ if (previousCandidates) removeCandidateSet$1(candidateCountByClass, runtimeSet, previousCandidates);
1441
1479
  if (!nextRawCandidates || nextRawCandidates.size === 0) {
1442
1480
  candidatesByFile.delete(file);
1443
1481
  continue;
@@ -1448,7 +1486,7 @@ function createBundleRuntimeClassSetManager(options = {}) {
1448
1486
  candidatesByFile.delete(file);
1449
1487
  continue;
1450
1488
  }
1451
- addCandidateSet(candidateCountByClass, runtimeSet, nextCandidates);
1489
+ addCandidateSet$1(candidateCountByClass, runtimeSet, nextCandidates);
1452
1490
  candidatesByFile.set(file, nextCandidates);
1453
1491
  }
1454
1492
  debug$1("incremental runtime set synced, changedFiles=%d rawCandidates=%d validateMisses=%d runtimeSize=%d trackedFiles=%d", changedRuntimeFiles.length, rawCandidateCount, unknownCandidates.size, runtimeSet.size, candidatesByFile.size);
@@ -1570,6 +1608,158 @@ function createRewriteCssImportsPlugins(options) {
1570
1608
  }];
1571
1609
  }
1572
1610
  //#endregion
1611
+ //#region src/bundlers/vite/source-candidates.ts
1612
+ const CLEAN_URL_RE = /[?#].*$/;
1613
+ const SOURCE_CANDIDATE_EXTENSIONS = [
1614
+ "js",
1615
+ "jsx",
1616
+ "mjs",
1617
+ "cjs",
1618
+ "ts",
1619
+ "tsx",
1620
+ "mts",
1621
+ "cts",
1622
+ "vue",
1623
+ "uvue",
1624
+ "nvue",
1625
+ "svelte",
1626
+ "mpx",
1627
+ "html",
1628
+ "wxml",
1629
+ "axml",
1630
+ "jxml",
1631
+ "ksml",
1632
+ "ttml",
1633
+ "qml",
1634
+ "tyml",
1635
+ "xhsml",
1636
+ "swan",
1637
+ "css",
1638
+ "wxss",
1639
+ "acss",
1640
+ "jxss",
1641
+ "ttss",
1642
+ "qss",
1643
+ "tyss",
1644
+ "scss",
1645
+ "sass",
1646
+ "less",
1647
+ "styl",
1648
+ "stylus"
1649
+ ];
1650
+ const SOURCE_CANDIDATE_EXTENSION_RE = /\.(?:[cm]?[jt]sx?|vue|uvue|nvue|svelte|mpx|html|wxml|axml|jxml|ksml|ttml|qml|tyml|xhsml|swan|css|wxss|acss|jxss|ttss|qss|tyss|scss|sass|less|stylus?)$/;
1651
+ const CSS_SOURCE_CANDIDATE_EXTENSION_RE = /^(?:css|wxss|acss|jxss|ttss|qss|tyss|scss|sass|less|styl|stylus)$/;
1652
+ const SOURCE_CANDIDATE_GLOB = `**/*.{${SOURCE_CANDIDATE_EXTENSIONS.join(",")}}`;
1653
+ const DEFAULT_SCAN_IGNORE = ["**/node_modules/**", "**/.git/**"];
1654
+ function cleanUrl(id) {
1655
+ return id.replace(CLEAN_URL_RE, "");
1656
+ }
1657
+ function toPosixPath(value) {
1658
+ return value.split(node_path.default.sep).join("/");
1659
+ }
1660
+ function resolveOutDirIgnorePattern(root, outDir) {
1661
+ if (!outDir) return;
1662
+ const relative = node_path.default.relative(root, node_path.default.resolve(root, outDir));
1663
+ if (!relative || relative.startsWith("..") || node_path.default.isAbsolute(relative)) return;
1664
+ return `${toPosixPath(relative)}/**`;
1665
+ }
1666
+ function resolveSourceCandidateExtension(id) {
1667
+ const normalized = cleanUrl(id);
1668
+ return /\.([^.\\/]+)$/.exec(normalized)?.[1] ?? "html";
1669
+ }
1670
+ function isSourceCandidateRequest(id) {
1671
+ return SOURCE_CANDIDATE_EXTENSION_RE.test(cleanUrl(id));
1672
+ }
1673
+ function removeCandidateSet(candidateCount, candidates) {
1674
+ for (const candidate of candidates) {
1675
+ const count = candidateCount.get(candidate);
1676
+ if (count == null) continue;
1677
+ if (count <= 1) {
1678
+ candidateCount.delete(candidate);
1679
+ continue;
1680
+ }
1681
+ candidateCount.set(candidate, count - 1);
1682
+ }
1683
+ }
1684
+ function addCandidateSet(candidateCount, candidates) {
1685
+ for (const candidate of candidates) candidateCount.set(candidate, (candidateCount.get(candidate) ?? 0) + 1);
1686
+ }
1687
+ const CSS_APPLY_RE = /@apply\s+([^;{}]+)/g;
1688
+ const CSS_APPLY_IMPORTANT = "!important";
1689
+ function extractCssApplyCandidates(source) {
1690
+ const candidates = /* @__PURE__ */ new Set();
1691
+ CSS_APPLY_RE.lastIndex = 0;
1692
+ let match = CSS_APPLY_RE.exec(source);
1693
+ while (match !== null) {
1694
+ const params = match[1] ?? "";
1695
+ for (const candidate of (0, _weapp_tailwindcss_shared_extractors.splitCode)(params, true)) {
1696
+ const normalized = candidate.trim();
1697
+ if (normalized && normalized !== CSS_APPLY_IMPORTANT) candidates.add(normalized);
1698
+ }
1699
+ match = CSS_APPLY_RE.exec(source);
1700
+ }
1701
+ return candidates;
1702
+ }
1703
+ function createSourceCandidateCollector() {
1704
+ const candidatesById = /* @__PURE__ */ new Map();
1705
+ const candidateCount = /* @__PURE__ */ new Map();
1706
+ async function sync(id, source) {
1707
+ const normalizedId = cleanUrl(id);
1708
+ const extension = resolveSourceCandidateExtension(normalizedId);
1709
+ const nextCandidates = /* @__PURE__ */ new Set();
1710
+ if (CSS_SOURCE_CANDIDATE_EXTENSION_RE.test(extension)) for (const candidate of extractCssApplyCandidates(source)) nextCandidates.add(candidate);
1711
+ else {
1712
+ const matches = await (0, tailwindcss_patch.extractRawCandidatesWithPositions)(source, extension);
1713
+ for (const match of matches) {
1714
+ const candidate = match.rawCandidate;
1715
+ if (typeof candidate === "string" && candidate.length > 0) nextCandidates.add(candidate);
1716
+ }
1717
+ }
1718
+ remove(normalizedId);
1719
+ if (nextCandidates.size === 0) return;
1720
+ candidatesById.set(normalizedId, nextCandidates);
1721
+ addCandidateSet(candidateCount, nextCandidates);
1722
+ }
1723
+ async function syncFile(id) {
1724
+ const normalizedId = cleanUrl(id);
1725
+ await sync(normalizedId, await (0, node_fs_promises.readFile)(normalizedId, "utf8"));
1726
+ }
1727
+ async function scanRoot({ root, outDir }) {
1728
+ const resolvedRoot = node_path.default.resolve(root);
1729
+ const outDirIgnore = resolveOutDirIgnorePattern(resolvedRoot, outDir);
1730
+ const files = await (0, fast_glob.default)(SOURCE_CANDIDATE_GLOB, {
1731
+ absolute: true,
1732
+ cwd: resolvedRoot,
1733
+ ignore: outDirIgnore ? [...DEFAULT_SCAN_IGNORE, outDirIgnore] : DEFAULT_SCAN_IGNORE,
1734
+ onlyFiles: true,
1735
+ unique: true
1736
+ });
1737
+ await Promise.all(files.map((file) => syncFile(file)));
1738
+ }
1739
+ function remove(id) {
1740
+ const normalizedId = cleanUrl(id);
1741
+ const previousCandidates = candidatesById.get(normalizedId);
1742
+ if (!previousCandidates) return;
1743
+ removeCandidateSet(candidateCount, previousCandidates);
1744
+ candidatesById.delete(normalizedId);
1745
+ }
1746
+ function values() {
1747
+ return new Set(candidateCount.keys());
1748
+ }
1749
+ function clear() {
1750
+ candidatesById.clear();
1751
+ candidateCount.clear();
1752
+ }
1753
+ return {
1754
+ sync,
1755
+ syncFile,
1756
+ scanRoot,
1757
+ remove,
1758
+ values,
1759
+ clear
1760
+ };
1761
+ }
1762
+ //#endregion
1573
1763
  //#region src/bundlers/vite/index.ts
1574
1764
  const debug = require_recorder.createDebug();
1575
1765
  const weappTailwindcssPackageDir = require_css_imports.resolvePackageDir("weapp-tailwindcss");
@@ -1714,8 +1904,12 @@ function UnifiedViteWeappTailwindcssPlugin(options = {}) {
1714
1904
  let runtimeRefreshOptionsKey;
1715
1905
  let recordedGeneratorCandidates;
1716
1906
  const bundleRuntimeClassSetManager = createBundleRuntimeClassSetManager();
1907
+ const sourceCandidateCollector = createSourceCandidateCollector();
1908
+ const pendingSourceCandidateSyncs = /* @__PURE__ */ new Set();
1717
1909
  const processedCssAssets = /* @__PURE__ */ new WeakSet();
1718
1910
  const processedCssAssetFiles = /* @__PURE__ */ new Set();
1911
+ const rememberedMainCssSources = /* @__PURE__ */ new Map();
1912
+ const rememberedMainCssSignatureByFile = /* @__PURE__ */ new Map();
1719
1913
  function resolveRuntimeRefreshOptions() {
1720
1914
  const configPath = require_patcher_options.resolveTailwindcssOptions(runtimeState.twPatcher.options)?.config;
1721
1915
  const signature = require_logger.getRuntimeClassSetSignature(runtimeState.twPatcher);
@@ -1783,15 +1977,8 @@ function UnifiedViteWeappTailwindcssPlugin(options = {}) {
1783
1977
  }
1784
1978
  if (runtimeState.twPatcher.majorVersion === 4 && !forceRuntimeRefresh) try {
1785
1979
  const nextRuntimeSet = await bundleRuntimeClassSetManager.sync(runtimeState.twPatcher, snapshot);
1786
- const shouldForceFullRuntimeSet = forceRuntimeRefresh || invalidation.changed || forceCollectBySource;
1787
- const fullRuntimeSet = !shouldForceFullRuntimeSet && runtimeSet ? runtimeSet : await require_recorder.collectRuntimeClassSet(runtimeState.twPatcher, {
1788
- force: shouldForceFullRuntimeSet,
1789
- skipRefresh: forceRuntimeRefresh,
1790
- clearCache: forceRuntimeRefresh || invalidation.changed
1791
- });
1792
- const mergedRuntimeSet = new Set([...fullRuntimeSet, ...nextRuntimeSet]);
1793
- runtimeSet = mergedRuntimeSet;
1794
- return mergedRuntimeSet;
1980
+ runtimeSet = nextRuntimeSet;
1981
+ return nextRuntimeSet;
1795
1982
  } catch (error) {
1796
1983
  debug("incremental runtime set sync failed, fallback to full collect: %O", error);
1797
1984
  await bundleRuntimeClassSetManager.reset();
@@ -1820,13 +2007,33 @@ function UnifiedViteWeappTailwindcssPlugin(options = {}) {
1820
2007
  return processedCssAssets.has(asset) || (file ? processedCssAssetFiles.has(require_css_imports.normalizeOutputPathKey(file)) : false);
1821
2008
  };
1822
2009
  const recordGeneratorCandidates = (candidates) => {
1823
- if (!recordedGeneratorCandidates) {
1824
- recordedGeneratorCandidates = new Set(candidates);
1825
- return;
1826
- }
1827
- for (const candidate of candidates) recordedGeneratorCandidates.add(candidate);
2010
+ recordedGeneratorCandidates = new Set(candidates);
1828
2011
  };
1829
2012
  const getRecordedGeneratorCandidates = () => recordedGeneratorCandidates;
2013
+ const getSourceCandidates = () => sourceCandidateCollector.values();
2014
+ const isWatchBuild = () => resolvedConfig?.command === "build" && resolvedConfig.build.watch != null;
2015
+ const waitForSourceCandidateSyncs = async () => {
2016
+ while (pendingSourceCandidateSyncs.size > 0) await Promise.all(pendingSourceCandidateSyncs);
2017
+ };
2018
+ const syncChangedSourceCandidateFile = (id) => {
2019
+ if (!shouldOwnTailwindGeneration || !isSourceCandidateRequest(id)) return Promise.resolve();
2020
+ const task = sourceCandidateCollector.syncFile(id).catch((error) => {
2021
+ debug("source candidate watch sync failed: %s %O", id, error);
2022
+ }).finally(() => {
2023
+ pendingSourceCandidateSyncs.delete(task);
2024
+ });
2025
+ pendingSourceCandidateSyncs.add(task);
2026
+ return task;
2027
+ };
2028
+ const rememberMainCssSource = (file, rawSource, cssRuntimeSignature) => {
2029
+ rememberedMainCssSources.set(file, rawSource);
2030
+ if (cssRuntimeSignature) rememberedMainCssSignatureByFile.set(file, cssRuntimeSignature);
2031
+ };
2032
+ const getRememberedMainCssSources = () => rememberedMainCssSources;
2033
+ const getRememberedMainCssSignature = (file) => rememberedMainCssSignatureByFile.get(file);
2034
+ const setRememberedMainCssSignature = (file, cssRuntimeSignature) => {
2035
+ rememberedMainCssSignatureByFile.set(file, cssRuntimeSignature);
2036
+ };
1830
2037
  const cssFinalizerOutputPlugin = createViteCssFinalizerOutputPlugin({
1831
2038
  opts,
1832
2039
  runtimeState,
@@ -1835,7 +2042,10 @@ function UnifiedViteWeappTailwindcssPlugin(options = {}) {
1835
2042
  getResolvedConfig,
1836
2043
  markCssAssetProcessed,
1837
2044
  isCssAssetProcessed,
1838
- getRecordedGeneratorCandidates
2045
+ getRecordedGeneratorCandidates,
2046
+ getSourceCandidates,
2047
+ waitForSourceCandidateSyncs,
2048
+ rememberMainCssSource
1839
2049
  });
1840
2050
  const isIosPlatform = require_utils.resolveUniUtsPlatform().isAppIos;
1841
2051
  const uniAppXPlugins = uniAppXEnabled ? createUniAppXPlugins({
@@ -1851,95 +2061,132 @@ function UnifiedViteWeappTailwindcssPlugin(options = {}) {
1851
2061
  getResolvedConfig,
1852
2062
  uniAppX
1853
2063
  }) : void 0;
1854
- const plugins = [...rewritePlugins, {
1855
- name: `${require_recorder.vitePluginName}:post`,
1856
- enforce: "post",
1857
- config(config) {
1858
- if (!shouldOwnTailwindGeneration) return;
1859
- if (Array.isArray(config.plugins)) {
1860
- const removed = disableAndRemoveTailwindVitePlugins(config.plugins);
1861
- if (removed > 0) debug("disable official tailwind vite plugins in generator mode: %d", removed);
1862
- }
1863
- const root = config.root ? node_path.default.resolve(config.root) : node_process.default.cwd();
1864
- const baseConfig = { resolve: { alias: [{
1865
- find: /^tailwindcss$/,
1866
- replacement: node_path.default.join(weappTailwindcssPackageDir, "generator-placeholder.css")
1867
- }] } };
1868
- if (config.css?.postcss !== void 0) return baseConfig;
1869
- return resolveFilteredPostcssConfig(root).then((postcssConfig) => {
1870
- if (!postcssConfig) return baseConfig;
1871
- debug("inline filtered postcss config without official tailwind plugins in generator mode: %d", postcssConfig.removed);
1872
- return {
1873
- ...baseConfig,
1874
- css: { postcss: {
1875
- ...postcssConfig.options,
1876
- plugins: postcssConfig.plugins
1877
- } }
1878
- };
1879
- });
1880
- },
1881
- async configResolved(config) {
1882
- resolvedConfig = config;
1883
- if (shouldOwnTailwindGeneration) {
1884
- const removed = Array.isArray(config.plugins) ? removeTailwindVitePlugins(config.plugins) : 0;
1885
- if (removed > 0) debug("remove official tailwind vite plugins in generator mode: %d", removed);
1886
- }
1887
- const resolvedRoot = config.root ? node_path.default.resolve(config.root) : void 0;
1888
- let shouldRefreshRuntime = false;
1889
- if (!hasExplicitTailwindcssBasedir && resolvedRoot) {
1890
- const nextTailwindcssBasedir = resolveImplicitTailwindcssBasedirFromViteRoot(resolvedRoot);
1891
- if (opts.tailwindcssBasedir !== nextTailwindcssBasedir) {
1892
- const previousBasedir = opts.tailwindcssBasedir;
1893
- opts.tailwindcssBasedir = nextTailwindcssBasedir;
1894
- debug("align tailwindcss basedir with vite root: %s -> %s", previousBasedir ?? "undefined", nextTailwindcssBasedir);
1895
- shouldRefreshRuntime = true;
2064
+ const plugins = [
2065
+ ...rewritePlugins,
2066
+ {
2067
+ name: `${require_recorder.vitePluginName}:source-candidates`,
2068
+ enforce: "pre",
2069
+ async transform(code, id) {
2070
+ if (!shouldOwnTailwindGeneration || !isSourceCandidateRequest(id)) return;
2071
+ await sourceCandidateCollector.sync(id, code);
2072
+ },
2073
+ async watchChange(id, change) {
2074
+ if (change.event === "delete") {
2075
+ sourceCandidateCollector.remove(id);
2076
+ return;
1896
2077
  }
2078
+ await syncChangedSourceCandidateFile(id);
2079
+ },
2080
+ async handleHotUpdate(ctx) {
2081
+ await syncChangedSourceCandidateFile(ctx.file);
2082
+ },
2083
+ async buildStart() {
2084
+ if (!shouldOwnTailwindGeneration) return;
2085
+ if (resolvedConfig?.command === "build" && !isWatchBuild()) sourceCandidateCollector.clear();
2086
+ const root = resolvedConfig?.root ?? node_process.default.cwd();
2087
+ const outDir = resolvedConfig?.build?.outDir;
2088
+ await sourceCandidateCollector.scanRoot({
2089
+ root,
2090
+ outDir
2091
+ });
1897
2092
  }
1898
- if (!hasExplicitAppType && resolvedRoot) {
1899
- const nextAppType = resolveImplicitAppTypeFromViteRoot(resolvedRoot);
1900
- if (nextAppType && opts.appType !== nextAppType) {
1901
- const previousAppType = opts.appType;
1902
- opts.appType = nextAppType;
1903
- _weapp_tailwindcss_logger.logger.info("根据 Vite 项目根目录自动推断 appType -> %s", nextAppType);
1904
- debug("align appType with vite root: %s -> %s", previousAppType ?? "undefined", nextAppType);
1905
- shouldRefreshRuntime = true;
2093
+ },
2094
+ {
2095
+ name: `${require_recorder.vitePluginName}:post`,
2096
+ enforce: "post",
2097
+ config(config) {
2098
+ if (!shouldOwnTailwindGeneration) return;
2099
+ if (Array.isArray(config.plugins)) {
2100
+ const removed = disableAndRemoveTailwindVitePlugins(config.plugins);
2101
+ if (removed > 0) debug("disable official tailwind vite plugins in generator mode: %d", removed);
1906
2102
  }
1907
- }
1908
- if (shouldRefreshRuntime) await refreshRuntimeState(true);
1909
- if (typeof config.css.postcss === "object" && Array.isArray(config.css.postcss.plugins)) {
1910
- const postcssPlugins = config.css.postcss.plugins;
2103
+ const root = config.root ? node_path.default.resolve(config.root) : node_process.default.cwd();
2104
+ const baseConfig = { resolve: { alias: [{
2105
+ find: /^tailwindcss$/,
2106
+ replacement: node_path.default.join(weappTailwindcssPackageDir, "generator-placeholder.css")
2107
+ }] } };
2108
+ if (config.css?.postcss !== void 0) return baseConfig;
2109
+ return resolveFilteredPostcssConfig(root).then((postcssConfig) => {
2110
+ if (!postcssConfig) return baseConfig;
2111
+ debug("inline filtered postcss config without official tailwind plugins in generator mode: %d", postcssConfig.removed);
2112
+ return {
2113
+ ...baseConfig,
2114
+ css: { postcss: {
2115
+ ...postcssConfig.options,
2116
+ plugins: postcssConfig.plugins
2117
+ } }
2118
+ };
2119
+ });
2120
+ },
2121
+ async configResolved(config) {
2122
+ resolvedConfig = config;
1911
2123
  if (shouldOwnTailwindGeneration) {
1912
- const removed = removeTailwindPostcssPlugins(postcssPlugins);
1913
- if (removed > 0) debug("remove official tailwind postcss plugins in generator mode: %d", removed);
2124
+ const removed = Array.isArray(config.plugins) ? removeTailwindVitePlugins(config.plugins) : 0;
2125
+ if (removed > 0) debug("remove official tailwind vite plugins in generator mode: %d", removed);
2126
+ }
2127
+ const resolvedRoot = config.root ? node_path.default.resolve(config.root) : void 0;
2128
+ let shouldRefreshRuntime = false;
2129
+ if (!hasExplicitTailwindcssBasedir && resolvedRoot) {
2130
+ const nextTailwindcssBasedir = resolveImplicitTailwindcssBasedirFromViteRoot(resolvedRoot);
2131
+ if (opts.tailwindcssBasedir !== nextTailwindcssBasedir) {
2132
+ const previousBasedir = opts.tailwindcssBasedir;
2133
+ opts.tailwindcssBasedir = nextTailwindcssBasedir;
2134
+ debug("align tailwindcss basedir with vite root: %s -> %s", previousBasedir ?? "undefined", nextTailwindcssBasedir);
2135
+ shouldRefreshRuntime = true;
2136
+ }
1914
2137
  }
1915
- const idx = postcssPlugins.findIndex((x) => getPostcssPluginName(x) === "postcss-html-transform");
1916
- if (idx > -1) {
1917
- postcssPlugins.splice(idx, 1, (0, _weapp_tailwindcss_postcss_html_transform.default)());
1918
- debug("remove postcss-html-transform plugin from vite config");
2138
+ if (!hasExplicitAppType && resolvedRoot) {
2139
+ const nextAppType = resolveImplicitAppTypeFromViteRoot(resolvedRoot);
2140
+ if (nextAppType && opts.appType !== nextAppType) {
2141
+ const previousAppType = opts.appType;
2142
+ opts.appType = nextAppType;
2143
+ _weapp_tailwindcss_logger.logger.info("根据 Vite 项目根目录自动推断 appType -> %s", nextAppType);
2144
+ debug("align appType with vite root: %s -> %s", previousAppType ?? "undefined", nextAppType);
2145
+ shouldRefreshRuntime = true;
2146
+ }
2147
+ }
2148
+ if (shouldRefreshRuntime) await refreshRuntimeState(true);
2149
+ if (typeof config.css.postcss === "object" && Array.isArray(config.css.postcss.plugins)) {
2150
+ const postcssPlugins = config.css.postcss.plugins;
2151
+ if (shouldOwnTailwindGeneration) {
2152
+ const removed = removeTailwindPostcssPlugins(postcssPlugins);
2153
+ if (removed > 0) debug("remove official tailwind postcss plugins in generator mode: %d", removed);
2154
+ }
2155
+ const idx = postcssPlugins.findIndex((x) => getPostcssPluginName(x) === "postcss-html-transform");
2156
+ if (idx > -1) {
2157
+ postcssPlugins.splice(idx, 1, (0, _weapp_tailwindcss_postcss_html_transform.default)());
2158
+ debug("remove postcss-html-transform plugin from vite config");
2159
+ }
1919
2160
  }
2161
+ },
2162
+ generateBundle: {
2163
+ order: "post",
2164
+ handler: createGenerateBundleHook({
2165
+ opts,
2166
+ runtimeState,
2167
+ ensureRuntimeClassSet,
2168
+ ensureBundleRuntimeClassSet,
2169
+ debug,
2170
+ getResolvedConfig,
2171
+ markCssAssetProcessed,
2172
+ getSourceCandidates,
2173
+ waitForSourceCandidateSyncs,
2174
+ rememberMainCssSource,
2175
+ getRememberedMainCssSources,
2176
+ getRememberedMainCssSignature,
2177
+ setRememberedMainCssSignature,
2178
+ recordGeneratorCandidates
2179
+ })
2180
+ },
2181
+ outputOptions(options) {
2182
+ const plugins = options.plugins;
2183
+ return {
2184
+ ...options,
2185
+ plugins: Array.isArray(plugins) ? [...plugins, cssFinalizerOutputPlugin] : [cssFinalizerOutputPlugin]
2186
+ };
1920
2187
  }
1921
- },
1922
- generateBundle: {
1923
- order: "post",
1924
- handler: createGenerateBundleHook({
1925
- opts,
1926
- runtimeState,
1927
- ensureRuntimeClassSet,
1928
- ensureBundleRuntimeClassSet,
1929
- debug,
1930
- getResolvedConfig,
1931
- markCssAssetProcessed,
1932
- recordGeneratorCandidates
1933
- })
1934
- },
1935
- outputOptions(options) {
1936
- const plugins = options.plugins;
1937
- return {
1938
- ...options,
1939
- plugins: Array.isArray(plugins) ? [...plugins, cssFinalizerOutputPlugin] : [cssFinalizerOutputPlugin]
1940
- };
1941
2188
  }
1942
- }];
2189
+ ];
1943
2190
  if (uniAppXPlugins) plugins.push(...uniAppXPlugins);
1944
2191
  return plugins;
1945
2192
  }