weapp-tailwindcss
Version:
把 tailwindcss 原子化样式思想,带给小程序开发者们! bring tailwindcss to miniprogram developers!
1,282 lines • 64.6 kB
JavaScript
import { C as findWorkspacePackageDir, Ct as expandTailwindSourceEntries, D as resolveTailwindcssOptions, Dt as resolveCssSourceEntries, E as normalizeTailwindcssRuntimeOptions, Et as parseConfigParam, Lt as loadTailwindV4DesignSystem, Nt as resolveCssMacroTailwindV4Source, O as normalizeStringListOption, S as findNearestPackageRoot, St as createTailwindSourceEntryMatcher, T as normalizeExtendLengthUnits, Tt as normalizeLegacyContentEntries, b as isTailwindV4CssEntry, d as resolveTailwindV4SourceFromRuntime, h as hasConfiguredTailwindV4CssRoots, i as normalizeWeappTailwindcssGeneratorOptions, kt as resolveTailwindV4CssSourceBase, m as filterTailwindV4CssSourceRoots, p as resolveTailwindV4SourceOptionsFromRuntime, v as groupCssEntriesByBase, w as findWorkspaceRoot, x as normalizeCssEntries, xt as FULL_SOURCE_SCAN_PATTERN, y as guessBasedirFromEntries } from "./generator-DYeAa2-5.js";
import { t as omitUndefined } from "./object-Bvy6-w9r.js";
import { n as defuOverrideArray$1 } from "./utils-MVwpU07P.js";
import { createRequire } from "node:module";
import { existsSync, readFileSync, statSync } from "node:fs";
import path from "node:path";
import process from "node:process";
import { extractProjectCandidatesWithPositions, resolveValidTailwindV4Candidates } from "@tailwindcss-mangle/engine";
import { postcss } from "@weapp-tailwindcss/postcss";
import { stat } from "node:fs/promises";
import { defuOverrideArray } from "@weapp-tailwindcss/shared";
import fg from "fast-glob";
import { loadConfig } from "tailwindcss-config";
import { logger } from "@weapp-tailwindcss/logger";
import { fileURLToPath } from "node:url";
//#region src/tailwindcss/source-scan/inline-source.ts
const NUMERICAL_RANGE_RE = /^(-?\d+)\.\.(-?\d+)(?:\.\.(-?\d+))?$/;
function segmentTopLevel(input, separator, options = {}) {
const parts = [];
const stack = [];
let lastPos = 0;
let quote;
for (let index = 0; index < input.length; index++) {
const char = input[index];
if (char === "\\") {
index += 1;
continue;
}
if (quote) {
if (char === quote) quote = void 0;
continue;
}
if (char === "\"" || char === "'") {
quote = char;
continue;
}
if (char === "(") {
stack.push(")");
continue;
}
if (char === "[") {
stack.push("]");
continue;
}
if (char === "{") {
stack.push("}");
continue;
}
if (stack.length > 0 && char === stack[stack.length - 1]) {
stack.pop();
continue;
}
if (stack.length === 0 && char === separator) {
const part = input.slice(lastPos, index);
if (part || options.keepEmpty) parts.push(part);
lastPos = index + 1;
}
}
const part = input.slice(lastPos);
if (part || options.keepEmpty) parts.push(part);
return parts;
}
function isSequence(value) {
return NUMERICAL_RANGE_RE.test(value);
}
function expandSequence(value) {
const match = value.match(NUMERICAL_RANGE_RE);
if (!match) return [value];
const [, start, end, stepValue] = match;
if (start === void 0 || end === void 0) return [value];
let step = stepValue ? Number.parseInt(stepValue, 10) : void 0;
const startNumber = Number.parseInt(start, 10);
const endNumber = Number.parseInt(end, 10);
const increasing = startNumber < endNumber;
if (step === void 0) step = increasing ? 1 : -1;
if (step === 0) return [];
if (increasing && step < 0) step = -step;
if (!increasing && step > 0) step = -step;
const result = [];
for (let value = startNumber; increasing ? value <= endNumber : value >= endNumber; value += step) result.push(String(value));
return result;
}
function expandInlineSourceCandidatePattern(pattern) {
const index = pattern.indexOf("{");
if (index === -1) return [pattern];
const prefix = pattern.slice(0, index);
const rest = pattern.slice(index);
let depth = 0;
let endIndex = -1;
for (let index = 0; index < rest.length; index++) {
const char = rest[index];
if (char === "{") depth += 1;
else if (char === "}") {
depth -= 1;
if (depth === 0) {
endIndex = index;
break;
}
}
}
if (endIndex === -1) return [pattern];
const inner = rest.slice(1, endIndex);
const suffix = rest.slice(endIndex + 1);
const parts = (isSequence(inner) ? expandSequence(inner) : segmentTopLevel(inner, ",", { keepEmpty: true })).flatMap((part) => expandInlineSourceCandidatePattern(part));
return expandInlineSourceCandidatePattern(suffix).flatMap((suffix) => parts.map((part) => `${prefix}${part}${suffix}`));
}
function parseSourceInlineParam(params) {
let value = params.trim();
const negated = value.startsWith("not ");
if (negated) value = value.slice(4).trim();
if (!value.startsWith("inline(") || !value.endsWith(")")) return;
const inlineValue = value.slice(7, -1).trim();
const match = /^(['"])([\s\S]*)\1$/.exec(inlineValue);
if (!match) return;
const source = match[2];
if (source === void 0) return;
return {
negated,
source
};
}
function collectCssInlineSourceCandidates(root) {
const included = /* @__PURE__ */ new Set();
const excluded = /* @__PURE__ */ new Set();
root.walkAtRules("source", (rule) => {
const parsed = parseSourceInlineParam(rule.params);
if (!parsed) return;
const target = parsed.negated ? excluded : included;
for (const source of segmentTopLevel(parsed.source, " ")) {
const trimmed = source.trim();
if (!trimmed) continue;
for (const candidate of expandInlineSourceCandidatePattern(trimmed)) {
const normalized = candidate.trim();
if (normalized) target.add(normalized);
}
}
});
for (const candidate of excluded) included.delete(candidate);
return {
included,
excluded
};
}
//#endregion
//#region src/tailwindcss/v4/preflight.ts
function parseCssImportSpecifier(params) {
const value = params.trim();
const quoted = /^(['"])(.*?)\1/.exec(value);
if (quoted) return quoted[2];
const url = /^url\(\s*(?:(['"])(.*?)\1|([^'")\s]+))\s*\)/.exec(value);
return url?.[2] ?? url?.[3];
}
function normalizeTailwindImportSpecifier(params) {
return parseCssImportSpecifier(params)?.replaceAll("\\", "/");
}
function isTailwindV4CssImportParam(params) {
const specifier = normalizeTailwindImportSpecifier(params);
return specifier === "tailwindcss" || specifier === "tailwindcss4" || specifier?.startsWith("tailwindcss/") === true || specifier?.startsWith("tailwindcss4/") === true || specifier?.endsWith("/tailwindcss/index.css") === true;
}
function isTailwindV4PreflightImportParam(params) {
const specifier = normalizeTailwindImportSpecifier(params);
return specifier === "tailwindcss" || specifier === "tailwindcss4" || specifier === "tailwindcss/preflight" || specifier === "tailwindcss/preflight.css" || specifier === "tailwindcss4/preflight" || specifier === "tailwindcss4/preflight.css" || specifier?.endsWith("/tailwindcss/index.css") === true || specifier?.endsWith("/tailwindcss/preflight.css") === true;
}
function includesTailwindV4PreflightDirective(css) {
try {
const root = postcss.parse(css);
let includesPreflight = false;
root.walkAtRules("import", (rule) => {
includesPreflight || (includesPreflight = isTailwindV4PreflightImportParam(rule.params));
});
root.walkAtRules("tailwind", (rule) => {
includesPreflight || (includesPreflight = rule.params.trim() === "base");
});
return includesPreflight;
} catch {
return /@import\s+(?:url\(\s*)?["']?tailwindcss4?(?:\/(?:preflight(?:\.css)?|index\.css))?["')\s;]/.test(css) || /@tailwind\s+base\b/.test(css);
}
}
//#endregion
//#region src/bundlers/shared/static-config-content.ts
function skipWhitespaceAndComments(source, start) {
let index = start;
while (index < source.length) {
const char = source[index];
if (/\s/.test(char ?? "")) {
index += 1;
continue;
}
if (char === "/" && source[index + 1] === "/") {
index += 2;
while (index < source.length && source[index] !== "\n") index += 1;
continue;
}
if (char === "/" && source[index + 1] === "*") {
index += 2;
while (index < source.length && !(source[index] === "*" && source[index + 1] === "/")) index += 1;
index = Math.min(index + 2, source.length);
continue;
}
break;
}
return index;
}
function readQuotedString(source, start) {
const quote = source[start];
if (quote !== "\"" && quote !== "'") return;
let value = "";
for (let index = start + 1; index < source.length; index++) {
const char = source[index];
if (char === "\\") {
const next = source[index + 1];
if (next === void 0) return;
value += next;
index += 1;
continue;
}
if (char === quote) return {
end: index + 1,
value
};
value += char;
}
}
function readIdentifier(source, start) {
return /^[A-Z_$][\w$]*/i.exec(source.slice(start))?.[0];
}
function findMatchingBracket(source, start, open, close) {
let depth = 0;
let quote;
for (let index = start; index < source.length; index++) {
const char = source[index];
if (char === "\\") {
index += 1;
continue;
}
if (quote) {
if (char === quote) quote = void 0;
continue;
}
if (char === "\"" || char === "'") {
quote = char;
continue;
}
if (char === "`") return;
if (char === open) {
depth += 1;
continue;
}
if (char === close) {
depth -= 1;
if (depth === 0) return index;
}
}
}
function findContentPropertyValue(source) {
let index = 0;
while (index < source.length) {
const nextIndex = source.indexOf("content", index);
if (nextIndex === -1) return;
const previous = source[nextIndex - 1];
const next = source[nextIndex + 7];
if (previous && /[\w$]/.test(previous) || next && /[\w$]/.test(next)) {
index = nextIndex + 7;
continue;
}
let colonIndex = skipWhitespaceAndComments(source, nextIndex + 7);
if (source[colonIndex] !== ":") {
index = nextIndex + 7;
continue;
}
colonIndex = skipWhitespaceAndComments(source, colonIndex + 1);
return { start: colonIndex };
}
}
function parseStaticContentArray(source, start) {
if (source[start] !== "[") return;
const value = [];
let index = skipWhitespaceAndComments(source, start + 1);
while (index < source.length) {
if (source[index] === "]") return {
end: index + 1,
value
};
const parsed = parseStaticContentValue(source, index);
if (!parsed) return;
value.push(parsed.value);
index = skipWhitespaceAndComments(source, parsed.end);
if (source[index] === ",") {
index = skipWhitespaceAndComments(source, index + 1);
continue;
}
if (source[index] === "]") continue;
return;
}
}
function parseStaticContentObject(source, start) {
if (source[start] !== "{") return;
const end = findMatchingBracket(source, start, "{", "}");
if (end === void 0) return;
let index = skipWhitespaceAndComments(source, start + 1);
let files;
while (index < end) {
let key;
const quotedKey = readQuotedString(source, index);
if (quotedKey) {
key = quotedKey.value;
index = quotedKey.end;
} else {
key = readIdentifier(source, index);
if (!key) return;
index += key.length;
}
index = skipWhitespaceAndComments(source, index);
if (source[index] !== ":") return;
index = skipWhitespaceAndComments(source, index + 1);
const parsedValue = parseStaticContentValue(source, index);
if (!parsedValue) return;
if (key === "files") files = parsedValue.value;
index = skipWhitespaceAndComments(source, parsedValue.end);
if (source[index] === ",") {
index = skipWhitespaceAndComments(source, index + 1);
continue;
}
if (index < end) return;
}
return files === void 0 ? void 0 : {
end: end + 1,
value: { files }
};
}
function parseStaticContentValue(source, start) {
const index = skipWhitespaceAndComments(source, start);
const quoted = readQuotedString(source, index);
if (quoted) return quoted;
if (source[index] === "[") return parseStaticContentArray(source, index);
if (source[index] === "{") return parseStaticContentObject(source, index);
}
function readStaticConfigContent(configPath) {
let source;
try {
source = readFileSync(configPath, "utf8");
} catch {
return;
}
const contentProperty = findContentPropertyValue(source);
if (!contentProperty) return;
return parseStaticContentValue(source, contentProperty.start)?.value;
}
//#endregion
//#region src/bundlers/shared/source-scan/css-entries.ts
const SOURCE_CANDIDATE_PATTERN = FULL_SOURCE_SCAN_PATTERN;
const TAILWIND_CSS_ENTRY_PATTERN = "**/*.css";
const tailwindV4CssEntriesCache = /* @__PURE__ */ new Map();
function parseImportSourceParam(params) {
const match = /\bsource\(\s*(none|(['"])(.*?)\2)\s*\)/.exec(params);
if (!match) return;
return {
none: match[1] === "none",
sourcePath: match[3]
};
}
function resolveSourceBase(base, sourcePath) {
return path.isAbsolute(sourcePath) ? sourcePath : path.resolve(base, sourcePath);
}
function resolveConfigPath(base, configPath) {
if (path.isAbsolute(configPath)) return path.resolve(configPath);
return path.resolve(base, configPath);
}
function createCssEntriesCacheKey(css, base, dependencies) {
return JSON.stringify({
base: path.resolve(base),
css,
dependencies
});
}
async function statConfigDependency(file) {
try {
const stats = await stat(file);
return {
file,
mtimeMs: stats.mtimeMs,
size: stats.size
};
} catch {
return {
file,
mtimeMs: -1,
size: -1
};
}
}
async function collectConfigDependencySignatures(root, base) {
const configPaths = /* @__PURE__ */ new Set();
root.walkAtRules("config", (rule) => {
const configPath = parseConfigParam(rule.params);
if (configPath) configPaths.add(resolveConfigPath(base, configPath));
});
return Promise.all([...configPaths].sort().map(statConfigDependency));
}
function mergeTailwindInlineSourceCandidates(allInlineCandidates) {
const merged = {
included: /* @__PURE__ */ new Set(),
excluded: /* @__PURE__ */ new Set()
};
for (const inlineCandidates of allInlineCandidates) {
if (!inlineCandidates) continue;
for (const candidate of inlineCandidates.included) if (!merged.excluded.has(candidate)) merged.included.add(candidate);
for (const candidate of inlineCandidates.excluded) {
merged.excluded.add(candidate);
merged.included.delete(candidate);
}
}
return merged.included.size > 0 || merged.excluded.size > 0 ? merged : void 0;
}
async function resolveConfigContentEntries(root, base) {
const configPaths = /* @__PURE__ */ new Set();
root.walkAtRules("config", (rule) => {
const configPath = parseConfigParam(rule.params);
if (configPath) configPaths.add(resolveConfigPath(base, configPath));
});
const entries = [];
for (const configPath of configPaths) {
const staticContent = readStaticConfigContent(configPath);
if (staticContent !== void 0) {
entries.push(...normalizeLegacyContentEntries(staticContent, path.dirname(configPath), { relativeBase: path.dirname(configPath) }));
continue;
}
try {
const loaded = await loadConfig({
config: configPath,
cwd: path.dirname(configPath)
});
entries.push(...normalizeLegacyContentEntries(loaded?.config.content, path.dirname(configPath), { relativeBase: path.dirname(configPath) }));
} catch {}
}
return {
dependencies: [...configPaths],
entries
};
}
async function resolveTailwindV4EntriesFromCss(css, base) {
let root;
try {
root = postcss.parse(css);
} catch {
return;
}
let importSourceBase;
let hasSourceNone = false;
let hasTailwindCssImport = false;
let includesPreflight = false;
const [sourceEntries, configEntries] = await Promise.all([resolveCssSourceEntries(root, base, SOURCE_CANDIDATE_PATTERN), resolveConfigContentEntries(root, base)]);
const entries = [...configEntries.entries, ...sourceEntries];
const hasPositiveEntries = entries.some((entry) => !entry.negated);
const inlineCandidates = collectCssInlineSourceCandidates(root);
root.walkAtRules("import", (rule) => {
if (!isTailwindV4CssImportParam(rule.params)) return;
hasTailwindCssImport = true;
includesPreflight || (includesPreflight = isTailwindV4PreflightImportParam(rule.params));
const sourceParam = parseImportSourceParam(rule.params);
if (sourceParam?.none) hasSourceNone = true;
if (sourceParam?.sourcePath) importSourceBase = resolveSourceBase(base, sourceParam.sourcePath);
});
root.walkAtRules("tailwind", (rule) => {
includesPreflight || (includesPreflight = rule.params.trim() === "base");
});
if (importSourceBase) return {
entries: [{
base: importSourceBase,
negated: false,
pattern: SOURCE_CANDIDATE_PATTERN
}, ...entries],
explicit: true,
includesPreflight,
inlineCandidates,
dependencies: configEntries.dependencies
};
if (hasSourceNone) return {
entries,
explicit: true,
includesPreflight,
inlineCandidates,
dependencies: configEntries.dependencies
};
if (hasPositiveEntries) return {
entries,
explicit: true,
includesPreflight,
inlineCandidates,
dependencies: configEntries.dependencies
};
if (inlineCandidates.included.size > 0 || inlineCandidates.excluded.size > 0) return {
entries: [],
explicit: true,
includesPreflight,
inlineCandidates,
dependencies: configEntries.dependencies
};
return hasTailwindCssImport ? {
entries,
explicit: false,
includesPreflight,
inlineCandidates,
dependencies: configEntries.dependencies
} : void 0;
}
async function resolveTailwindV4CssDependencies(css, base) {
return (await resolveTailwindV4EntriesFromCss(css, base))?.dependencies ?? [];
}
function collectExistingCssEntries(options) {
return [
...options.cssEntries ?? [],
...options.tailwindcss?.v4?.cssEntries ?? [],
...options.tailwindcssRuntimeOptions?.tailwindcss?.v4?.cssEntries ?? []
].filter((item) => typeof item === "string" && item.length > 0).filter(isTailwindV4CssEntry).map((item) => path.resolve(item)).filter((item) => existsSync(item));
}
async function pathExistsAsFile(file) {
try {
return (await stat(file)).isFile();
} catch {
return false;
}
}
async function resolveTailwindV4EntriesFromCssCached(css, base) {
let root;
try {
root = postcss.parse(css);
} catch {
return;
}
const cacheKey = createCssEntriesCacheKey(css, base, await collectConfigDependencySignatures(root, base));
const cached = tailwindV4CssEntriesCache.get(cacheKey);
if (cached) return cached;
const task = resolveTailwindV4EntriesFromCss(css, base).catch((error) => {
tailwindV4CssEntriesCache.delete(cacheKey);
throw error;
});
tailwindV4CssEntriesCache.set(cacheKey, task);
return task;
}
async function discoverTailwindV4CssEntries(root, outDir) {
const resolvedRoot = path.resolve(root);
const ignore = ["**/node_modules/**", "**/.git/**"];
const resolvedOutDir = outDir ? path.resolve(resolvedRoot, outDir) : void 0;
if (resolvedOutDir) {
const relativeOutDir = path.relative(resolvedRoot, resolvedOutDir);
if (relativeOutDir && !relativeOutDir.startsWith("..") && !path.isAbsolute(relativeOutDir)) ignore.push(`${relativeOutDir.split(path.sep).join("/")}/**`);
}
const candidates = await fg(TAILWIND_CSS_ENTRY_PATTERN, {
absolute: true,
cwd: resolvedRoot,
ignore,
onlyFiles: true,
unique: true
});
const entries = [];
for (const file of candidates) {
if (!await pathExistsAsFile(file)) continue;
try {
const css = readFileSync(file, "utf8");
if (css.includes("tailwindcss") || css.includes("@source") || css.includes("@config")) {
if (await resolveTailwindV4EntriesFromCssCached(css, path.dirname(file))) entries.push(file);
}
} catch {}
}
return entries;
}
function collectConfiguredCssSources(options) {
return filterTailwindV4CssSourceRoots([...options.tailwindcss?.v4?.cssSources ?? [], ...options.tailwindcssRuntimeOptions?.tailwindcss?.v4?.cssSources ?? []]) ?? [];
}
//#endregion
//#region src/bundlers/shared/source-scan/dependencies.ts
function addSourceScanDependency(dependencies, file) {
if (typeof file === "string" && file.length > 0) dependencies.add(path.resolve(file));
}
function addSourceScanDependencies(dependencies, files) {
for (const file of files ?? []) addSourceScanDependency(dependencies, file);
}
//#endregion
//#region src/bundlers/shared/source-scan.ts
function createResolvedSourceScan(input, dependencies) {
return {
...input,
...dependencies.size > 0 ? { dependencies: [...dependencies].sort() } : {}
};
}
function createMergedCssEntrySourceScanEntries(entries, options) {
if (options.sourceCount <= 1) return entries;
const positiveEntries = entries.filter((entry) => !entry.negated);
return positiveEntries.length > 0 ? positiveEntries : entries;
}
function resolveExplicitSourceScanEntries(entries, explicit) {
if (!explicit) return entries.length > 0 ? entries : void 0;
return entries.some((entry) => !entry.negated) ? entries : [];
}
function createResolvedV4CssScanInput(entries, inlineCandidates, explicit) {
return {
entries: resolveExplicitSourceScanEntries(entries, explicit),
explicit,
inlineCandidates
};
}
async function resolveSourceScanEntries(options, runtime, scanOptions = {}) {
const sourceOptions = resolveTailwindV4SourceOptionsFromRuntime(runtime);
const cssEntries = collectExistingCssEntries(options);
if (cssEntries.length === 0 && !sourceOptions.css && !sourceOptions.cssSources?.length) {
const scanRoot = scanOptions.root;
const sourceProjectRoot = sourceOptions.projectRoot;
if (scanRoot && sourceProjectRoot && path.resolve(scanRoot) === path.resolve(sourceProjectRoot)) {
const discoveredCssEntries = await discoverTailwindV4CssEntries(scanRoot, scanOptions.outDir);
cssEntries.push(...discoveredCssEntries);
}
}
const entries = [];
const cssInlineCandidates = [];
const dependencies = /* @__PURE__ */ new Set();
let explicit = false;
let readableCssEntryCount = 0;
for (const cssEntry of cssEntries) {
addSourceScanDependency(dependencies, cssEntry);
let css;
try {
css = readFileSync(cssEntry, "utf8");
} catch {
continue;
}
readableCssEntryCount++;
const resolved = await resolveTailwindV4EntriesFromCssCached(css, path.dirname(cssEntry));
if (resolved) {
entries.push(...resolved.entries);
cssInlineCandidates.push(resolved.inlineCandidates);
addSourceScanDependencies(dependencies, resolved.dependencies);
explicit || (explicit = resolved.explicit);
}
}
const inlineCandidates = mergeTailwindInlineSourceCandidates(cssInlineCandidates);
const scanEntries = createMergedCssEntrySourceScanEntries(entries, { sourceCount: readableCssEntryCount });
if (scanEntries.length > 0 || inlineCandidates || explicit || readableCssEntryCount > 0) return createResolvedSourceScan({
entries: resolveExplicitSourceScanEntries(scanEntries, explicit),
explicit,
inlineCandidates
}, dependencies);
if (typeof sourceOptions.css === "string" && sourceOptions.css.length > 0) {
const resolved = await resolveTailwindV4EntriesFromCssCached(sourceOptions.css, sourceOptions.base ?? sourceOptions.projectRoot ?? process.cwd());
return resolved ? createResolvedSourceScan(createResolvedV4CssScanInput(resolved.entries, resolved.inlineCandidates, resolved.explicit), new Set(resolved.dependencies)) : void 0;
}
const sourceOptionBase = sourceOptions.base ?? sourceOptions.projectRoot ?? process.cwd();
const configuredCssSources = collectConfiguredCssSources(options);
for (const cssSource of [...configuredCssSources, ...sourceOptions.cssSources ?? []]) {
if (typeof cssSource.css !== "string" || cssSource.css.length === 0) continue;
addSourceScanDependency(dependencies, cssSource.file);
addSourceScanDependencies(dependencies, cssSource.dependencies);
const resolved = await resolveTailwindV4EntriesFromCssCached(cssSource.css, resolveTailwindV4CssSourceBase(cssSource, sourceOptionBase));
if (resolved) {
entries.push(...resolved.entries);
cssInlineCandidates.push(resolved.inlineCandidates);
addSourceScanDependencies(dependencies, resolved.dependencies);
explicit || (explicit = resolved.explicit);
}
}
const cssSourceInlineCandidates = mergeTailwindInlineSourceCandidates(cssInlineCandidates);
const cssSourceCount = (sourceOptions.cssSources?.length ?? 0) + configuredCssSources.length;
const cssSourceScanEntries = createMergedCssEntrySourceScanEntries(entries, { sourceCount: cssSourceCount });
if (cssSourceScanEntries.length > 0 || cssSourceInlineCandidates || explicit) return createResolvedSourceScan({
entries: resolveExplicitSourceScanEntries(cssSourceScanEntries, explicit),
explicit,
inlineCandidates: cssSourceInlineCandidates
}, dependencies);
if (cssSourceCount > 0) return;
const source = await resolveTailwindV4SourceFromRuntime(runtime);
addSourceScanDependency(dependencies, source.file);
addSourceScanDependencies(dependencies, source.dependencies);
const resolved = await resolveTailwindV4EntriesFromCssCached(source.css, source.base);
return resolved ? createResolvedSourceScan(createResolvedV4CssScanInput(resolved.entries.length > 0 ? resolved.entries : [], resolved.inlineCandidates, resolved.entries.length > 0 ? resolved.explicit : false), /* @__PURE__ */ new Set([...dependencies, ...resolved.dependencies])) : void 0;
}
function createSourceScanMatcher(entries) {
if (entries?.length === 0) return () => false;
return createTailwindSourceEntryMatcher(entries);
}
//#endregion
//#region src/tailwindcss/runtime/cache.ts
const runtimeClassSetCache = /* @__PURE__ */ new WeakMap();
const runtimeFileSignatureCache = /* @__PURE__ */ new Map();
const runtimeTrackedSourceFilesCache = /* @__PURE__ */ new Map();
let runtimeFileSignatureCacheClearTimer;
const runtimeSignatureRuntimesSymbol = Symbol.for("weapp-tailwindcss.runtimeSignatureRuntimes");
function getCacheEntry(tailwindRuntime) {
let entry = runtimeClassSetCache.get(tailwindRuntime);
if (!entry) {
entry = {};
runtimeClassSetCache.set(tailwindRuntime, entry);
}
return entry;
}
function scheduleRuntimeConfigSignatureCacheClear() {
if (runtimeFileSignatureCacheClearTimer) return;
runtimeFileSignatureCacheClearTimer = setTimeout(() => {
runtimeFileSignatureCache.clear();
runtimeTrackedSourceFilesCache.clear();
runtimeFileSignatureCacheClearTimer = void 0;
}, 0);
runtimeFileSignatureCacheClearTimer.unref?.();
}
function getFileSignature(filePath) {
const cached = runtimeFileSignatureCache.get(filePath);
if (cached !== void 0) return cached;
let signature;
try {
const stats = statSync(filePath);
signature = `${filePath}:${stats.size}:${stats.mtimeMs}`;
} catch {
signature = `${filePath}:missing`;
}
runtimeFileSignatureCache.set(filePath, signature);
scheduleRuntimeConfigSignatureCacheClear();
return signature;
}
function getTailwindTrackedFiles(tailwindRuntime) {
const tailwindOptions = resolveTailwindcssOptions(tailwindRuntime.options);
const tracked = /* @__PURE__ */ new Set();
const configPath = tailwindOptions?.config;
if (typeof configPath === "string" && configPath.length > 0) tracked.add(configPath);
for (const entry of tailwindOptions?.v4?.cssEntries ?? []) if (typeof entry === "string" && entry.length > 0) tracked.add(entry);
for (const source of tailwindOptions?.v4?.cssSources ?? []) {
if (typeof source.file === "string" && source.file.length > 0) tracked.add(source.file);
for (const dependency of source.dependencies ?? []) if (typeof dependency === "string" && dependency.length > 0) tracked.add(dependency);
}
return tracked;
}
function normalizeTrackedSourceSignature(cssEntries, cssSources) {
return normalizeSignatureValue({
cssEntries: cssEntries?.map((entry) => {
if (!existsSync(entry)) return `${entry}:missing`;
return getFileSignature(entry);
}),
cssSources
});
}
async function collectTailwindV4TrackedSourceFiles(tailwindRuntime) {
const tailwindOptions = resolveTailwindcssOptions(tailwindRuntime.options);
const signature = normalizeTrackedSourceSignature(tailwindOptions?.v4?.cssEntries, tailwindOptions?.v4?.cssSources);
const cached = runtimeTrackedSourceFilesCache.get(signature);
if (cached) return cached;
const files = /* @__PURE__ */ new Set();
for (const cssEntry of tailwindOptions?.v4?.cssEntries ?? []) {
if (!existsSync(cssEntry)) continue;
const resolved = await resolveTailwindV4EntriesFromCssCached(readFileSync(cssEntry, "utf8"), path.dirname(cssEntry));
const expanded = resolved?.entries?.length ? await expandTailwindSourceEntries(resolved.entries) : [];
for (const file of expanded) files.add(file);
}
for (const cssSource of tailwindOptions?.v4?.cssSources ?? []) {
if (typeof cssSource.css !== "string" || cssSource.css.length === 0) continue;
const base = typeof cssSource.file === "string" && cssSource.file.length > 0 ? path.dirname(cssSource.file) : tailwindOptions?.v4?.base ?? tailwindOptions?.cwd ?? tailwindRuntime.options?.projectRoot ?? process.cwd();
const resolved = await resolveTailwindV4EntriesFromCssCached(cssSource.css, base);
const expanded = resolved?.entries?.length ? await expandTailwindSourceEntries(resolved.entries) : [];
for (const file of expanded) files.add(file);
}
const result = [...files].sort((a, b) => a.localeCompare(b));
runtimeTrackedSourceFilesCache.set(signature, result);
return result;
}
function normalizeSignatureValue(value) {
if (value == null) return "null";
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean") return String(value);
if (Array.isArray(value)) return `[${value.map((item) => normalizeSignatureValue(item)).join(",")}]`;
if (typeof value === "object") return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${key}:${normalizeSignatureValue(item)}`).join(",")}}`;
return String(value);
}
function readOptionalProperty(value, key) {
if (typeof value !== "object" || value === null || !(key in value)) return;
return value[key];
}
function getTailwindOptionsSignature(tailwindRuntime) {
const options = tailwindRuntime.options;
const tailwindOptions = resolveTailwindcssOptions(options);
return normalizeSignatureValue({
projectRoot: options?.projectRoot,
packageName: tailwindOptions?.packageName,
versionHint: readOptionalProperty(tailwindOptions, "versionHint"),
cwd: tailwindOptions?.cwd,
config: tailwindOptions?.config,
v4: {
base: tailwindOptions?.v4?.base,
configuredBase: readOptionalProperty(tailwindOptions?.v4, "configuredBase"),
css: tailwindOptions?.v4?.css,
cssEntries: tailwindOptions?.v4?.cssEntries,
cssSources: tailwindOptions?.v4?.cssSources,
hasUserDefinedSources: readOptionalProperty(tailwindOptions?.v4, "hasUserDefinedSources"),
sources: tailwindOptions?.v4?.sources
}
});
}
function getRuntimeTargetSignature(tailwindRuntime) {
const packageInfo = tailwindRuntime.packageInfo;
return [
packageInfo?.name ?? "missing",
packageInfo?.rootPath ?? "missing",
packageInfo?.version ?? "unknown",
tailwindRuntime.majorVersion ?? "unknown",
getTailwindOptionsSignature(tailwindRuntime)
].join(":");
}
function getNestedRuntimes(tailwindRuntime) {
const nested = tailwindRuntime[runtimeSignatureRuntimesSymbol];
return Array.isArray(nested) && nested.length > 0 ? nested : void 0;
}
function getOwnRuntimeClassSetSignature(tailwindRuntime) {
const trackedFiles = [...getTailwindTrackedFiles(tailwindRuntime)].sort((a, b) => a.localeCompare(b)).map(getFileSignature);
return `${trackedFiles.length > 0 ? trackedFiles.join("|") : "files:missing"}|runtime:${getRuntimeTargetSignature(tailwindRuntime)}`;
}
function invalidateRuntimeClassSet(tailwindRuntime) {
if (!tailwindRuntime) return;
const nestedRuntimes = getNestedRuntimes(tailwindRuntime);
if (nestedRuntimes) for (const runtime of nestedRuntimes) invalidateRuntimeClassSet(runtime);
for (const trackedFile of getTailwindTrackedFiles(tailwindRuntime)) runtimeFileSignatureCache.delete(trackedFile);
runtimeTrackedSourceFilesCache.clear();
runtimeClassSetCache.delete(tailwindRuntime);
}
function getRuntimeClassSetCacheEntry(tailwindRuntime) {
return getCacheEntry(tailwindRuntime);
}
function getRuntimeClassSetSignature(tailwindRuntime) {
const nestedRuntimes = getNestedRuntimes(tailwindRuntime);
if (nestedRuntimes) return nestedRuntimes.map(getOwnRuntimeClassSetSignature).sort((a, b) => a.localeCompare(b)).join("||");
return getOwnRuntimeClassSetSignature(tailwindRuntime);
}
async function getRuntimeClassSetSignatureWithSources(tailwindRuntime) {
const baseSignature = getRuntimeClassSetSignature(tailwindRuntime);
const trackedSourceFiles = await collectTailwindV4TrackedSourceFiles(tailwindRuntime);
if (trackedSourceFiles.length === 0) return baseSignature;
return [baseSignature, trackedSourceFiles.map(getFileSignature).join("|")].join("|sources:");
}
//#endregion
//#region src/tailwindcss/v4/config.ts
const DEFAULT_CSS_CALC_CUSTOM_PROPERTIES = [];
function includesToken(list, token) {
return list.some((candidate) => {
if (typeof token === "string") {
if (typeof candidate === "string") return candidate === token;
candidate.lastIndex = 0;
return candidate.test(token);
}
if (typeof candidate === "string") {
token.lastIndex = 0;
return token.test(candidate);
}
return candidate.source === token.source && candidate.flags === token.flags;
});
}
function ensureDefaultsIncluded(value) {
if (value === true) return { includeCustomProperties: [...DEFAULT_CSS_CALC_CUSTOM_PROPERTIES] };
if (Array.isArray(value)) {
if (!DEFAULT_CSS_CALC_CUSTOM_PROPERTIES.length) return value;
const missing = DEFAULT_CSS_CALC_CUSTOM_PROPERTIES.filter((token) => !includesToken(value, token));
return missing.length > 0 ? [...value, ...missing] : value;
}
if (value && typeof value === "object") {
const include = value.includeCustomProperties;
if (!Array.isArray(include)) return {
...value,
includeCustomProperties: [...DEFAULT_CSS_CALC_CUSTOM_PROPERTIES]
};
if (!DEFAULT_CSS_CALC_CUSTOM_PROPERTIES.length) return value;
const missing = DEFAULT_CSS_CALC_CUSTOM_PROPERTIES.filter((token) => !includesToken(include, token));
return missing.length > 0 ? {
...value,
includeCustomProperties: [...include, ...missing]
} : value;
}
return value;
}
function normalizeCssEntriesConfig(entries) {
const normalized = normalizeStringListOption(entries)?.filter(isTailwindV4CssEntry);
return normalized && normalized.length > 0 ? normalized : void 0;
}
function hasConfiguredCssEntries(ctx) {
if (normalizeCssEntriesConfig(ctx.cssEntries)) return true;
if (normalizeCssEntriesConfig(ctx.tailwindcss?.v4?.cssEntries)) return true;
const runtimeOptions = ctx.tailwindcssRuntimeOptions;
if (runtimeOptions) {
if (normalizeCssEntriesConfig(runtimeOptions.tailwindcss?.v4?.cssEntries)) return true;
}
return false;
}
let hasWarnedMissingCssEntries = false;
function warnMissingCssEntries(ctx, tailwindRuntime) {
if (hasWarnedMissingCssEntries) return;
if (!tailwindRuntime) return;
if (hasConfiguredCssEntries(ctx) || hasConfiguredTailwindV4CssRoots(ctx)) return;
hasWarnedMissingCssEntries = true;
logger.warn("[tailwindcss@4] 未检测到 cssEntries 配置。请传入包含 tailwindcss 引用的 CSS 绝对路径,例如 cssEntries: [\"/absolute/path/to/src/app.css\"],否则 tailwindcss 生成的类名不会参与转译。");
}
function applyV4CssCalcDefaults(cssCalc, tailwindRuntime) {
const cssCalcOptions = cssCalc ?? false;
if (tailwindRuntime && cssCalcOptions) return ensureDefaultsIncluded(cssCalcOptions);
return cssCalcOptions;
}
//#endregion
//#region src/tailwindcss/runtime-resolve.ts
const GENERIC_RELATIVE_SPECIFIERS = [".", ".."];
const DEFAULT_TAILWIND_CONFIG_SPECIFIERS = ["stubs/config.full.js", "defaultConfig.js"];
const TAILWIND_CONFIG_FILES = [
"tailwind.config.js",
"tailwind.config.cjs",
"tailwind.config.mjs",
"tailwind.config.ts",
"tailwind.config.cts",
"tailwind.config.mts"
];
function isPathSpecifier(specifier) {
if (!specifier) return false;
if (specifier.startsWith("file://")) return true;
if (path.isAbsolute(specifier)) return true;
return GENERIC_RELATIVE_SPECIFIERS.some((prefix) => specifier.startsWith(`${prefix}/`) || specifier.startsWith(`${prefix}\\`));
}
function resolveModuleFromPaths(specifier, paths) {
if (!specifier || isPathSpecifier(specifier) || paths.length === 0) return;
try {
return createRequire(import.meta.url).resolve(specifier, { paths });
} catch {
return;
}
}
function resolveTailwindConfigFallback(packageName, paths) {
if (!packageName) return;
for (const suffix of DEFAULT_TAILWIND_CONFIG_SPECIFIERS) {
const resolved = resolveModuleFromPaths(`${packageName}/${suffix}`, paths);
if (resolved) return resolved;
}
}
function appendNodeModules(paths, dir) {
if (!dir) return;
const nodeModulesDir = path.join(dir, "node_modules");
if (existsSync(nodeModulesDir)) paths.add(nodeModulesDir);
}
function findTailwindConfig(searchRoots) {
for (const root of searchRoots) for (const file of TAILWIND_CONFIG_FILES) {
const candidate = path.resolve(root, file);
if (existsSync(candidate)) return candidate;
}
}
function createDefaultResolvePaths(basedir) {
const paths = /* @__PURE__ */ new Set();
let fallbackCandidates = [];
if (basedir) {
const resolvedBase = path.resolve(basedir);
appendNodeModules(paths, resolvedBase);
fallbackCandidates.push(resolvedBase);
const packageRoot = findNearestPackageRoot(resolvedBase);
if (packageRoot) {
appendNodeModules(paths, packageRoot);
fallbackCandidates.push(packageRoot);
}
const workspaceRoot = findWorkspaceRoot(resolvedBase);
if (workspaceRoot) {
appendNodeModules(paths, workspaceRoot);
fallbackCandidates.push(workspaceRoot);
}
}
const cwd = process.cwd();
appendNodeModules(paths, cwd);
try {
const modulePath = fileURLToPath(import.meta.url);
const candidate = existsSync(modulePath) && !path.extname(modulePath) ? modulePath : path.dirname(modulePath);
paths.add(candidate);
} catch {
paths.add(import.meta.url);
}
if (paths.size === 0) {
fallbackCandidates = fallbackCandidates.filter(Boolean);
if (fallbackCandidates.length === 0) fallbackCandidates.push(cwd);
for (const candidate of fallbackCandidates) paths.add(candidate);
}
return [...paths];
}
//#endregion
//#region src/tailwindcss/version.ts
function normalizeSupportedTailwindcssMajorVersion(version) {
return version === 4 ? version : void 0;
}
function readPackageJson(packageJsonPath) {
try {
return JSON.parse(readFileSync(packageJsonPath, "utf8"));
} catch {
return;
}
}
function findPackageJsonDeclaringPackage(packageName, base) {
let current = path.resolve(base);
while (true) {
const pkgPath = path.join(current, "package.json");
if (existsSync(pkgPath)) {
const pkg = readPackageJson(pkgPath);
if (readDeclaredPackageVersion(packageName, pkg)) return pkgPath;
if (pkg?.name !== "weapp-tailwindcss") return;
}
const parent = path.dirname(current);
if (parent === current) return;
current = parent;
}
}
function readDeclaredPackageVersion(packageName, pkg) {
return pkg?.dependencies?.[packageName] ?? pkg?.devDependencies?.[packageName] ?? pkg?.peerDependencies?.[packageName] ?? pkg?.optionalDependencies?.[packageName];
}
function readDeclaredPackageMajorVersion(version) {
const match = version?.match(/(?:^|\D)(4)(?:\.|\b)/);
return normalizeSupportedTailwindcssMajorVersion(match ? Number(match[1]) : void 0);
}
function readInstalledPackageMajorVersion(packageName, base) {
const packageJsonPath = findPackageJsonDeclaringPackage(packageName, base);
if (!packageJsonPath) return;
const declaredVersion = readDeclaredPackageVersion(packageName, readPackageJson(packageJsonPath));
if (!declaredVersion) return;
try {
const pkg = createRequire(packageJsonPath)(`${packageName}/package.json`);
return normalizeSupportedTailwindcssMajorVersion(Number(pkg.version?.split(".")[0]));
} catch {
return readDeclaredPackageMajorVersion(declaredVersion);
}
}
//#endregion
//#region src/tailwindcss/runtime-factory.ts
const require = createRequire(import.meta.url);
function createPackageInfo(tailwindOptions) {
const packageName = tailwindOptions?.packageName ?? "tailwindcss";
const resolvePaths = tailwindOptions?.resolve?.paths;
let rootPath;
const cwdPackageJsonPath = tailwindOptions?.cwd ? path.join(tailwindOptions.cwd, "package.json") : void 0;
if (cwdPackageJsonPath) try {
if (require(cwdPackageJsonPath).name === packageName) rootPath = cwdPackageJsonPath;
} catch {}
rootPath ?? (rootPath = resolveModuleFromPaths(`${packageName}/package.json`, resolvePaths ?? []));
if (!rootPath) for (const resolvePath of [tailwindOptions?.cwd, ...resolvePaths ?? []]) {
if (!resolvePath) continue;
try {
rootPath = createRequire(path.join(resolvePath, "package.json")).resolve(`${packageName}/package.json`);
break;
} catch {}
}
if (rootPath) {
const packageJsonPath = rootPath;
const packageRoot = path.dirname(packageJsonPath);
try {
const packageJson = require(packageJsonPath);
return {
name: packageName,
version: packageJson.version,
rootPath: packageRoot,
packageJsonPath,
packageJson
};
} catch {
return {
name: packageName,
version: void 0,
rootPath: packageRoot,
packageJsonPath,
packageJson: {}
};
}
}
return {
name: packageName,
version: void 0,
rootPath: "",
packageJsonPath: "",
packageJson: {}
};
}
function resolveMajorVersion(tailwindOptions, packageInfo) {
if (tailwindOptions?.version === 4) return tailwindOptions.version;
if (packageInfo.version?.startsWith("4.")) return 4;
return 4;
}
function createFallbackTailwindcssRuntime(options) {
const packageInfo = createPackageInfo(options?.tailwindcss);
return {
packageInfo,
majorVersion: resolveMajorVersion(options?.tailwindcss, packageInfo),
options,
async getClassSet() {
return /* @__PURE__ */ new Set();
},
async extract(_options) {
return {
classList: [],
classSet: /* @__PURE__ */ new Set()
};
},
async collectContentTokens() {
return {
entries: [],
filesScanned: 0,
sources: [],
skippedFiles: []
};
}
};
}
function createEngineTailwindcssRuntime(options) {
const tailwindOptions = options.tailwindcss;
const packageInfo = createPackageInfo(tailwindOptions);
const majorVersion = resolveMajorVersion(tailwindOptions, packageInfo);
let classSetCache;
let runtime;
function applyClassSetFilter(classSet) {
if (typeof options.filter !== "function") return classSet;
return new Set([...classSet].filter((className) => options.filter?.(className) !== false));
}
function hasTailwindV4ApplyContext(css) {
if (!css.includes("@apply")) return false;
try {
const root = postcss.parse(css);
let hasContext = false;
root.walkAtRules((rule) => {
if (rule.name === "reference" || rule.name === "import" || rule.name === "tailwind" && rule.params.trim() === "utilities") hasContext = true;
});
return hasContext;
} catch {
return false;
}
}
async function collectClassSet() {
const report = await collectContentTokens();
const rawCandidates = new Set(report.entries.map((entry) => {
return typeof entry === "string" ? entry : entry.rawCandidate;
}).filter((entry) => typeof entry === "string" && entry.length > 0));
const source = resolveCssMacroTailwindV4Source(await resolveTailwindV4SourceFromRuntime(runtime));
const designSystem = await loadTailwindV4DesignSystem(source);
const candidates = new Set(resolveValidTailwindV4Candidates(designSystem, rawCandidates, { ...source.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: source.bareArbitraryValues } }));
await collectTailwindV4CssCandidates(candidates);
return applyClassSetFilter(candidates);
}
async function collectTailwindV4CssCandidates(candidates) {
const source = resolveCssMacroTailwindV4Source(await resolveTailwindV4SourceFromRuntime(runtime));
const cssList = [source.css, ...(source.cssSources ?? []).map((cssSource) => cssSource.css).filter((css) => typeof css === "string")];
for (const css of cssList) {
if (!hasTailwindV4ApplyContext(css)) continue;
try {
postcss.parse(css).walkAtRules("apply", (rule) => {
for (const candidate of rule.params.split(/\s+/)) {
const normalized = candidate.replace(/!important$/, "").trim();
if (normalized) candidates.add(normalized);
}
});
} catch {}
}
}
async function collectContentTokens() {
const source = resolveCssMacroTailwindV4Source(await resolveTailwindV4SourceFromRuntime(runtime));
const report = await extractProjectCandidatesWithPositions({
base: source.base,
baseFallbacks: source.baseFallbacks,
css: source.css,
cwd: source.projectRoot,
...source.sources === void 0 ? {} : { sources: source.sources }
});
return {
entries: report.entries,
filesScanned: report.filesScanned,
sources: source.sources ?? [],
skippedFiles: report.skippedFiles
};
}
async function extract(options) {
let classSet = await collectClassSet();
const filter = options?.removeUniversalSelector === true ? (className) => className !== "*" : void 0;
if (filter) classSet = new Set([...classSet].filter(filter));
if (typeof options?.write === "boolean") {}
classSetCache = classSet;
return {
classList: [...classSet],
classSet
};
}
runtime = {
packageInfo,
majorVersion,
options,
async getClassSet() {
return (await extract({ write: false })).classSet;
},
getClassSetSync() {
return classSetCache ?? /* @__PURE__ */ new Set();
},
extract,
collectContentTokens
};
return runtime;
}
let hasLoggedMissingTailwind = false;
const TAILWINDCSS_NOT_FOUND_RE = /tailwindcss not found/i;
const UNABLE_TO_LOCATE_TAILWINDCSS_RE = /unable to locate tailwind css package/i;
function createTailwindcssRuntime(options) {
const { basedir, cacheDir, supportCustomLengthUnits, tailwindcss, tailwindcssRuntimeOptions } = options || {};
const cache = {
enabled: true,
driver: "memory"
};
const normalizedBasedir = basedir ? path.resolve(basedir) : void 0;
const cacheRoot = findNearestPackageRoot(normalizedBasedir) ?? normalizedBasedir ?? process.cwd();
if (cacheDir) if (path.isAbsolute(cacheDir)) cache.dir = cacheDir;
else if (normalizedBasedir) cache.dir = path.resolve(normalizedBasedir, cacheDir);
else cache.dir = path.resolve(process.cwd(), cacheDir);
else cache.dir = path.join(cacheRoot, "node_modules", ".cache", "@tailwindcss-mangle", "engine");
if (normalizedBasedir) cache.cwd = normalizedBasedir;
const resolvePaths = createDefaultResolvePaths(cache.cwd ?? normalizedBasedir ?? process.cwd());
const normalizedUserOptions = normalizeTailwindcssRuntimeOptions(tailwindcssRuntimeOptions);
const extendLengthUnits = normalizeExtendLengthUnits(supportCustomLengthUnits ?? true);
const baseTailwindOptions = defuOverrideArray(tailwindcss ?? {}, omitUndefined({
cwd: normalizedBasedir,
resolve: { paths: resolvePaths }
}));
baseTailwindOptions.packageName = tailwindcss?.packageName ?? normalizedUserOptions?.tailwindcss?.packageName ?? baseTailwindOptions.packageName ?? "tailwindcss";
if (!baseTailwindOptions.postcssPlugin) baseTailwindOptions.postcssPlugin = "tailwindcss";
if (typeof baseTailwindOptions.postcssPlugin === "string") {
const resolvedPlugin = resolveModuleFromPaths(baseTailwindOptions.postcssPlugin, resolvePaths);
if (resolvedPlugin) baseTailwindOptions.postcssPlugin = resolvedPlugin;
}
const baseOptions = omitUndefined({
projectRoot: normalizedBasedir,
cache,
tailwindcss: baseTailwindOptions,
apply: omitUndefined({
exposeContext: true,
extendLengthUnits
})
});
const resolvedOptions = defuOverrideArray(normalizedUserOptions ?? {}, baseOptions);
const resolvedTailwindOptions = resolvedOptions.tailwindcss;
if (resolvedTailwindOptions) {
const existingResolve = resolvedTailwindOptions.resolve ?? {};
const sourcePaths = Array.isArray(existingResolve.paths) && existingResolve.paths.length > 0 ? [...existingResolve.paths ?? [], ...resolvePaths] : resolvePaths;
resolvedTailwindOptions.resolve = {
...existingResolve,
paths: [...new Set(sourcePaths)]
};
logger.debug("Tailwind resolve config %O", {
packageName: resolvedTailwindOptions.packageName,
version: resolvedTailwindOptions.version,
resolve: resolvedTailwindOptions.resolve,
cwd: resolvedTailwindOptions.cwd
});
if (typeof resolvedTailwindOptions.postcssPlugin === "string") {
const resolvedPlugin = resolveModuleFromPaths(resolvedTailwindOptions.postcssPlugin, resolvedTailwindOptions.resolve?.paths ?? resolvePaths);
if (resolvedPlugin) resolvedTailwindOptions.postcssPlugin = resolvedPlugin;
}
const searchRoots = /* @__PURE__ */ new Set();
if (resolvedTailwindOptions.cwd) searchRoots.add(resolvedTailwindOptions.cwd);
for (const resolvePath of resolvedTailwindOptions.resolve?.paths ?? []) {
const parentDir = path.dirname(resolvePath);
searchRoots.add(parentDir);
}
const configPath = findTailwindConfig(searchRoots);
if (!resolvedTailwindOptions.config) if (configPath) resolvedTailwindOptions.config = configPath;
else {
const fallbackConfig = resolveTailwindConfigFallback(resolvedTailwindOptions.packageName, resolvedTailwindOptions.resolve.paths ?? resolvePaths);
if (fallbackConfig) resolvedTailwindOptions.config = fallbackConfig;
}
if (!resolvedTailwindOptions.cwd && configPath) resolvedTailwindOptions.cwd = path.dirname(configPath);
resolvedOptions.tailwindcss = resolvedTailwindOptions;
}
try {
return createEngineTailwindcssRuntime(resolvedOptions);
} catch (error) {
const searchPaths = resolvedOptions.tailwindcss?.resolve?.paths;
if (error instanceof Error && TAILWINDCSS_NOT_FOUND_RE.test(error.message)) {
if (!hasLoggedMissingTailwind) {
logger.warn("Tailwind CSS 未安装,已跳过 Tailwind 运行时能力。若需使用 Tailwind 能力,请安装 tailwindcss。");
hasLoggedMissingTailwind = true;
}
return createFallbackTailwindcssRuntime(resolvedOptions);
}
if (error instanceof Error && UNABLE_TO_LOCATE_TAILWINDCSS_RE.test(error.message)) logger.error("无法定位 Tailwind CSS 包 \"%s\",已尝试路径: %O", resolvedOptions.tailwindcss?.packageName, searchPaths);
throw error;
}
}
//#endregion
//#region src/tailwindcss/v4/multi-runtime.ts
function createMultiTailwindcssRuntime(runtimes) {
if (ru