auklet 0.1.8 → 0.2.0
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/css/core/style/entries.js +7 -4
- package/dist/css/core/stylePackageContext.d.ts +5 -0
- package/dist/css/core/stylePackageContext.js +11 -0
- package/dist/css/vite/hmr.d.ts +2 -0
- package/dist/css/vite/hmr.js +39 -32
- package/dist/css/vite/moduleGraph/graph.d.ts +6 -5
- package/dist/css/vite/moduleGraph/graph.js +32 -7
- package/dist/css/vite/moduleGraph/loadResult.d.ts +2 -0
- package/dist/css/vite/moduleGraph/loadResult.js +2 -0
- package/dist/css/vite/moduleGraph/persistentCache.d.ts +13 -0
- package/dist/css/vite/moduleGraph/persistentCache.js +137 -0
- package/dist/css/vite/moduleGraph/requestCache.d.ts +22 -1
- package/dist/css/vite/moduleGraph/requestCache.js +125 -0
- package/dist/css/vite/moduleGraph/styleCodeFactory.d.ts +4 -5
- package/dist/css/vite/moduleGraph/styleCodeFactory.js +28 -10
- package/dist/css/vite/moduleGraph/types.d.ts +2 -0
- package/dist/css/vite/vitePlugin.js +6 -1
- package/package.json +1 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getGlobalStyleDependencies, getThemeNames, getThemeStyleDependencies, } from '#auklet/css/core/style/dependencies';
|
|
2
|
-
import { StyleModuleEntryPlanner } from '#auklet/css/core/styleModuleEntryPlanner';
|
|
3
2
|
const dependenciesPart = (specifiers) => ({ type: 'dependencies', specifiers });
|
|
4
3
|
// 环境无关的 style entry graph。production writer 和 Vite/dev renderer 都从这里取入口语义。
|
|
5
4
|
export function createStyleEntryParts(config) {
|
|
@@ -25,11 +24,15 @@ export function createExternalEntryParts(config) {
|
|
|
25
24
|
];
|
|
26
25
|
}
|
|
27
26
|
export function collectModuleStyleImports(packageContext) {
|
|
28
|
-
return packageContext.
|
|
27
|
+
return packageContext.getModuleStyleImports();
|
|
29
28
|
}
|
|
30
29
|
export function createModuleStyleEntryPlan(packageContext, sourceDir) {
|
|
31
|
-
return
|
|
30
|
+
return packageContext
|
|
31
|
+
.getModuleStyleEntryPlanner()
|
|
32
|
+
.createEntry(sourceDir, collectModuleStyleImports(packageContext));
|
|
32
33
|
}
|
|
33
34
|
export function createModuleStyleEntryPlans(packageContext) {
|
|
34
|
-
return
|
|
35
|
+
return packageContext
|
|
36
|
+
.getModuleStyleEntryPlanner()
|
|
37
|
+
.createEntries(collectModuleStyleImports(packageContext));
|
|
35
38
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ModuleStyleImportCollector } from '#auklet/css/core/styleImports/collector';
|
|
2
|
+
import { StyleModuleEntryPlanner } from '#auklet/css/core/styleModuleEntryPlanner';
|
|
2
3
|
import { StyleProcessor } from '#auklet/css/core/styleProcessor';
|
|
3
4
|
import { WorkspaceStyleResolver } from '#auklet/css/core/workspaceStyleResolver';
|
|
4
5
|
import type { ModuleStyleBuildConfig, NormalizedAukletConfig, ResolvedModuleStyleBuildContext } from '#auklet/types';
|
|
@@ -18,6 +19,10 @@ export declare class StylePackageContext {
|
|
|
18
19
|
readonly themeFiles: Map<string, string>;
|
|
19
20
|
readonly themeNames: Array<string>;
|
|
20
21
|
readonly styleFiles: Array<string>;
|
|
22
|
+
private moduleStyleEntryPlanner?;
|
|
23
|
+
private moduleStyleImports?;
|
|
21
24
|
constructor(options: StylePackageContextOptions);
|
|
22
25
|
getStyleFiles(files: Array<string>): string[];
|
|
26
|
+
getModuleStyleImports(): Map<string, string[]>;
|
|
27
|
+
getModuleStyleEntryPlanner(): StyleModuleEntryPlanner;
|
|
23
28
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ModuleStyleImportCollector } from '#auklet/css/core/styleImports/collector';
|
|
4
|
+
import { StyleModuleEntryPlanner } from '#auklet/css/core/styleModuleEntryPlanner';
|
|
4
5
|
import { StyleProcessor } from '#auklet/css/core/styleProcessor';
|
|
5
6
|
import { WorkspaceStyleResolver } from '#auklet/css/core/workspaceStyleResolver';
|
|
6
7
|
import { createStyleFileKeySet } from '#auklet/css/core/style/files';
|
|
@@ -17,6 +18,8 @@ export class StylePackageContext {
|
|
|
17
18
|
themeFiles;
|
|
18
19
|
themeNames;
|
|
19
20
|
styleFiles;
|
|
21
|
+
moduleStyleEntryPlanner;
|
|
22
|
+
moduleStyleImports;
|
|
20
23
|
constructor(options) {
|
|
21
24
|
this.options = options;
|
|
22
25
|
const { config, context, normalizedConfig } = this.options;
|
|
@@ -38,4 +41,12 @@ export class StylePackageContext {
|
|
|
38
41
|
.filter((file) => this.options.config.styleExtensions.includes(path.extname(file)))
|
|
39
42
|
.filter((styleFile) => !themeFileKeys.has(normalizeFileKey(styleFile)));
|
|
40
43
|
}
|
|
44
|
+
getModuleStyleImports() {
|
|
45
|
+
this.moduleStyleImports ??= this.importCollector.collect(this.sourceFiles, this.normalizedConfig);
|
|
46
|
+
return this.moduleStyleImports;
|
|
47
|
+
}
|
|
48
|
+
getModuleStyleEntryPlanner() {
|
|
49
|
+
this.moduleStyleEntryPlanner ??= new StyleModuleEntryPlanner(this);
|
|
50
|
+
return this.moduleStyleEntryPlanner;
|
|
51
|
+
}
|
|
41
52
|
}
|
package/dist/css/vite/hmr.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export declare class AukletStyleHmr {
|
|
|
9
9
|
trackVirtualStyleDependency(file: string, virtualId: string): void;
|
|
10
10
|
installFullReloadGuard(server: Pick<ViteDevServer, 'ws'>): void;
|
|
11
11
|
handleStyleHotUpdate(context: HotUpdateOptions): never[] | undefined;
|
|
12
|
+
handleSourceModuleChange(server: Pick<ViteDevServer, 'moduleGraph' | 'ws'>, file: string): boolean;
|
|
13
|
+
private sendVirtualStyleUpdates;
|
|
12
14
|
private suppressFullReload;
|
|
13
15
|
private shouldSuppressFullReload;
|
|
14
16
|
private isDuplicateUpdate;
|
package/dist/css/vite/hmr.js
CHANGED
|
@@ -11,19 +11,6 @@ const toBrowserVirtualPath = (id) => {
|
|
|
11
11
|
const getRelativeFile = (file) => {
|
|
12
12
|
return path.relative(process.cwd(), file);
|
|
13
13
|
};
|
|
14
|
-
const invalidateVirtualModules = (server, graph) => {
|
|
15
|
-
const modules = [];
|
|
16
|
-
for (const packageName of graph.getPackageNames()) {
|
|
17
|
-
for (const entry of ['style.css', 'external.css', 'module.css']) {
|
|
18
|
-
const module = server.moduleGraph.getModuleById(`\0auklet-css:${packageName}/${entry}`);
|
|
19
|
-
if (!module)
|
|
20
|
-
continue;
|
|
21
|
-
server.moduleGraph.invalidateModule(module);
|
|
22
|
-
modules.push(module);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return modules;
|
|
26
|
-
};
|
|
27
14
|
const addVirtualStyleDependency = (virtualIdsByDependency, file, virtualId) => {
|
|
28
15
|
const normalizedFile = normalizeFileKey(file);
|
|
29
16
|
const values = virtualIdsByDependency.get(normalizedFile) ?? new Set();
|
|
@@ -39,6 +26,19 @@ const getDependencyVirtualModules = (virtualIdsByDependency, server, file) => {
|
|
|
39
26
|
return module ? [module] : [];
|
|
40
27
|
});
|
|
41
28
|
};
|
|
29
|
+
const createJsUpdates = (virtualIds, timestamp) => {
|
|
30
|
+
return virtualIds.map((id) => {
|
|
31
|
+
const browserPath = toBrowserVirtualPath(id);
|
|
32
|
+
return {
|
|
33
|
+
type: 'js-update',
|
|
34
|
+
path: browserPath,
|
|
35
|
+
acceptedPath: browserPath,
|
|
36
|
+
timestamp,
|
|
37
|
+
explicitImportRequired: false,
|
|
38
|
+
isWithinCircularImport: false,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
42
|
export class AukletStyleHmr {
|
|
43
43
|
graph;
|
|
44
44
|
lastUpdateTimes = new Map();
|
|
@@ -72,35 +72,42 @@ export class AukletStyleHmr {
|
|
|
72
72
|
!graph.isStyleFile(context.file)) {
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
|
+
this.suppressFullReload();
|
|
76
|
+
graph.invalidateFile(context.file);
|
|
75
77
|
if (this.isDuplicateUpdate(context.file)) {
|
|
76
78
|
return [];
|
|
77
79
|
}
|
|
78
|
-
this.
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
const updates = this.sendVirtualStyleUpdates(context.file, context.server, context.timestamp);
|
|
81
|
+
logger.info(`package css hmr ${getRelativeFile(context.file)} tracked=${updates.tracked} updates=${updates.sent}`);
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
handleSourceModuleChange(server, file) {
|
|
85
|
+
const graph = this.graph();
|
|
86
|
+
if (!graph.isSourceGraphFile(file) || !graph.isSourceModuleFile(file)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
graph.invalidateFile(file);
|
|
90
|
+
const updates = this.sendVirtualStyleUpdates(file, server, Date.now());
|
|
91
|
+
logger.info(`package css source hmr ${getRelativeFile(file)} tracked=${updates.tracked} updates=${updates.sent}`);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
sendVirtualStyleUpdates(file, server, timestamp) {
|
|
95
|
+
const virtualIds = getDependencyVirtualIds(this.virtualIdsByDependency, file);
|
|
96
|
+
const modules = getDependencyVirtualModules(this.virtualIdsByDependency, server, file);
|
|
81
97
|
for (const module of modules) {
|
|
82
|
-
|
|
98
|
+
server.moduleGraph.invalidateModule(module);
|
|
83
99
|
}
|
|
84
|
-
|
|
85
|
-
const updates = virtualIds.map((id) => {
|
|
86
|
-
const browserPath = toBrowserVirtualPath(id);
|
|
87
|
-
return {
|
|
88
|
-
type: 'js-update',
|
|
89
|
-
path: browserPath,
|
|
90
|
-
acceptedPath: browserPath,
|
|
91
|
-
timestamp: context.timestamp,
|
|
92
|
-
explicitImportRequired: false,
|
|
93
|
-
isWithinCircularImport: false,
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
logger.info(`package css hmr ${getRelativeFile(context.file)} tracked=${virtualIds.length} updates=${updates.length}`);
|
|
100
|
+
const updates = createJsUpdates(virtualIds, timestamp);
|
|
97
101
|
if (updates.length) {
|
|
98
|
-
|
|
102
|
+
server.ws.send({
|
|
99
103
|
type: 'update',
|
|
100
104
|
updates,
|
|
101
105
|
});
|
|
102
106
|
}
|
|
103
|
-
return
|
|
107
|
+
return {
|
|
108
|
+
sent: updates.length,
|
|
109
|
+
tracked: virtualIds.length,
|
|
110
|
+
};
|
|
104
111
|
}
|
|
105
112
|
suppressFullReload() {
|
|
106
113
|
this.suppressFullReloadUntil = Date.now() + FULL_RELOAD_SUPPRESS_MS;
|
|
@@ -3,6 +3,7 @@ export declare class ModuleStyleGraph {
|
|
|
3
3
|
private readonly config;
|
|
4
4
|
private readonly packageSource;
|
|
5
5
|
private readonly styleCodeFactory;
|
|
6
|
+
private readonly requestCache;
|
|
6
7
|
private readonly loadAukletConfig;
|
|
7
8
|
constructor(options: ModuleStyleGraphOptions);
|
|
8
9
|
parsePackageStyleId(id: string): {
|
|
@@ -14,9 +15,9 @@ export declare class ModuleStyleGraph {
|
|
|
14
15
|
isStyleFile(file: string): boolean;
|
|
15
16
|
getPackageNames(): string[];
|
|
16
17
|
getWatchRoots(): Promise<string[]>;
|
|
17
|
-
createPackageStyleCode(parsed: PackageStyleId): Promise<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private
|
|
18
|
+
createPackageStyleCode(parsed: PackageStyleId): Promise<import("#auklet/css/vite/moduleGraph/types").PackageStyleLoadResult>;
|
|
19
|
+
invalidatePackage(packageName: string): void;
|
|
20
|
+
invalidateFile(file: string): string | null;
|
|
21
|
+
isSourceModuleFile(file: string): boolean;
|
|
22
|
+
private isPackageFile;
|
|
22
23
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { isAukletConfigFile } from '#auklet/config';
|
|
3
3
|
import { loadAukletConfig } from '#auklet/configLoader';
|
|
4
|
+
import { SOURCE_MODULE_RE } from '#auklet/css/constants';
|
|
4
5
|
import { moduleStyleBuildConfig } from '#auklet/css/config';
|
|
5
6
|
import { parsePackageStyleId } from '#auklet/css/vite/moduleGraph/styleId';
|
|
6
7
|
import { StyleCodeFactory } from '#auklet/css/vite/moduleGraph/styleCodeFactory';
|
|
@@ -13,6 +14,7 @@ export class ModuleStyleGraph {
|
|
|
13
14
|
config;
|
|
14
15
|
packageSource;
|
|
15
16
|
styleCodeFactory;
|
|
17
|
+
requestCache;
|
|
16
18
|
loadAukletConfig;
|
|
17
19
|
constructor(options) {
|
|
18
20
|
this.config = options.config ?? moduleStyleBuildConfig;
|
|
@@ -29,6 +31,13 @@ export class ModuleStyleGraph {
|
|
|
29
31
|
styleExtensions: this.config.styleExtensions,
|
|
30
32
|
loadAukletConfig: this.loadAukletConfig,
|
|
31
33
|
});
|
|
34
|
+
this.requestCache = new ModuleStyleGraphRequestCache({
|
|
35
|
+
root: normalizeFileKey(options.root),
|
|
36
|
+
mode: options.mode ?? 'package',
|
|
37
|
+
packageSource: this.packageSource,
|
|
38
|
+
config: this.config,
|
|
39
|
+
loadAukletConfig: this.loadAukletConfig,
|
|
40
|
+
});
|
|
32
41
|
}
|
|
33
42
|
parsePackageStyleId(id) {
|
|
34
43
|
return parsePackageStyleId(id, this.getPackageNames());
|
|
@@ -49,13 +58,29 @@ export class ModuleStyleGraph {
|
|
|
49
58
|
return this.packageSource.getWatchRoots();
|
|
50
59
|
}
|
|
51
60
|
createPackageStyleCode(parsed) {
|
|
52
|
-
return this.styleCodeFactory.createPackageStyleCode(parsed, this.
|
|
61
|
+
return this.styleCodeFactory.createPackageStyleCode(parsed, this.requestCache);
|
|
53
62
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
invalidatePackage(packageName) {
|
|
64
|
+
this.requestCache.invalidatePackage(packageName);
|
|
65
|
+
}
|
|
66
|
+
invalidateFile(file) {
|
|
67
|
+
if (!this.isSourceGraphFile(file))
|
|
68
|
+
return null;
|
|
69
|
+
const normalizedFile = normalizeFileKey(file);
|
|
70
|
+
const stylePackage = this.packageSource
|
|
71
|
+
.getPackages()
|
|
72
|
+
.find((item) => this.isPackageFile(item.packageRoot, normalizedFile));
|
|
73
|
+
if (!stylePackage)
|
|
74
|
+
return null;
|
|
75
|
+
this.invalidatePackage(stylePackage.packageName);
|
|
76
|
+
return stylePackage.packageName;
|
|
77
|
+
}
|
|
78
|
+
isSourceModuleFile(file) {
|
|
79
|
+
return SOURCE_MODULE_RE.test(normalizeFileKey(file));
|
|
80
|
+
}
|
|
81
|
+
isPackageFile(packageRoot, file) {
|
|
82
|
+
const normalizedPackageRoot = normalizeFileKey(packageRoot);
|
|
83
|
+
return (file === normalizedPackageRoot ||
|
|
84
|
+
file.startsWith(`${normalizedPackageRoot}/`));
|
|
60
85
|
}
|
|
61
86
|
}
|
|
@@ -2,4 +2,6 @@ import type { PackageStyleLoadResult } from '#auklet/css/vite/moduleGraph/types'
|
|
|
2
2
|
export declare function mergeLoadResults(...results: Array<PackageStyleLoadResult>): {
|
|
3
3
|
code: string;
|
|
4
4
|
watchFiles: string[];
|
|
5
|
+
cacheInputFiles: string[];
|
|
6
|
+
dependencyPackages: string[];
|
|
5
7
|
};
|
|
@@ -6,5 +6,7 @@ export function mergeLoadResults(...results) {
|
|
|
6
6
|
.filter((code) => code.trim())
|
|
7
7
|
.join('\n'),
|
|
8
8
|
watchFiles: Array.from(new Set(results.flatMap((result) => result.watchFiles))),
|
|
9
|
+
cacheInputFiles: Array.from(new Set(results.flatMap((result) => result.cacheInputFiles ?? []))),
|
|
10
|
+
dependencyPackages: Array.from(new Set(results.flatMap((result) => result.dependencyPackages ?? []))),
|
|
9
11
|
};
|
|
10
12
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PackageStyleLoadResult } from '#auklet/css/vite/moduleGraph/types';
|
|
2
|
+
export type PersistentStyleGraphCacheOptions = {
|
|
3
|
+
root: string;
|
|
4
|
+
};
|
|
5
|
+
export declare class PersistentStyleGraphCache {
|
|
6
|
+
private readonly cacheRoot;
|
|
7
|
+
constructor(options: PersistentStyleGraphCacheOptions);
|
|
8
|
+
createKey(value: unknown): string;
|
|
9
|
+
read(key: string): PackageStyleLoadResult | null;
|
|
10
|
+
write(key: string, result: PackageStyleLoadResult, inputFiles: Array<string>): void;
|
|
11
|
+
private getCacheFile;
|
|
12
|
+
private isFresh;
|
|
13
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { toPosixPath } from '#auklet/utils';
|
|
5
|
+
const cacheVersion = 'v1';
|
|
6
|
+
const stableStringify = (value) => {
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
return `[${value.map((item) => stableStringify(item)).join(',')}]`;
|
|
9
|
+
}
|
|
10
|
+
if (value && typeof value === 'object') {
|
|
11
|
+
return `{${Object.entries(value)
|
|
12
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
13
|
+
.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`)
|
|
14
|
+
.join(',')}}`;
|
|
15
|
+
}
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
};
|
|
18
|
+
const hashValue = (value) => {
|
|
19
|
+
return crypto
|
|
20
|
+
.createHash('sha256')
|
|
21
|
+
.update(stableStringify(value))
|
|
22
|
+
.digest('hex');
|
|
23
|
+
};
|
|
24
|
+
const hashFile = (file) => {
|
|
25
|
+
return crypto.createHash('md5').update(fs.readFileSync(file)).digest('hex');
|
|
26
|
+
};
|
|
27
|
+
const normalizeCachePath = (file) => {
|
|
28
|
+
return toPosixPath(path.resolve(file));
|
|
29
|
+
};
|
|
30
|
+
const normalizeRealpath = (file) => {
|
|
31
|
+
return toPosixPath(fs.realpathSync.native(file));
|
|
32
|
+
};
|
|
33
|
+
const statCachedFile = (file) => {
|
|
34
|
+
const resolved = path.resolve(file);
|
|
35
|
+
if (!fs.existsSync(resolved)) {
|
|
36
|
+
return {
|
|
37
|
+
file: normalizeCachePath(file),
|
|
38
|
+
exists: false,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const stat = fs.statSync(resolved);
|
|
42
|
+
if (stat.isDirectory()) {
|
|
43
|
+
return {
|
|
44
|
+
file: normalizeCachePath(file),
|
|
45
|
+
exists: true,
|
|
46
|
+
realpath: normalizeRealpath(resolved),
|
|
47
|
+
type: 'directory',
|
|
48
|
+
mtimeMs: stat.mtimeMs,
|
|
49
|
+
size: stat.size,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (!stat.isFile()) {
|
|
53
|
+
return {
|
|
54
|
+
file: normalizeCachePath(file),
|
|
55
|
+
exists: false,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
hash: hashFile(resolved),
|
|
60
|
+
file: normalizeCachePath(file),
|
|
61
|
+
exists: true,
|
|
62
|
+
realpath: normalizeRealpath(resolved),
|
|
63
|
+
type: 'file',
|
|
64
|
+
mtimeMs: stat.mtimeMs,
|
|
65
|
+
size: stat.size,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export class PersistentStyleGraphCache {
|
|
69
|
+
cacheRoot;
|
|
70
|
+
constructor(options) {
|
|
71
|
+
this.cacheRoot = path.join(options.root, 'node_modules', '.auklet', 'cache', 'vite-style', cacheVersion);
|
|
72
|
+
}
|
|
73
|
+
createKey(value) {
|
|
74
|
+
return hashValue({
|
|
75
|
+
cacheVersion,
|
|
76
|
+
value,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
read(key) {
|
|
80
|
+
const cacheFile = this.getCacheFile(key);
|
|
81
|
+
if (!fs.existsSync(cacheFile))
|
|
82
|
+
return null;
|
|
83
|
+
try {
|
|
84
|
+
const cached = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
|
85
|
+
if (cached.key !== key)
|
|
86
|
+
return null;
|
|
87
|
+
if (!this.isFresh(cached.files))
|
|
88
|
+
return null;
|
|
89
|
+
return cached.result;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
write(key, result, inputFiles) {
|
|
96
|
+
const files = Array.from(new Map(inputFiles
|
|
97
|
+
.map((file) => statCachedFile(file))
|
|
98
|
+
.map((file) => [file.file, file])).values());
|
|
99
|
+
try {
|
|
100
|
+
fs.mkdirSync(this.cacheRoot, { recursive: true });
|
|
101
|
+
fs.writeFileSync(this.getCacheFile(key), `${JSON.stringify({
|
|
102
|
+
files,
|
|
103
|
+
key,
|
|
104
|
+
result,
|
|
105
|
+
}, null, 2)}\n`);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Cache writes are an optimization; dev CSS generation must keep working.
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getCacheFile(key) {
|
|
112
|
+
return path.join(this.cacheRoot, `${key}.json`);
|
|
113
|
+
}
|
|
114
|
+
isFresh(files) {
|
|
115
|
+
for (const file of files) {
|
|
116
|
+
const current = statCachedFile(file.file);
|
|
117
|
+
if (current.exists !== file.exists)
|
|
118
|
+
return false;
|
|
119
|
+
if (!current.exists || !file.exists)
|
|
120
|
+
continue;
|
|
121
|
+
if (current.type !== file.type)
|
|
122
|
+
return false;
|
|
123
|
+
if (current.realpath !== file.realpath ||
|
|
124
|
+
current.size !== file.size ||
|
|
125
|
+
current.mtimeMs !== file.mtimeMs ||
|
|
126
|
+
toPosixPath(current.file) !== toPosixPath(file.file)) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
if (current.type === 'file' &&
|
|
130
|
+
file.type === 'file' &&
|
|
131
|
+
current.hash !== file.hash) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { ModuleStyleBuildConfig, NormalizedAukletConfig, ResolvedModuleStyl
|
|
|
3
3
|
import type { StyleProcessor } from '#auklet/css/core/styleProcessor';
|
|
4
4
|
import type { WorkspaceStyleResolver } from '#auklet/css/core/workspaceStyleResolver';
|
|
5
5
|
import type { StylePackageSource } from '#auklet/css/vite/moduleGraph/packageSource/types';
|
|
6
|
-
import type { LoadAukletConfig, PackageStyleId } from '#auklet/css/vite/moduleGraph/types';
|
|
6
|
+
import type { LoadAukletConfig, PackageStyleId, PackageStyleLoadResult } from '#auklet/css/vite/moduleGraph/types';
|
|
7
7
|
export type PackageStyleContext = {
|
|
8
8
|
normalizedConfig: NormalizedAukletConfig;
|
|
9
9
|
context: ResolvedModuleStyleBuildContext;
|
|
@@ -15,6 +15,8 @@ export type PackageStyleContext = {
|
|
|
15
15
|
styleProcessor: StyleProcessor;
|
|
16
16
|
};
|
|
17
17
|
export type ModuleStyleGraphRequestCacheOptions = {
|
|
18
|
+
root: string;
|
|
19
|
+
mode: 'monorepo' | 'package';
|
|
18
20
|
packageSource: StylePackageSource;
|
|
19
21
|
config: ModuleStyleBuildConfig;
|
|
20
22
|
loadAukletConfig?: LoadAukletConfig;
|
|
@@ -22,7 +24,10 @@ export type ModuleStyleGraphRequestCacheOptions = {
|
|
|
22
24
|
export declare class ModuleStyleGraphRequestCache {
|
|
23
25
|
private readonly options;
|
|
24
26
|
private readonly contexts;
|
|
27
|
+
private readonly loadResults;
|
|
28
|
+
private readonly loadResultDependencies;
|
|
25
29
|
private readonly loadAukletConfig;
|
|
30
|
+
private readonly persistentCache;
|
|
26
31
|
constructor(options: ModuleStyleGraphRequestCacheOptions);
|
|
27
32
|
getPackageNames(): string[];
|
|
28
33
|
isKnownPackageName(packageName: string): boolean;
|
|
@@ -62,5 +67,21 @@ export declare class ModuleStyleGraphRequestCache {
|
|
|
62
67
|
sourceRoot: string;
|
|
63
68
|
styleProcessor: StyleProcessor;
|
|
64
69
|
} | null>;
|
|
70
|
+
getLoadResult(parsed: PackageStyleId, create: () => Promise<PackageStyleLoadResult>): Promise<PackageStyleLoadResult>;
|
|
71
|
+
invalidatePackage(packageName: string): void;
|
|
72
|
+
readPersistentLoadResult(parsed: PackageStyleId, context: PackageStyleContext): PackageStyleLoadResult | null;
|
|
73
|
+
writePersistentLoadResult(parsed: PackageStyleId, context: PackageStyleContext, result: PackageStyleLoadResult): {
|
|
74
|
+
cacheInputFiles: string[];
|
|
75
|
+
code: string;
|
|
76
|
+
watchFiles: Array<string>;
|
|
77
|
+
dependencyPackages?: Array<string>;
|
|
78
|
+
};
|
|
65
79
|
private createContext;
|
|
80
|
+
private createPersistentKey;
|
|
81
|
+
private getPersistentInputFiles;
|
|
82
|
+
private getSourceInputFiles;
|
|
83
|
+
private getResolutionInputFiles;
|
|
84
|
+
private getLoadResultKey;
|
|
85
|
+
private getLoadResultPackageName;
|
|
86
|
+
private invalidateLoadResults;
|
|
66
87
|
}
|
|
@@ -2,13 +2,21 @@ import path from 'node:path';
|
|
|
2
2
|
import { loadAukletConfig, resolveAukletConfigPath, } from '#auklet/configLoader';
|
|
3
3
|
import { aukletConfigFiles, normalizeAukletConfig } from '#auklet/config';
|
|
4
4
|
import { StylePackageContext } from '#auklet/css/core/stylePackageContext';
|
|
5
|
+
import { PersistentStyleGraphCache } from '#auklet/css/vite/moduleGraph/persistentCache';
|
|
6
|
+
import { normalizeFileKey, toPosixPath } from '#auklet/utils';
|
|
5
7
|
export class ModuleStyleGraphRequestCache {
|
|
6
8
|
options;
|
|
7
9
|
contexts = new Map();
|
|
10
|
+
loadResults = new Map();
|
|
11
|
+
loadResultDependencies = new Map();
|
|
8
12
|
loadAukletConfig;
|
|
13
|
+
persistentCache;
|
|
9
14
|
constructor(options) {
|
|
10
15
|
this.options = options;
|
|
11
16
|
this.loadAukletConfig = options.loadAukletConfig ?? loadAukletConfig;
|
|
17
|
+
this.persistentCache = new PersistentStyleGraphCache({
|
|
18
|
+
root: options.root,
|
|
19
|
+
});
|
|
12
20
|
}
|
|
13
21
|
getPackageNames() {
|
|
14
22
|
return this.options.packageSource.getPackageNames();
|
|
@@ -24,6 +32,34 @@ export class ModuleStyleGraphRequestCache {
|
|
|
24
32
|
this.contexts.set(parsed.packageName, context);
|
|
25
33
|
return context;
|
|
26
34
|
}
|
|
35
|
+
getLoadResult(parsed, create) {
|
|
36
|
+
const key = this.getLoadResultKey(parsed);
|
|
37
|
+
const cachedResult = this.loadResults.get(key);
|
|
38
|
+
if (cachedResult)
|
|
39
|
+
return cachedResult;
|
|
40
|
+
const result = create().then((value) => {
|
|
41
|
+
this.loadResultDependencies.set(key, new Set(value.dependencyPackages ?? []));
|
|
42
|
+
return value;
|
|
43
|
+
});
|
|
44
|
+
this.loadResults.set(key, result);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
invalidatePackage(packageName) {
|
|
48
|
+
this.contexts.delete(packageName);
|
|
49
|
+
this.invalidateLoadResults(packageName);
|
|
50
|
+
}
|
|
51
|
+
readPersistentLoadResult(parsed, context) {
|
|
52
|
+
return this.persistentCache.read(this.createPersistentKey(parsed, context));
|
|
53
|
+
}
|
|
54
|
+
writePersistentLoadResult(parsed, context, result) {
|
|
55
|
+
const cacheInputFiles = this.getPersistentInputFiles(context, result);
|
|
56
|
+
const cacheResult = {
|
|
57
|
+
...result,
|
|
58
|
+
cacheInputFiles,
|
|
59
|
+
};
|
|
60
|
+
this.persistentCache.write(this.createPersistentKey(parsed, context), cacheResult, cacheInputFiles);
|
|
61
|
+
return cacheResult;
|
|
62
|
+
}
|
|
27
63
|
async createContext(parsed) {
|
|
28
64
|
const stylePackage = this.options.packageSource
|
|
29
65
|
.getPackages()
|
|
@@ -60,4 +96,93 @@ export class ModuleStyleGraphRequestCache {
|
|
|
60
96
|
styleProcessor: packageContext.styleProcessor,
|
|
61
97
|
};
|
|
62
98
|
}
|
|
99
|
+
createPersistentKey(parsed, context) {
|
|
100
|
+
return this.persistentCache.createKey({
|
|
101
|
+
config: this.options.config,
|
|
102
|
+
mode: this.options.mode,
|
|
103
|
+
normalizedConfig: context.normalizedConfig,
|
|
104
|
+
packageName: context.packageName,
|
|
105
|
+
packageNames: this.getPackageNames(),
|
|
106
|
+
packageRoot: normalizeFileKey(context.context.packageRoot),
|
|
107
|
+
parsed,
|
|
108
|
+
root: normalizeFileKey(this.options.root),
|
|
109
|
+
sourceFiles: context.packageContext.sourceFiles.map((file) => toPosixPath(path.relative(context.sourceRoot, file))),
|
|
110
|
+
sourceRoot: normalizeFileKey(context.sourceRoot),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
getPersistentInputFiles(context, result) {
|
|
114
|
+
return [
|
|
115
|
+
...result.watchFiles,
|
|
116
|
+
...(result.cacheInputFiles ?? []),
|
|
117
|
+
...this.getSourceInputFiles(context.sourceRoot, context.packageContext.sourceFiles),
|
|
118
|
+
...this.getResolutionInputFiles(context.context.packageRoot),
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
getSourceInputFiles(sourceRoot, sourceFiles) {
|
|
122
|
+
const sourceInputFiles = new Set([sourceRoot, ...sourceFiles]);
|
|
123
|
+
const normalizedSourceRoot = normalizeFileKey(sourceRoot);
|
|
124
|
+
for (const file of sourceFiles) {
|
|
125
|
+
let current = path.dirname(file);
|
|
126
|
+
while (true) {
|
|
127
|
+
sourceInputFiles.add(current);
|
|
128
|
+
if (normalizeFileKey(current) === normalizedSourceRoot)
|
|
129
|
+
break;
|
|
130
|
+
const parent = path.dirname(current);
|
|
131
|
+
if (parent === current)
|
|
132
|
+
break;
|
|
133
|
+
current = parent;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return Array.from(sourceInputFiles);
|
|
137
|
+
}
|
|
138
|
+
getResolutionInputFiles(packageRoot) {
|
|
139
|
+
const files = [path.join(packageRoot, 'package.json')];
|
|
140
|
+
let current = packageRoot;
|
|
141
|
+
const graphRoot = normalizeFileKey(this.options.root);
|
|
142
|
+
while (true) {
|
|
143
|
+
files.push(path.join(current, 'tsconfig.json'));
|
|
144
|
+
if (normalizeFileKey(current) === graphRoot)
|
|
145
|
+
break;
|
|
146
|
+
const parent = path.dirname(current);
|
|
147
|
+
if (parent === current)
|
|
148
|
+
break;
|
|
149
|
+
current = parent;
|
|
150
|
+
}
|
|
151
|
+
return files;
|
|
152
|
+
}
|
|
153
|
+
getLoadResultKey(parsed) {
|
|
154
|
+
return `${parsed.packageName}\0${parsed.stylePath}`;
|
|
155
|
+
}
|
|
156
|
+
getLoadResultPackageName(key) {
|
|
157
|
+
return key.split('\0')[0];
|
|
158
|
+
}
|
|
159
|
+
invalidateLoadResults(packageName) {
|
|
160
|
+
const invalidPackageNames = new Set([packageName]);
|
|
161
|
+
let changed = true;
|
|
162
|
+
while (changed) {
|
|
163
|
+
changed = false;
|
|
164
|
+
for (const [key, dependencyPackages] of this.loadResultDependencies) {
|
|
165
|
+
const resultPackageName = this.getLoadResultPackageName(key);
|
|
166
|
+
const shouldInvalidate = invalidPackageNames.has(resultPackageName) ||
|
|
167
|
+
Array.from(dependencyPackages).some((dependencyPackage) => invalidPackageNames.has(dependencyPackage));
|
|
168
|
+
if (!shouldInvalidate)
|
|
169
|
+
continue;
|
|
170
|
+
if (!invalidPackageNames.has(resultPackageName)) {
|
|
171
|
+
invalidPackageNames.add(resultPackageName);
|
|
172
|
+
changed = true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const key of this.loadResults.keys()) {
|
|
177
|
+
if (!invalidPackageNames.has(this.getLoadResultPackageName(key))) {
|
|
178
|
+
const dependencyPackages = this.loadResultDependencies.get(key);
|
|
179
|
+
if (!dependencyPackages ||
|
|
180
|
+
!Array.from(dependencyPackages).some((dependencyPackage) => invalidPackageNames.has(dependencyPackage))) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
this.loadResults.delete(key);
|
|
185
|
+
this.loadResultDependencies.delete(key);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
63
188
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import type { ModuleStyleBuildConfig } from '#auklet/types';
|
|
2
2
|
import type { ModuleStyleGraphRequestCache } from '#auklet/css/vite/moduleGraph/requestCache';
|
|
3
|
-
import type { PackageStyleId } from '#auklet/css/vite/moduleGraph/types';
|
|
3
|
+
import type { PackageStyleId, PackageStyleLoadResult } from '#auklet/css/vite/moduleGraph/types';
|
|
4
4
|
export declare class StyleCodeFactory {
|
|
5
5
|
private readonly config;
|
|
6
6
|
constructor(config: ModuleStyleBuildConfig);
|
|
7
|
-
createPackageStyleCode(parsed: PackageStyleId, cache: ModuleStyleGraphRequestCache): Promise<
|
|
8
|
-
|
|
9
|
-
watchFiles: string[];
|
|
10
|
-
}>;
|
|
7
|
+
createPackageStyleCode(parsed: PackageStyleId, cache: ModuleStyleGraphRequestCache): Promise<PackageStyleLoadResult>;
|
|
8
|
+
private createUncachedPackageStyleCode;
|
|
11
9
|
private createStyleCode;
|
|
12
10
|
private createDependencyStyleCode;
|
|
13
11
|
private createExternalStyleCode;
|
|
@@ -17,4 +15,5 @@ export declare class StyleCodeFactory {
|
|
|
17
15
|
private toDevModuleImportSpecifier;
|
|
18
16
|
private toDevExternalStyleSpecifier;
|
|
19
17
|
private parsePackageStyleIdInRequest;
|
|
18
|
+
private withDependencyPackage;
|
|
20
19
|
}
|
|
@@ -12,6 +12,9 @@ export class StyleCodeFactory {
|
|
|
12
12
|
this.config = config;
|
|
13
13
|
}
|
|
14
14
|
async createPackageStyleCode(parsed, cache) {
|
|
15
|
+
return cache.getLoadResult(parsed, () => this.createUncachedPackageStyleCode(parsed, cache));
|
|
16
|
+
}
|
|
17
|
+
async createUncachedPackageStyleCode(parsed, cache) {
|
|
15
18
|
const context = await cache.getContext(parsed);
|
|
16
19
|
if (!context) {
|
|
17
20
|
return {
|
|
@@ -19,21 +22,28 @@ export class StyleCodeFactory {
|
|
|
19
22
|
watchFiles: [],
|
|
20
23
|
};
|
|
21
24
|
}
|
|
25
|
+
const cachedResult = cache.readPersistentLoadResult(parsed, context);
|
|
26
|
+
if (cachedResult)
|
|
27
|
+
return cachedResult;
|
|
28
|
+
let result;
|
|
22
29
|
if (parsed.stylePath === STYLE_ENTRY) {
|
|
23
|
-
|
|
30
|
+
result = await this.createStyleCode(context, cache);
|
|
24
31
|
}
|
|
25
|
-
if (parsed.stylePath === EXTERNAL_ENTRY) {
|
|
26
|
-
|
|
32
|
+
else if (parsed.stylePath === EXTERNAL_ENTRY) {
|
|
33
|
+
result = await this.createExternalStyleCode(context, cache);
|
|
27
34
|
}
|
|
28
|
-
if (parsed.stylePath === MODULE_ENTRY) {
|
|
29
|
-
|
|
35
|
+
else if (parsed.stylePath === MODULE_ENTRY) {
|
|
36
|
+
result = this.createModuleStyleCode(context);
|
|
30
37
|
}
|
|
31
|
-
if (parsed.stylePath.startsWith(THEMES_ENTRY_PREFIX)) {
|
|
32
|
-
|
|
38
|
+
else if (parsed.stylePath.startsWith(THEMES_ENTRY_PREFIX)) {
|
|
39
|
+
result = await this.createThemeStyleCode(context, cache, [
|
|
33
40
|
removeStyleExtension(parsed.stylePath.slice(THEMES_ENTRY_PREFIX.length)),
|
|
34
41
|
]);
|
|
35
42
|
}
|
|
36
|
-
|
|
43
|
+
else {
|
|
44
|
+
result = await this.createSourceModuleStyleCode(context, cache, parsed.stylePath);
|
|
45
|
+
}
|
|
46
|
+
return cache.writePersistentLoadResult(parsed, context, result);
|
|
37
47
|
}
|
|
38
48
|
async createStyleCode(context, cache) {
|
|
39
49
|
const results = [];
|
|
@@ -58,7 +68,8 @@ export class StyleCodeFactory {
|
|
|
58
68
|
const outputSpecifier = mapSpecifier(specifier);
|
|
59
69
|
const parsed = this.parsePackageStyleIdInRequest(outputSpecifier, cache);
|
|
60
70
|
if (parsed) {
|
|
61
|
-
|
|
71
|
+
const result = await this.createPackageStyleCode(parsed, cache);
|
|
72
|
+
results.push(this.withDependencyPackage(result, parsed.packageName));
|
|
62
73
|
continue;
|
|
63
74
|
}
|
|
64
75
|
const resolvedSpecifier = toDevDependencyImportSpecifier(context, outputSpecifier);
|
|
@@ -137,7 +148,8 @@ export class StyleCodeFactory {
|
|
|
137
148
|
const result = this.toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir);
|
|
138
149
|
const parsed = this.parsePackageStyleIdInRequest(result, cache);
|
|
139
150
|
if (parsed) {
|
|
140
|
-
|
|
151
|
+
const loadResult = await this.createPackageStyleCode(parsed, cache);
|
|
152
|
+
moduleStyleResults.push(this.withDependencyPackage(loadResult, parsed.packageName));
|
|
141
153
|
continue;
|
|
142
154
|
}
|
|
143
155
|
const resolvedSpecifier = toDevDependencyImportSpecifier(context, result);
|
|
@@ -190,4 +202,10 @@ export class StyleCodeFactory {
|
|
|
190
202
|
parsePackageStyleIdInRequest(id, cache) {
|
|
191
203
|
return parsePackageStyleId(id, cache.getPackageNames());
|
|
192
204
|
}
|
|
205
|
+
withDependencyPackage(result, packageName) {
|
|
206
|
+
return {
|
|
207
|
+
...result,
|
|
208
|
+
dependencyPackages: Array.from(new Set([packageName, ...(result.dependencyPackages ?? [])])),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
193
211
|
}
|
|
@@ -11,7 +11,9 @@ export type PackageStyleId = {
|
|
|
11
11
|
};
|
|
12
12
|
export type PackageStyleLoadResult = {
|
|
13
13
|
code: string;
|
|
14
|
+
cacheInputFiles?: Array<string>;
|
|
14
15
|
watchFiles: Array<string>;
|
|
16
|
+
dependencyPackages?: Array<string>;
|
|
15
17
|
};
|
|
16
18
|
export type LoadAukletConfig = (packageRoot: string, options?: {
|
|
17
19
|
cacheBust?: boolean;
|
|
@@ -106,6 +106,7 @@ export function aukletStylePlugin(options = {}) {
|
|
|
106
106
|
const invalidateStyleGraph = (file) => {
|
|
107
107
|
if (!graph.isSourceGraphFile(file))
|
|
108
108
|
return false;
|
|
109
|
+
graph.invalidateFile(file);
|
|
109
110
|
invalidateVirtualModules(server, graph);
|
|
110
111
|
return true;
|
|
111
112
|
};
|
|
@@ -116,7 +117,7 @@ export function aukletStylePlugin(options = {}) {
|
|
|
116
117
|
};
|
|
117
118
|
const handleSourceAddOrUnlink = (file) => {
|
|
118
119
|
if (graph.isStyleFile(file)) {
|
|
119
|
-
|
|
120
|
+
reloadStyleGraph(file);
|
|
120
121
|
return;
|
|
121
122
|
}
|
|
122
123
|
reloadStyleGraph(file);
|
|
@@ -126,6 +127,10 @@ export function aukletStylePlugin(options = {}) {
|
|
|
126
127
|
server.watcher.on('change', (file) => {
|
|
127
128
|
if (graph.isStyleConfigFile(file)) {
|
|
128
129
|
reloadStyleGraph(file);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (graph.isSourceModuleFile(file)) {
|
|
133
|
+
hmr.handleSourceModuleChange(server, file);
|
|
129
134
|
}
|
|
130
135
|
});
|
|
131
136
|
},
|