auklet 0.2.0 → 0.2.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/configLoader.js +3 -1
- package/dist/css/vite/moduleGraph/devDependency.d.ts +2 -0
- package/dist/css/vite/moduleGraph/devDependency.js +51 -0
- package/dist/css/vite/moduleGraph/persistentCache.d.ts +2 -0
- package/dist/css/vite/moduleGraph/persistentCache.js +42 -0
- package/dist/css/vite/moduleGraph/requestCache.d.ts +2 -0
- package/dist/css/vite/moduleGraph/requestCache.js +33 -8
- package/dist/css/vite/moduleGraph/styleCodeFactory.js +6 -0
- package/package.json +1 -1
package/dist/configLoader.js
CHANGED
|
@@ -6,6 +6,7 @@ import { aukletConfigFiles, isAukletConfigFile } from '#auklet/config';
|
|
|
6
6
|
const asRecord = (value) => {
|
|
7
7
|
return isPlainObject(value) ? value : null;
|
|
8
8
|
};
|
|
9
|
+
let configImportVersion = 0;
|
|
9
10
|
const assertSupportedConfigFile = (configFile) => {
|
|
10
11
|
const basename = path.basename(configFile);
|
|
11
12
|
if (isAukletConfigFile(basename))
|
|
@@ -53,7 +54,8 @@ export async function loadAukletConfig(packageRoot, options = {}) {
|
|
|
53
54
|
}
|
|
54
55
|
const url = pathToFileURL(configPath);
|
|
55
56
|
if (options.cacheBust) {
|
|
56
|
-
|
|
57
|
+
configImportVersion += 1;
|
|
58
|
+
url.searchParams.set('t', configImportVersion.toString());
|
|
57
59
|
}
|
|
58
60
|
const module = (await import(url.href));
|
|
59
61
|
return resolveAukletConfigModule(module);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { PackageStyleContext } from '#auklet/css/vite/moduleGraph/requestCache';
|
|
2
2
|
export declare function toDevDependencyImportSpecifier(context: PackageStyleContext, specifier: string): {
|
|
3
3
|
specifier: string;
|
|
4
|
+
cacheInputFiles?: undefined;
|
|
4
5
|
watchFile?: undefined;
|
|
5
6
|
} | {
|
|
7
|
+
cacheInputFiles: string[];
|
|
6
8
|
specifier: string;
|
|
7
9
|
watchFile: string;
|
|
8
10
|
};
|
|
@@ -1,11 +1,62 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
1
3
|
import { toFsSpecifier } from '#auklet/utils';
|
|
4
|
+
const getPackageName = (specifier) => {
|
|
5
|
+
if (!specifier.startsWith('@'))
|
|
6
|
+
return specifier.split('/')[0] ?? specifier;
|
|
7
|
+
const [scope, name] = specifier.split('/');
|
|
8
|
+
if (!scope || !name)
|
|
9
|
+
return null;
|
|
10
|
+
return `${scope}/${name}`;
|
|
11
|
+
};
|
|
12
|
+
const findNodeModulesPackageRoot = (file, packageName) => {
|
|
13
|
+
const resolved = path.resolve(file);
|
|
14
|
+
const root = path.parse(resolved).root;
|
|
15
|
+
const parts = path.relative(root, resolved).split(path.sep);
|
|
16
|
+
const packageParts = packageName.split('/');
|
|
17
|
+
const packageLength = packageParts.length;
|
|
18
|
+
for (let index = parts.length - packageLength - 1; index >= 0; index -= 1) {
|
|
19
|
+
if (parts[index] !== 'node_modules')
|
|
20
|
+
continue;
|
|
21
|
+
const candidateParts = parts.slice(index + 1, index + 1 + packageLength);
|
|
22
|
+
if (candidateParts.join('/') !== packageName)
|
|
23
|
+
continue;
|
|
24
|
+
return path.join(root, ...parts.slice(0, index + 1 + packageLength));
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
const findPackageJson = (file, context, specifier) => {
|
|
29
|
+
const packageName = getPackageName(specifier);
|
|
30
|
+
if (!packageName)
|
|
31
|
+
return null;
|
|
32
|
+
const packageRoot = findNodeModulesPackageRoot(file, packageName);
|
|
33
|
+
if (!packageRoot) {
|
|
34
|
+
return path.join(context.context.packageRoot, 'node_modules', packageName, 'package.json');
|
|
35
|
+
}
|
|
36
|
+
let current = path.dirname(file);
|
|
37
|
+
let next = current;
|
|
38
|
+
const packageRootKey = path.resolve(packageRoot);
|
|
39
|
+
do {
|
|
40
|
+
const packageJson = path.join(current, 'package.json');
|
|
41
|
+
if (fs.existsSync(packageJson))
|
|
42
|
+
return packageJson;
|
|
43
|
+
if (path.resolve(current) === packageRootKey)
|
|
44
|
+
break;
|
|
45
|
+
next = path.dirname(current);
|
|
46
|
+
if (next !== current)
|
|
47
|
+
current = next;
|
|
48
|
+
} while (next !== current);
|
|
49
|
+
return path.join(context.context.packageRoot, 'node_modules', packageName, 'package.json');
|
|
50
|
+
};
|
|
2
51
|
// 在 Vite 虚拟 CSS 中,第三方 CSS 依赖要用声明它的包作为解析根。
|
|
3
52
|
export function toDevDependencyImportSpecifier(context, specifier) {
|
|
4
53
|
if (specifier.startsWith('.') || specifier.startsWith('/')) {
|
|
5
54
|
return { specifier };
|
|
6
55
|
}
|
|
7
56
|
const resolved = context.resolver.resolveStyleDependency(specifier);
|
|
57
|
+
const packageJson = findPackageJson(resolved, context, specifier);
|
|
8
58
|
return {
|
|
59
|
+
cacheInputFiles: packageJson ? [packageJson] : [],
|
|
9
60
|
specifier: toFsSpecifier(resolved),
|
|
10
61
|
watchFile: resolved,
|
|
11
62
|
};
|
|
@@ -3,11 +3,13 @@ export type PersistentStyleGraphCacheOptions = {
|
|
|
3
3
|
root: string;
|
|
4
4
|
};
|
|
5
5
|
export declare class PersistentStyleGraphCache {
|
|
6
|
+
private static readonly cleanedRoots;
|
|
6
7
|
private readonly cacheRoot;
|
|
7
8
|
constructor(options: PersistentStyleGraphCacheOptions);
|
|
8
9
|
createKey(value: unknown): string;
|
|
9
10
|
read(key: string): PackageStyleLoadResult | null;
|
|
10
11
|
write(key: string, result: PackageStyleLoadResult, inputFiles: Array<string>): void;
|
|
12
|
+
private cleanupStaleEntries;
|
|
11
13
|
private getCacheFile;
|
|
12
14
|
private isFresh;
|
|
13
15
|
}
|
|
@@ -3,6 +3,8 @@ import path from 'node:path';
|
|
|
3
3
|
import crypto from 'node:crypto';
|
|
4
4
|
import { toPosixPath } from '#auklet/utils';
|
|
5
5
|
const cacheVersion = 'v1';
|
|
6
|
+
const maxCacheFiles = 5000;
|
|
7
|
+
const staleCacheAgeMs = 7 * 24 * 60 * 60 * 1000;
|
|
6
8
|
const stableStringify = (value) => {
|
|
7
9
|
if (Array.isArray(value)) {
|
|
8
10
|
return `[${value.map((item) => stableStringify(item)).join(',')}]`;
|
|
@@ -66,6 +68,7 @@ const statCachedFile = (file) => {
|
|
|
66
68
|
};
|
|
67
69
|
};
|
|
68
70
|
export class PersistentStyleGraphCache {
|
|
71
|
+
static cleanedRoots = new Set();
|
|
69
72
|
cacheRoot;
|
|
70
73
|
constructor(options) {
|
|
71
74
|
this.cacheRoot = path.join(options.root, 'node_modules', '.auklet', 'cache', 'vite-style', cacheVersion);
|
|
@@ -106,6 +109,45 @@ export class PersistentStyleGraphCache {
|
|
|
106
109
|
}
|
|
107
110
|
catch {
|
|
108
111
|
// Cache writes are an optimization; dev CSS generation must keep working.
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.cleanupStaleEntries();
|
|
115
|
+
}
|
|
116
|
+
cleanupStaleEntries() {
|
|
117
|
+
if (PersistentStyleGraphCache.cleanedRoots.has(this.cacheRoot))
|
|
118
|
+
return;
|
|
119
|
+
PersistentStyleGraphCache.cleanedRoots.add(this.cacheRoot);
|
|
120
|
+
try {
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
const entries = fs
|
|
123
|
+
.readdirSync(this.cacheRoot, { withFileTypes: true })
|
|
124
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
|
|
125
|
+
.map((entry) => {
|
|
126
|
+
const file = path.join(this.cacheRoot, entry.name);
|
|
127
|
+
return {
|
|
128
|
+
file,
|
|
129
|
+
mtimeMs: fs.statSync(file).mtimeMs,
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
const freshEntries = [];
|
|
133
|
+
for (const entry of entries) {
|
|
134
|
+
if (now - entry.mtimeMs > staleCacheAgeMs) {
|
|
135
|
+
fs.unlinkSync(entry.file);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
freshEntries.push(entry);
|
|
139
|
+
}
|
|
140
|
+
const overflowCount = freshEntries.length - maxCacheFiles;
|
|
141
|
+
if (overflowCount <= 0)
|
|
142
|
+
return;
|
|
143
|
+
for (const entry of freshEntries
|
|
144
|
+
.sort((left, right) => left.mtimeMs - right.mtimeMs)
|
|
145
|
+
.slice(0, overflowCount)) {
|
|
146
|
+
fs.unlinkSync(entry.file);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Cache cleanup is best-effort and must not affect dev CSS generation.
|
|
109
151
|
}
|
|
110
152
|
}
|
|
111
153
|
getCacheFile(key) {
|
|
@@ -79,6 +79,8 @@ export declare class ModuleStyleGraphRequestCache {
|
|
|
79
79
|
private createContext;
|
|
80
80
|
private createPersistentKey;
|
|
81
81
|
private getPersistentInputFiles;
|
|
82
|
+
private getPackageKeyEntries;
|
|
83
|
+
private getWorkspaceInputFiles;
|
|
82
84
|
private getSourceInputFiles;
|
|
83
85
|
private getResolutionInputFiles;
|
|
84
86
|
private getLoadResultKey;
|
|
@@ -103,6 +103,7 @@ export class ModuleStyleGraphRequestCache {
|
|
|
103
103
|
normalizedConfig: context.normalizedConfig,
|
|
104
104
|
packageName: context.packageName,
|
|
105
105
|
packageNames: this.getPackageNames(),
|
|
106
|
+
packages: this.getPackageKeyEntries(),
|
|
106
107
|
packageRoot: normalizeFileKey(context.context.packageRoot),
|
|
107
108
|
parsed,
|
|
108
109
|
root: normalizeFileKey(this.options.root),
|
|
@@ -116,21 +117,42 @@ export class ModuleStyleGraphRequestCache {
|
|
|
116
117
|
...(result.cacheInputFiles ?? []),
|
|
117
118
|
...this.getSourceInputFiles(context.sourceRoot, context.packageContext.sourceFiles),
|
|
118
119
|
...this.getResolutionInputFiles(context.context.packageRoot),
|
|
120
|
+
...this.getWorkspaceInputFiles(),
|
|
119
121
|
];
|
|
120
122
|
}
|
|
123
|
+
getPackageKeyEntries() {
|
|
124
|
+
return this.options.packageSource
|
|
125
|
+
.getPackages()
|
|
126
|
+
.map((item) => ({
|
|
127
|
+
packageName: item.packageName,
|
|
128
|
+
packageRoot: normalizeFileKey(item.packageRoot),
|
|
129
|
+
}))
|
|
130
|
+
.sort((left, right) => {
|
|
131
|
+
const nameOrder = left.packageName.localeCompare(right.packageName);
|
|
132
|
+
if (nameOrder !== 0)
|
|
133
|
+
return nameOrder;
|
|
134
|
+
return left.packageRoot.localeCompare(right.packageRoot);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
getWorkspaceInputFiles() {
|
|
138
|
+
if (this.options.mode !== 'monorepo')
|
|
139
|
+
return [];
|
|
140
|
+
return [path.join(this.options.root, 'pnpm-workspace.yaml')];
|
|
141
|
+
}
|
|
121
142
|
getSourceInputFiles(sourceRoot, sourceFiles) {
|
|
122
143
|
const sourceInputFiles = new Set([sourceRoot, ...sourceFiles]);
|
|
123
144
|
const normalizedSourceRoot = normalizeFileKey(sourceRoot);
|
|
124
145
|
for (const file of sourceFiles) {
|
|
125
146
|
let current = path.dirname(file);
|
|
126
|
-
|
|
147
|
+
let currentKey = normalizeFileKey(current);
|
|
148
|
+
while (currentKey === normalizedSourceRoot ||
|
|
149
|
+
currentKey.startsWith(`${normalizedSourceRoot}/`)) {
|
|
127
150
|
sourceInputFiles.add(current);
|
|
128
|
-
if (
|
|
151
|
+
if (currentKey === normalizedSourceRoot)
|
|
129
152
|
break;
|
|
130
153
|
const parent = path.dirname(current);
|
|
131
|
-
if (parent === current)
|
|
132
|
-
break;
|
|
133
154
|
current = parent;
|
|
155
|
+
currentKey = normalizeFileKey(current);
|
|
134
156
|
}
|
|
135
157
|
}
|
|
136
158
|
return Array.from(sourceInputFiles);
|
|
@@ -139,16 +161,19 @@ export class ModuleStyleGraphRequestCache {
|
|
|
139
161
|
const files = [path.join(packageRoot, 'package.json')];
|
|
140
162
|
let current = packageRoot;
|
|
141
163
|
const graphRoot = normalizeFileKey(this.options.root);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
164
|
+
let reachedGraphRoot = false;
|
|
165
|
+
while (!reachedGraphRoot) {
|
|
166
|
+
const tsconfig = path.join(current, 'tsconfig.json');
|
|
167
|
+
files.push(tsconfig);
|
|
168
|
+
reachedGraphRoot = normalizeFileKey(current) === graphRoot;
|
|
169
|
+
if (reachedGraphRoot)
|
|
145
170
|
break;
|
|
146
171
|
const parent = path.dirname(current);
|
|
147
172
|
if (parent === current)
|
|
148
173
|
break;
|
|
149
174
|
current = parent;
|
|
150
175
|
}
|
|
151
|
-
return files;
|
|
176
|
+
return Array.from(new Set(files));
|
|
152
177
|
}
|
|
153
178
|
getLoadResultKey(parsed) {
|
|
154
179
|
return `${parsed.packageName}\0${parsed.stylePath}`;
|
|
@@ -62,6 +62,7 @@ export class StyleCodeFactory {
|
|
|
62
62
|
}
|
|
63
63
|
async createDependencyStyleCode(context, cache, specifiers, mapSpecifier = (specifier) => specifier) {
|
|
64
64
|
const results = [];
|
|
65
|
+
const cacheInputFiles = [];
|
|
65
66
|
const imports = [];
|
|
66
67
|
const watchFiles = [...context.configPaths];
|
|
67
68
|
for (const specifier of specifiers) {
|
|
@@ -74,12 +75,14 @@ export class StyleCodeFactory {
|
|
|
74
75
|
}
|
|
75
76
|
const resolvedSpecifier = toDevDependencyImportSpecifier(context, outputSpecifier);
|
|
76
77
|
imports.push(resolvedSpecifier.specifier);
|
|
78
|
+
cacheInputFiles.push(...(resolvedSpecifier.cacheInputFiles ?? []));
|
|
77
79
|
if (resolvedSpecifier.watchFile) {
|
|
78
80
|
watchFiles.push(resolvedSpecifier.watchFile);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
return mergeLoadResults({
|
|
82
84
|
code: createImportCode(imports),
|
|
85
|
+
cacheInputFiles,
|
|
83
86
|
watchFiles,
|
|
84
87
|
}, ...results);
|
|
85
88
|
}
|
|
@@ -144,6 +147,7 @@ export class StyleCodeFactory {
|
|
|
144
147
|
const moduleStyleResults = [];
|
|
145
148
|
const moduleStyleSpecifiers = [];
|
|
146
149
|
const moduleStyleWatchFiles = [];
|
|
150
|
+
const moduleStyleCacheInputFiles = [];
|
|
147
151
|
for (const specifier of entry.moduleStyleImports) {
|
|
148
152
|
const result = this.toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir);
|
|
149
153
|
const parsed = this.parsePackageStyleIdInRequest(result, cache);
|
|
@@ -154,6 +158,7 @@ export class StyleCodeFactory {
|
|
|
154
158
|
}
|
|
155
159
|
const resolvedSpecifier = toDevDependencyImportSpecifier(context, result);
|
|
156
160
|
moduleStyleSpecifiers.push(resolvedSpecifier.specifier);
|
|
161
|
+
moduleStyleCacheInputFiles.push(...(resolvedSpecifier.cacheInputFiles ?? []));
|
|
157
162
|
if (resolvedSpecifier.watchFile) {
|
|
158
163
|
moduleStyleWatchFiles.push(resolvedSpecifier.watchFile);
|
|
159
164
|
}
|
|
@@ -179,6 +184,7 @@ export class StyleCodeFactory {
|
|
|
179
184
|
...moduleStyleWatchFiles,
|
|
180
185
|
...sourceFiles.filter((file) => /\.(ts|tsx)$/.test(file)),
|
|
181
186
|
],
|
|
187
|
+
cacheInputFiles: moduleStyleCacheInputFiles,
|
|
182
188
|
});
|
|
183
189
|
}
|
|
184
190
|
toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir) {
|