@weapp-vite/tailwindcss 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +8 -2
- package/dist/index.mjs +167 -8
- package/package.json +9 -4
package/dist/index.d.mts
CHANGED
|
@@ -22,6 +22,10 @@ export declare function createTailwindController(options?: TailwindControllerOpt
|
|
|
22
22
|
/** 同一份 core 快照用于所有转换;宿主提供最终资产,公共层不推断框架输出归属。 */
|
|
23
23
|
export declare function createTailwindPreparation(compiler: Compiler$1, snapshot: CompilerSnapshot$1, assets?: NonNullable<HmrCompilerPreparation['assets']>): HmrCompilerPreparation;
|
|
24
24
|
//#endregion
|
|
25
|
+
//#region src/generationValue.d.ts
|
|
26
|
+
/** 只复制可比较的生成配置;保留函数身份、属性描述与原型,拒绝不可安全封存的输入。 */
|
|
27
|
+
export declare function copyTailwindGenerationValue<T>(value: T, parents?: Set<object>): T;
|
|
28
|
+
//#endregion
|
|
25
29
|
//#region src/output.d.ts
|
|
26
30
|
export interface TailwindOutputInput {
|
|
27
31
|
id: string;
|
|
@@ -45,14 +49,16 @@ export interface TailwindRootState {
|
|
|
45
49
|
result: CompilerGenerateResult$1;
|
|
46
50
|
rawSources: ReadonlyMap<string, string | null | undefined>;
|
|
47
51
|
}
|
|
48
|
-
export interface TailwindRootHost {
|
|
52
|
+
export interface TailwindRootHost<K = unknown> {
|
|
49
53
|
cwd: string;
|
|
50
54
|
sourceId: (file: string) => string;
|
|
51
55
|
isOutput?: (file: string) => boolean;
|
|
52
56
|
reusePreprocessedCss?: (file: string, previous: string | null | undefined, current: string | null | undefined) => boolean;
|
|
57
|
+
/** 捕获实际内存请求的独立只读副本;生成和缓存命中均调用,失败保留原始错误。 */
|
|
58
|
+
captureRequest?: (key: K, request: CompilerGenerateRequest$1) => void | Promise<void>;
|
|
53
59
|
}
|
|
54
60
|
/** 使用封存源码驱动上游完整候选生成;框架预处理与输出排除由宿主提供。 */
|
|
55
|
-
export declare function prepareTailwindRoots<K>(compiler: Compiler$1, request: HmrCompilerRequest, roots: ReadonlyMap<K, TailwindRootState>, options: TailwindRootHost): Promise<Map<K, CompilerGenerateResult$1>>;
|
|
61
|
+
export declare function prepareTailwindRoots<K>(compiler: Compiler$1, request: HmrCompilerRequest, roots: ReadonlyMap<K, TailwindRootState>, options: TailwindRootHost<K>): Promise<Map<K, CompilerGenerateResult$1>>;
|
|
56
62
|
//#endregion
|
|
57
63
|
//#region src/sources.d.ts
|
|
58
64
|
/** 返回上游实际扫描边界中的文件,宿主将它们登记到现有 watcher。 */
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { CompilerHmrResyncError, normalizeHmrSourceMap } from "@weapp-vite/hmr";
|
|
2
|
+
import { types } from "node:util";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { readFileSync, statSync } from "node:fs";
|
|
4
5
|
import path from "pathe";
|
|
6
|
+
import path$1 from "node:path";
|
|
7
|
+
import { resolveSourceScanPathWithApi, sourcePathApi, toPosixPath } from "@weapp-tailwindcss/source-scan";
|
|
8
|
+
import micromatch from "micromatch";
|
|
5
9
|
//#region src/controller.ts
|
|
6
10
|
/** 编译器按宿主生命周期惰性创建;不创建 Vite、DevEngine、watcher 或输出写入者。 */
|
|
7
11
|
var TailwindController = class {
|
|
@@ -62,6 +66,34 @@ function createTailwindPreparation(compiler, snapshot, assets = []) {
|
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
68
|
//#endregion
|
|
69
|
+
//#region src/generationValue.ts
|
|
70
|
+
/** 只复制可比较的生成配置;保留函数身份、属性描述与原型,拒绝不可安全封存的输入。 */
|
|
71
|
+
function copyTailwindGenerationValue(value, parents = /* @__PURE__ */ new Set()) {
|
|
72
|
+
if (value === null || typeof value !== "object") return value;
|
|
73
|
+
if (types.isProxy(value)) throw new TypeError("Tailwind generation configuration must not contain proxies");
|
|
74
|
+
const array = Array.isArray(value);
|
|
75
|
+
if (parents.has(value) || (array ? Object.getPrototypeOf(value) !== Array.prototype : Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)) throw new TypeError("Unsupported Tailwind generation configuration");
|
|
76
|
+
parents.add(value);
|
|
77
|
+
try {
|
|
78
|
+
const keys = Reflect.ownKeys(value);
|
|
79
|
+
if (array && keys.some((key) => key !== "length" && (typeof key !== "string" || !/^(?:0|[1-9]\d*)$/.test(key) || Number(key) >= value.length))) throw new TypeError("Tailwind generation configuration must not contain custom array properties");
|
|
80
|
+
const entries = keys.filter((key) => !array || key !== "length").map((key) => {
|
|
81
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
82
|
+
if (!("value" in descriptor)) throw new TypeError("Tailwind generation configuration must not contain accessors");
|
|
83
|
+
return [key, copyTailwindGenerationValue(descriptor.value, parents)];
|
|
84
|
+
});
|
|
85
|
+
const copy = array ? [] : Object.create(Object.getPrototypeOf(value));
|
|
86
|
+
if (array) copy.length = value.length;
|
|
87
|
+
for (const [key, item] of entries) Object.defineProperty(copy, key, {
|
|
88
|
+
value: item,
|
|
89
|
+
enumerable: Object.getOwnPropertyDescriptor(value, key).enumerable
|
|
90
|
+
});
|
|
91
|
+
return Object.freeze(copy);
|
|
92
|
+
} finally {
|
|
93
|
+
parents.delete(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
65
97
|
//#region src/output.ts
|
|
66
98
|
/** 在宿主回调内封存投影,再异步转换;Vite 最终 CSS 和所有补丁共用同一身份集合。 */
|
|
67
99
|
function prepareTailwindOutput(compiler, input) {
|
|
@@ -83,6 +115,127 @@ function prepareTailwindOutput(compiler, input) {
|
|
|
83
115
|
});
|
|
84
116
|
}
|
|
85
117
|
//#endregion
|
|
118
|
+
//#region src/sources/compact.ts
|
|
119
|
+
const MAX_COMPACTED_PATTERN_LENGTH = 8192;
|
|
120
|
+
function isLiteral(value) {
|
|
121
|
+
return /^[\w.-]+$/.test(value) && value !== "." && !value.includes("..");
|
|
122
|
+
}
|
|
123
|
+
function classify(entry) {
|
|
124
|
+
if (entry.negated !== true || typeof entry.base !== "string" || typeof entry.pattern !== "string" || !entry.pattern.startsWith("**/")) return;
|
|
125
|
+
const rest = entry.pattern.slice(3);
|
|
126
|
+
if (rest.endsWith("/**")) {
|
|
127
|
+
const token = rest.slice(0, -3);
|
|
128
|
+
return isLiteral(token) ? {
|
|
129
|
+
shape: "directory",
|
|
130
|
+
token
|
|
131
|
+
} : void 0;
|
|
132
|
+
}
|
|
133
|
+
const extension = /^\*\.([\w-]+)$/.exec(rest)?.[1];
|
|
134
|
+
if (extension) return {
|
|
135
|
+
shape: "extension",
|
|
136
|
+
token: extension
|
|
137
|
+
};
|
|
138
|
+
return isLiteral(rest) ? {
|
|
139
|
+
shape: "file",
|
|
140
|
+
token: rest
|
|
141
|
+
} : void 0;
|
|
142
|
+
}
|
|
143
|
+
function combinedPattern(shape, tokens) {
|
|
144
|
+
const prefix = shape === "extension" ? "**/*." : "**/";
|
|
145
|
+
const suffix = shape === "directory" ? "/**" : "";
|
|
146
|
+
return `${prefix}{${[...tokens].join(",")}}${suffix}`;
|
|
147
|
+
}
|
|
148
|
+
/** 仅合并连续的固定否定形态;保留上游 globstar、隐藏文件与异常求值顺序。 */
|
|
149
|
+
function compactTailwindSourceEntries(entries) {
|
|
150
|
+
const result = [];
|
|
151
|
+
for (let index = 0; index < entries.length;) {
|
|
152
|
+
const first = entries[index];
|
|
153
|
+
const shape = classify(first);
|
|
154
|
+
if (!shape) {
|
|
155
|
+
result.push(first);
|
|
156
|
+
index += 1;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const run = [first];
|
|
160
|
+
const tokens = /* @__PURE__ */ new Set([shape.token]);
|
|
161
|
+
let next = index + 1;
|
|
162
|
+
while (next < entries.length) {
|
|
163
|
+
const current = entries[next];
|
|
164
|
+
const member = classify(current);
|
|
165
|
+
if (current.base !== first.base || member?.shape !== shape.shape) break;
|
|
166
|
+
run.push(current);
|
|
167
|
+
tokens.add(member.token);
|
|
168
|
+
next += 1;
|
|
169
|
+
}
|
|
170
|
+
const pattern = combinedPattern(shape.shape, tokens);
|
|
171
|
+
result.push(...tokens.size > 1 && pattern.length <= MAX_COMPACTED_PATTERN_LENGTH ? [{
|
|
172
|
+
...first,
|
|
173
|
+
pattern
|
|
174
|
+
}] : run);
|
|
175
|
+
index = next;
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/sources/matcher.ts
|
|
181
|
+
/** 检查不执行访问器;不明对象仍由上游读取并保持原异常顺序。 */
|
|
182
|
+
function hasPlainEntries(entries) {
|
|
183
|
+
if (types.isProxy(entries) || !Array.isArray(entries) || Object.getPrototypeOf(entries) !== Array.prototype || Reflect.ownKeys(entries).some((key) => typeof key !== "string" || key !== "length" && !/^(?:0|[1-9]\d*)$/.test(key))) return false;
|
|
184
|
+
for (let index = 0; index < entries.length; index++) {
|
|
185
|
+
const item = Object.getOwnPropertyDescriptor(entries, String(index));
|
|
186
|
+
if (!item || !("value" in item)) return false;
|
|
187
|
+
const entry = item.value;
|
|
188
|
+
if (!entry || typeof entry !== "object" || types.isProxy(entry)) return false;
|
|
189
|
+
const prototype = Object.getPrototypeOf(entry);
|
|
190
|
+
if (prototype !== null && prototype !== Object.prototype) return false;
|
|
191
|
+
const descriptors = Object.getOwnPropertyDescriptors(entry);
|
|
192
|
+
if (Reflect.ownKeys(entry).some((key) => !("value" in Object.getOwnPropertyDescriptor(entry, key)))) return false;
|
|
193
|
+
if (typeof descriptors.base?.value !== "string" || typeof descriptors.pattern?.value !== "string" || typeof descriptors.negated?.value !== "boolean") return false;
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
/** 绝对模式沿上游词法 base 归一化;不能替换成真实路径 base。 */
|
|
198
|
+
function normalizePattern(entry) {
|
|
199
|
+
const windows = /^[a-z]:[\\/]/i.test(entry.base) || entry.base.includes("\\") || /^[a-z]:[\\/]/i.test(entry.pattern);
|
|
200
|
+
const pathApi = windows ? path$1.win32 : sourcePathApi(entry.base);
|
|
201
|
+
return pathApi.isAbsolute(entry.pattern) ? toPosixPath(pathApi.relative(pathApi.resolve(entry.base), entry.pattern)) : windows ? toPosixPath(entry.pattern) : entry.pattern;
|
|
202
|
+
}
|
|
203
|
+
/** 每文件刷新真实路径,仅复用本批次与文件系统无关的延迟 glob 编译。 */
|
|
204
|
+
function createTailwindSourceMatcher(original) {
|
|
205
|
+
const patterns = /* @__PURE__ */ new Map();
|
|
206
|
+
return (file, entries) => {
|
|
207
|
+
if (typeof file !== "string" || !hasPlainEntries(entries) || !entries.length) return original(file, entries);
|
|
208
|
+
const sources = compactTailwindSourceEntries(entries);
|
|
209
|
+
const resolvedFile = resolveSourceScanPathWithApi(file, sourcePathApi(file, ...sources.map((entry) => entry.base)));
|
|
210
|
+
const bases = /* @__PURE__ */ new Map();
|
|
211
|
+
const matches = (entry) => {
|
|
212
|
+
const pathApi = sourcePathApi(entry.base, resolvedFile);
|
|
213
|
+
let paths = bases.get(pathApi);
|
|
214
|
+
if (!paths) {
|
|
215
|
+
paths = /* @__PURE__ */ new Map();
|
|
216
|
+
bases.set(pathApi, paths);
|
|
217
|
+
}
|
|
218
|
+
let base = paths.get(entry.base);
|
|
219
|
+
if (base === void 0) {
|
|
220
|
+
base = resolveSourceScanPathWithApi(entry.base, pathApi);
|
|
221
|
+
paths.set(entry.base, base);
|
|
222
|
+
}
|
|
223
|
+
const relative = toPosixPath(pathApi.relative(base, resolvedFile));
|
|
224
|
+
if (!relative || relative.startsWith("../") || pathApi.isAbsolute(relative)) return false;
|
|
225
|
+
const pattern = normalizePattern(entry);
|
|
226
|
+
let match = patterns.get(pattern);
|
|
227
|
+
if (!match) {
|
|
228
|
+
match = micromatch.matcher(pattern);
|
|
229
|
+
patterns.set(pattern, match);
|
|
230
|
+
}
|
|
231
|
+
return match(relative);
|
|
232
|
+
};
|
|
233
|
+
const positive = sources.filter((entry) => !entry.negated);
|
|
234
|
+
const negative = sources.filter((entry) => entry.negated);
|
|
235
|
+
return positive.some(matches) && !negative.some(matches);
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
//#endregion
|
|
86
239
|
//#region src/roots.ts
|
|
87
240
|
const caches = /* @__PURE__ */ new WeakMap();
|
|
88
241
|
/** 使用封存源码驱动上游完整候选生成;框架预处理与输出排除由宿主提供。 */
|
|
@@ -97,15 +250,15 @@ async function prepareTailwindRoots(compiler, request, roots, options) {
|
|
|
97
250
|
};
|
|
98
251
|
const entries = /* @__PURE__ */ new Map();
|
|
99
252
|
if (!capturedRoots.size) return entries;
|
|
100
|
-
const {
|
|
253
|
+
const { isFileMatchedByTailwindV4SourceEntries } = await import("@weapp-tailwindcss/engine");
|
|
254
|
+
const matches = createTailwindSourceMatcher(isFileMatchedByTailwindV4SourceEntries);
|
|
101
255
|
for (const [index, root] of capturedRoots) {
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
const sources = [...request.sources].flatMap(([file, content]) => content !== null && matches
|
|
256
|
+
const sourceOptions = root.request.sourceOptions;
|
|
257
|
+
const sourceEntries = [...root.result.sources];
|
|
258
|
+
const sources = [...request.sources].flatMap(([file, content]) => content !== null && sourceEntries.length > 0 && matches(file, sourceEntries) && !options.isOutput?.(file) ? [{
|
|
105
259
|
content,
|
|
106
260
|
extension: path.extname(file).slice(1)
|
|
107
261
|
}] : []);
|
|
108
|
-
const sourceOptions = root.request.sourceOptions;
|
|
109
262
|
if (!sourceOptions) throw new Error("Tailwind HMR requires a captured source entry");
|
|
110
263
|
const cssSources = sourceOptions.cssSources?.map((source) => {
|
|
111
264
|
if (!source.file) return source;
|
|
@@ -150,7 +303,7 @@ async function prepareTailwindRoots(compiler, request, roots, options) {
|
|
|
150
303
|
[...dependencyVersions]
|
|
151
304
|
])).digest("hex");
|
|
152
305
|
const cached = cache.get(root);
|
|
153
|
-
|
|
306
|
+
let effectiveRequest = {
|
|
154
307
|
...root.request,
|
|
155
308
|
sourceOptions: {
|
|
156
309
|
...sourceOptions,
|
|
@@ -158,8 +311,14 @@ async function prepareTailwindRoots(compiler, request, roots, options) {
|
|
|
158
311
|
cssSources: [...cssSources ?? [], ...entrySources]
|
|
159
312
|
},
|
|
160
313
|
sources,
|
|
314
|
+
scanMode: "compiled",
|
|
161
315
|
scanSources: false
|
|
162
|
-
}
|
|
316
|
+
};
|
|
317
|
+
if (options.captureRequest) {
|
|
318
|
+
effectiveRequest = copyTailwindGenerationValue(effectiveRequest);
|
|
319
|
+
await options.captureRequest(index, effectiveRequest);
|
|
320
|
+
}
|
|
321
|
+
const generated = cached?.signature === signature ? cached.result : await compiler.generate(effectiveRequest);
|
|
163
322
|
entries.set(index, generated);
|
|
164
323
|
for (const file of generated.dependencies) checkDependency(file);
|
|
165
324
|
cache.set(root, {
|
|
@@ -184,4 +343,4 @@ async function listTailwindSourceFiles(result, cwd) {
|
|
|
184
343
|
});
|
|
185
344
|
}
|
|
186
345
|
//#endregion
|
|
187
|
-
export { TailwindController, createTailwindController, createTailwindPreparation, listTailwindSourceFiles, prepareTailwindOutput, prepareTailwindRoots };
|
|
346
|
+
export { TailwindController, copyTailwindGenerationValue, createTailwindController, createTailwindPreparation, listTailwindSourceFiles, prepareTailwindOutput, prepareTailwindRoots };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weapp-vite/tailwindcss",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "基于 weapp-tailwindcss/core 的宿主无关编译控制器",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/weapp-vite/weapp-vite#readme",
|
|
@@ -37,10 +37,15 @@
|
|
|
37
37
|
"node": "^22.18.0 || ^24.11.0 || >=26.0.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@weapp-tailwindcss/engine": "0.1.
|
|
41
|
-
"@weapp-
|
|
40
|
+
"@weapp-tailwindcss/engine": "0.1.6",
|
|
41
|
+
"@weapp-tailwindcss/source-scan": "0.1.2",
|
|
42
|
+
"@weapp-vite/hmr": "0.2.2",
|
|
43
|
+
"micromatch": "4.0.8",
|
|
42
44
|
"pathe": "^2.0.3",
|
|
43
|
-
"weapp-tailwindcss": "^5.6.
|
|
45
|
+
"weapp-tailwindcss": "^5.6.3"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/micromatch": "4.0.10"
|
|
44
49
|
},
|
|
45
50
|
"publishConfig": {
|
|
46
51
|
"access": "public",
|