auklet 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,7 @@ export declare class StyleProcessor {
23
23
  private throwMissingLocalStyleImport;
24
24
  collectImportedStyleFiles(styleFiles: Array<string>): Set<string>;
25
25
  collectImportedStyleFileReferences(styleFiles: Array<string>): StyleFileImportReference[];
26
+ collectStyleImportReferences(styleFiles: Array<string>): StyleFileImportReference[];
26
27
  collectStyleImportSpecifiers(styleFiles: Array<string>): Set<string>;
27
28
  assertNoLocalStyleImportCycles(styleFiles: Array<string>): void;
28
29
  assertNoSourceRootEscapingLocalStyleImports(styleFiles: Array<string>): void;
@@ -98,6 +98,21 @@ export class StyleProcessor {
98
98
  }
99
99
  return imports;
100
100
  }
101
+ collectStyleImportReferences(styleFiles) {
102
+ const imports = [];
103
+ for (const styleFile of styleFiles) {
104
+ const css = fs.readFileSync(styleFile, 'utf8');
105
+ const root = this.parse(css, styleFile);
106
+ root.walkAtRules('import', (rule) => {
107
+ const specifier = this.parseImportSpecifier(rule.params);
108
+ if (!specifier)
109
+ return;
110
+ const { reference } = this.resolveStyleImportReference(specifier, styleFile);
111
+ imports.push(reference);
112
+ });
113
+ }
114
+ return imports;
115
+ }
101
116
  collectStyleImportSpecifiers(styleFiles) {
102
117
  const specifiers = new Set();
103
118
  for (const styleFile of styleFiles) {
@@ -1,5 +1,6 @@
1
1
  import type { HotUpdateOptions, ViteDevServer } from 'vite';
2
2
  import type { ModuleStyleGraph } from '#auklet/css/vite/moduleGraph/graph';
3
+ type TrackedVirtualStyleFileKind = 'entry' | 'dependency';
3
4
  export type AukletStyleHmrOptions = {
4
5
  pruneDelayMs?: number;
5
6
  };
@@ -12,8 +13,11 @@ export declare class AukletStyleHmr {
12
13
  private readonly schedulePruneStaleVirtualDependencies;
13
14
  private readonly pruneDelayMs;
14
15
  constructor(graph: () => ModuleStyleGraph, options?: AukletStyleHmrOptions);
15
- trackVirtualStyleDependency(file: string, virtualId: string): void;
16
- replaceVirtualStyleDependency(virtualId: string, files: Array<string>): void;
16
+ trackVirtualStyleDependency(file: string, virtualId: string, kind?: TrackedVirtualStyleFileKind): void;
17
+ replaceVirtualStyleDependency(virtualId: string, files: Array<string>, fileKinds?: Array<{
18
+ file: string;
19
+ kind: TrackedVirtualStyleFileKind;
20
+ }>): void;
17
21
  hasTrackedStyleDependency(file: string, moduleGraph?: Pick<ViteDevServer['moduleGraph'], 'getModuleById'>): boolean;
18
22
  pruneStaleVirtualDependencies(moduleGraph: Pick<ViteDevServer['moduleGraph'], 'getModuleById'>): void;
19
23
  scheduleStaleVirtualDependencyPrune(moduleGraph: Pick<ViteDevServer['moduleGraph'], 'getModuleById'>): void;
@@ -21,13 +25,18 @@ export declare class AukletStyleHmr {
21
25
  installFullReloadGuard(server: Pick<ViteDevServer, 'ws'>): void;
22
26
  handleStyleHotUpdate(context: HotUpdateOptions): Promise<never[] | undefined>;
23
27
  handleSourceModuleChange(server: Pick<ViteDevServer, 'moduleGraph' | 'ws'>, file: string): Promise<boolean>;
24
- private sendVirtualStyleUpdates;
25
28
  private parseTrackedVirtualIds;
29
+ private createTrackedVirtualStyleUpdates;
30
+ private invalidateTrackedVirtualPackages;
26
31
  private getDependencyVirtualIds;
27
- private parseTrackedVirtualId;
32
+ private getTrackedStyleFileEntries;
28
33
  private createTrackedVirtualStyleResults;
29
- private refreshSourceModuleUpdates;
34
+ private parseTrackedVirtualId;
35
+ private parseTrackedVirtualIdWithKind;
36
+ private refreshTrackedVirtualStyleUpdates;
37
+ private sameStyleLoadResult;
30
38
  private suppressFullReload;
31
39
  private shouldSuppressFullReload;
32
40
  private isDuplicateUpdate;
33
41
  }
42
+ export {};
@@ -12,13 +12,15 @@ const toBrowserVirtualPath = (id) => {
12
12
  const getRelativeFile = (file) => {
13
13
  return path.relative(process.cwd(), file);
14
14
  };
15
- const addVirtualStyleDependency = (virtualIdsByDependency, filesByVirtualId, file, virtualId) => {
15
+ const addVirtualStyleDependency = (virtualIdsByDependency, filesByVirtualId, file, virtualId, kind) => {
16
16
  const normalizedFile = normalizeFileKey(file);
17
17
  const values = virtualIdsByDependency.get(normalizedFile) ?? new Set();
18
18
  values.add(virtualId);
19
19
  virtualIdsByDependency.set(normalizedFile, values);
20
- const files = filesByVirtualId.get(virtualId) ?? new Set();
21
- files.add(normalizedFile);
20
+ const files = filesByVirtualId.get(virtualId) ??
21
+ new Map();
22
+ const previousKind = files.get(normalizedFile);
23
+ files.set(normalizedFile, previousKind === 'entry' || kind === 'entry' ? 'entry' : kind);
22
24
  filesByVirtualId.set(virtualId, files);
23
25
  };
24
26
  const removeVirtualStyleDependency = (virtualIdsByDependency, filesByVirtualId, file, virtualId) => {
@@ -72,19 +74,20 @@ export class AukletStyleHmr {
72
74
  this.pruneDelayMs = options.pruneDelayMs ?? 2 * 60 * 1000;
73
75
  this.schedulePruneStaleVirtualDependencies = throttle(this.pruneDelayMs, (moduleGraph) => this.pruneStaleVirtualDependencies(moduleGraph));
74
76
  }
75
- trackVirtualStyleDependency(file, virtualId) {
76
- addVirtualStyleDependency(this.virtualIdsByDependency, this.filesByVirtualId, file, virtualId);
77
+ trackVirtualStyleDependency(file, virtualId, kind = 'dependency') {
78
+ addVirtualStyleDependency(this.virtualIdsByDependency, this.filesByVirtualId, file, virtualId, kind);
77
79
  }
78
- replaceVirtualStyleDependency(virtualId, files) {
80
+ replaceVirtualStyleDependency(virtualId, files, fileKinds = []) {
79
81
  const normalizedFiles = new Set(files.map((file) => normalizeFileKey(file)));
80
- const previousFiles = this.filesByVirtualId.get(virtualId) ?? new Set();
81
- for (const file of previousFiles) {
82
+ const previousFiles = this.filesByVirtualId.get(virtualId) ?? new Map();
83
+ const nextKinds = new Map(fileKinds.map((item) => [normalizeFileKey(item.file), item.kind]));
84
+ for (const file of previousFiles.keys()) {
82
85
  if (normalizedFiles.has(file))
83
86
  continue;
84
87
  removeVirtualStyleDependency(this.virtualIdsByDependency, this.filesByVirtualId, file, virtualId);
85
88
  }
86
89
  for (const file of normalizedFiles) {
87
- addVirtualStyleDependency(this.virtualIdsByDependency, this.filesByVirtualId, file, virtualId);
90
+ addVirtualStyleDependency(this.virtualIdsByDependency, this.filesByVirtualId, file, virtualId, nextKinds.get(file) ?? 'dependency');
88
91
  }
89
92
  }
90
93
  hasTrackedStyleDependency(file, moduleGraph) {
@@ -123,20 +126,52 @@ export class AukletStyleHmr {
123
126
  }
124
127
  async handleStyleHotUpdate(context) {
125
128
  const graph = this.graph();
126
- if (!graph.isSourceGraphFile(context.file) ||
127
- !graph.isStyleFile(context.file)) {
128
- return;
129
+ if (!graph.isStyleFile(context.file)) {
130
+ return undefined;
131
+ }
132
+ const isSourceGraphFile = graph.isSourceGraphFile(context.file);
133
+ const trackedEntries = this.getTrackedStyleFileEntries(context.file, context.server.moduleGraph);
134
+ if (!trackedEntries.length) {
135
+ if (isSourceGraphFile) {
136
+ graph.invalidateFile(context.file);
137
+ }
138
+ return undefined;
139
+ }
140
+ const entryEntries = isSourceGraphFile
141
+ ? trackedEntries.filter((item) => item.kind === 'entry')
142
+ : [];
143
+ const dependencyEntries = isSourceGraphFile
144
+ ? trackedEntries.filter((item) => item.kind === 'dependency')
145
+ : trackedEntries;
146
+ const previousResults = entryEntries.length
147
+ ? this.createTrackedVirtualStyleResults(graph, entryEntries)
148
+ : null;
149
+ if (isSourceGraphFile) {
150
+ graph.invalidateFile(context.file);
151
+ }
152
+ else {
153
+ this.invalidateTrackedVirtualPackages(graph, dependencyEntries);
129
154
  }
130
- this.suppressFullReload();
131
- graph.invalidateFile(context.file);
132
155
  if (this.isDuplicateUpdate(context.file)) {
133
156
  return [];
134
157
  }
135
- const updates = this.sendVirtualStyleUpdates(context.file, context.server, context.timestamp);
136
- if (!updates.sent) {
137
- return [];
158
+ const updates = [
159
+ ...(dependencyEntries.length
160
+ ? this.createTrackedVirtualStyleUpdates(context.server, dependencyEntries, context.timestamp)
161
+ : []),
162
+ ...(entryEntries.length
163
+ ? await this.refreshTrackedVirtualStyleUpdates(context.server, entryEntries, previousResults, context.timestamp)
164
+ : []),
165
+ ];
166
+ if (!updates.length) {
167
+ return undefined;
138
168
  }
139
- logger.info(`package css hmr ${getRelativeFile(context.file)} tracked=${updates.tracked} updates=${updates.sent}`);
169
+ this.suppressFullReload();
170
+ context.server.ws.send({
171
+ type: 'update',
172
+ updates,
173
+ });
174
+ logger.info(`package css hmr ${getRelativeFile(context.file)} tracked=${trackedEntries.length} updates=${updates.length}`);
140
175
  return [];
141
176
  }
142
177
  async handleSourceModuleChange(server, file) {
@@ -156,37 +191,39 @@ export class AukletStyleHmr {
156
191
  }
157
192
  const previousResults = this.createTrackedVirtualStyleResults(graph, parsedVirtualIds);
158
193
  graph.invalidateFile(file);
159
- const updates = await this.refreshSourceModuleUpdates(server, parsedVirtualIds, previousResults);
160
- if (!updates.sent) {
194
+ const updates = await this.refreshTrackedVirtualStyleUpdates(server, parsedVirtualIds, previousResults, Date.now());
195
+ if (!updates.length) {
161
196
  return false;
162
197
  }
163
- logger.info(`package css source hmr ${getRelativeFile(file)} tracked=${updates.tracked} updates=${updates.sent}`);
164
- return updates.sent > 0;
198
+ this.suppressFullReload();
199
+ server.ws.send({
200
+ type: 'update',
201
+ updates,
202
+ });
203
+ logger.info(`package css source hmr ${getRelativeFile(file)} tracked=${parsedVirtualIds.length} updates=${updates.length}`);
204
+ return true;
165
205
  }
166
- sendVirtualStyleUpdates(file, server, timestamp) {
167
- const virtualIds = this.getDependencyVirtualIds(file, server.moduleGraph);
168
- for (const id of virtualIds) {
169
- const module = server.moduleGraph.getModuleById(id);
206
+ parseTrackedVirtualIds(graph, virtualIds) {
207
+ return virtualIds
208
+ .map((id) => this.parseTrackedVirtualId(graph, id))
209
+ .filter((item) => item !== null);
210
+ }
211
+ createTrackedVirtualStyleUpdates(server, parsedVirtualIds, timestamp) {
212
+ const changedVirtualIds = [];
213
+ for (const item of parsedVirtualIds) {
214
+ changedVirtualIds.push(item.id);
215
+ const module = server.moduleGraph.getModuleById(item.id);
170
216
  if (module) {
171
217
  server.moduleGraph.invalidateModule(module);
172
218
  }
173
219
  }
174
- const updates = createJsUpdates(virtualIds, timestamp);
175
- if (updates.length) {
176
- server.ws.send({
177
- type: 'update',
178
- updates,
179
- });
180
- }
181
- return {
182
- sent: updates.length,
183
- tracked: virtualIds.length,
184
- };
220
+ return createJsUpdates(changedVirtualIds, timestamp);
185
221
  }
186
- parseTrackedVirtualIds(graph, virtualIds) {
187
- return virtualIds
188
- .map((id) => this.parseTrackedVirtualId(graph, id))
189
- .filter((item) => Boolean(item));
222
+ invalidateTrackedVirtualPackages(graph, parsedVirtualIds) {
223
+ const packageNames = new Set(parsedVirtualIds.map((item) => item.parsed.packageName));
224
+ for (const packageName of packageNames) {
225
+ graph.invalidatePackage(packageName);
226
+ }
190
227
  }
191
228
  getDependencyVirtualIds(file, moduleGraph) {
192
229
  const normalizedFile = normalizeFileKey(file);
@@ -205,6 +242,32 @@ export class AukletStyleHmr {
205
242
  }
206
243
  return liveVirtualIds;
207
244
  }
245
+ getTrackedStyleFileEntries(file, moduleGraph) {
246
+ const normalizedFile = normalizeFileKey(file);
247
+ const virtualIds = Array.from(this.virtualIdsByDependency.get(normalizedFile) ?? []);
248
+ const entries = virtualIds
249
+ .map((id) => this.parseTrackedVirtualIdWithKind(id, normalizedFile, moduleGraph))
250
+ .filter((item) => Boolean(item));
251
+ if (!moduleGraph) {
252
+ return entries;
253
+ }
254
+ if (entries.length !== virtualIds.length) {
255
+ const liveSet = new Set(entries.map((item) => item.id));
256
+ for (const virtualId of virtualIds) {
257
+ if (liveSet.has(virtualId))
258
+ continue;
259
+ removeVirtualStyleDependency(this.virtualIdsByDependency, this.filesByVirtualId, normalizedFile, virtualId);
260
+ }
261
+ }
262
+ return entries;
263
+ }
264
+ createTrackedVirtualStyleResults(graph, parsedVirtualIds) {
265
+ const previousResults = new Map();
266
+ for (const item of parsedVirtualIds) {
267
+ previousResults.set(item.id, graph.peekPackageStyleCode(item.parsed));
268
+ }
269
+ return previousResults;
270
+ }
208
271
  parseTrackedVirtualId(graph, id) {
209
272
  const parsedId = id.startsWith(RESOLVED_VIRTUAL_ID_PREFIX)
210
273
  ? id.slice(RESOLVED_VIRTUAL_ID_PREFIX.length)
@@ -216,24 +279,30 @@ export class AukletStyleHmr {
216
279
  return {
217
280
  id,
218
281
  parsed,
282
+ kind: 'dependency',
219
283
  };
220
284
  }
221
- createTrackedVirtualStyleResults(graph, parsedVirtualIds) {
222
- const previousResults = new Map();
223
- for (const item of parsedVirtualIds) {
224
- previousResults.set(item.id, graph.peekPackageStyleCode(item.parsed));
285
+ parseTrackedVirtualIdWithKind(id, normalizedFile, moduleGraph) {
286
+ if (moduleGraph && !moduleGraph.getModuleById(id)) {
287
+ return null;
225
288
  }
226
- return previousResults;
289
+ const parsed = this.parseTrackedVirtualId(this.graph(), id);
290
+ if (!parsed)
291
+ return null;
292
+ const kind = this.filesByVirtualId.get(id)?.get(normalizedFile) ?? 'dependency';
293
+ return {
294
+ ...parsed,
295
+ kind,
296
+ };
227
297
  }
228
- async refreshSourceModuleUpdates(server, parsedVirtualIds, previousResults) {
298
+ async refreshTrackedVirtualStyleUpdates(server, parsedVirtualIds, previousResults, timestamp) {
229
299
  const graph = this.graph();
230
300
  const changedVirtualIds = [];
231
301
  for (const item of parsedVirtualIds) {
232
302
  const nextResult = await graph.createPackageStyleCode(item.parsed);
233
303
  const previousResult = previousResults.get(item.id);
234
304
  if (!previousResult ||
235
- previousResult.code !== nextResult.code ||
236
- !sameStringSets(previousResult.watchFiles, nextResult.watchFiles)) {
305
+ !this.sameStyleLoadResult(previousResult, nextResult)) {
237
306
  changedVirtualIds.push(item.id);
238
307
  const module = server.moduleGraph.getModuleById(item.id);
239
308
  if (module) {
@@ -241,17 +310,12 @@ export class AukletStyleHmr {
241
310
  }
242
311
  }
243
312
  }
244
- const updates = createJsUpdates(changedVirtualIds, Date.now());
245
- if (updates.length) {
246
- server.ws.send({
247
- type: 'update',
248
- updates,
249
- });
250
- }
251
- return {
252
- sent: updates.length,
253
- tracked: parsedVirtualIds.length,
254
- };
313
+ return createJsUpdates(changedVirtualIds, timestamp);
314
+ }
315
+ sameStyleLoadResult(left, right) {
316
+ return (left.code === right.code &&
317
+ sameStringSets(left.watchFiles, right.watchFiles) &&
318
+ sameStringSets(left.dependencyPackages ?? [], right.dependencyPackages ?? []));
255
319
  }
256
320
  suppressFullReload() {
257
321
  this.suppressFullReloadUntil = Date.now() + FULL_RELOAD_SUPPRESS_MS;
@@ -4,4 +4,8 @@ export declare function mergeLoadResults(...results: Array<PackageStyleLoadResul
4
4
  watchFiles: string[];
5
5
  cacheInputFiles: string[];
6
6
  dependencyPackages: string[];
7
+ watchFileKinds: {
8
+ file: string;
9
+ kind: "dependency" | "entry";
10
+ }[];
7
11
  };
@@ -1,5 +1,15 @@
1
1
  // 合并递归 style graph 加载结果,同时保留 CSS 顺序并去重 watch files。
2
2
  export function mergeLoadResults(...results) {
3
+ const watchFileKinds = new Map();
4
+ for (const result of results) {
5
+ for (const item of result.watchFileKinds ?? []) {
6
+ const currentKind = watchFileKinds.get(item.file);
7
+ if (currentKind === 'entry' || item.kind === currentKind) {
8
+ continue;
9
+ }
10
+ watchFileKinds.set(item.file, item.kind === 'entry' ? 'entry' : (currentKind ?? item.kind));
11
+ }
12
+ }
3
13
  return {
4
14
  code: results
5
15
  .map((result) => result.code)
@@ -8,5 +18,9 @@ export function mergeLoadResults(...results) {
8
18
  watchFiles: Array.from(new Set(results.flatMap((result) => result.watchFiles))),
9
19
  cacheInputFiles: Array.from(new Set(results.flatMap((result) => result.cacheInputFiles ?? []))),
10
20
  dependencyPackages: Array.from(new Set(results.flatMap((result) => result.dependencyPackages ?? []))),
21
+ watchFileKinds: Array.from(watchFileKinds, ([file, kind]) => ({
22
+ file,
23
+ kind,
24
+ })),
11
25
  };
12
26
  }
@@ -30,7 +30,9 @@ export declare class ModuleStyleGraphRequestCache {
30
30
  private readonly contexts;
31
31
  private readonly loadResults;
32
32
  private readonly settledLoadResults;
33
+ private readonly loadResultsByPackage;
33
34
  private readonly loadResultDependencies;
35
+ private readonly loadResultDependents;
34
36
  private readonly loadResultVersions;
35
37
  private readonly loadAukletConfig;
36
38
  private readonly persistentCache;
@@ -82,6 +84,7 @@ export declare class ModuleStyleGraphRequestCache {
82
84
  cacheInputFiles: string[];
83
85
  code: string;
84
86
  watchFiles: Array<string>;
87
+ watchFileKinds?: Array<import("#auklet/css/vite/moduleGraph/types").PackageStyleWatchFile>;
85
88
  dependencyPackages?: Array<string>;
86
89
  };
87
90
  private createContext;
@@ -99,5 +102,8 @@ export declare class ModuleStyleGraphRequestCache {
99
102
  private getGraphVersion;
100
103
  private bumpGraphVersion;
101
104
  private bumpLoadResultVersion;
105
+ private addLoadResultKey;
106
+ private deleteLoadResultKey;
107
+ private replaceLoadResultDependencies;
102
108
  }
103
109
  export {};
@@ -9,7 +9,9 @@ export class ModuleStyleGraphRequestCache {
9
9
  contexts = new Map();
10
10
  loadResults = new Map();
11
11
  settledLoadResults = new Map();
12
+ loadResultsByPackage = new Map();
12
13
  loadResultDependencies = new Map();
14
+ loadResultDependents = new Map();
13
15
  loadResultVersions = new Map();
14
16
  loadAukletConfig;
15
17
  persistentCache;
@@ -41,6 +43,7 @@ export class ModuleStyleGraphRequestCache {
41
43
  if (cachedResult)
42
44
  return cachedResult;
43
45
  const version = this.bumpLoadResultVersion(key);
46
+ this.addLoadResultKey(this.loadResultsByPackage, parsed.packageName, key);
44
47
  const graphVersion = this.getGraphVersion();
45
48
  let result;
46
49
  result = create()
@@ -54,7 +57,7 @@ export class ModuleStyleGraphRequestCache {
54
57
  return this.getLoadResult(parsed, create);
55
58
  }
56
59
  if (this.loadResultVersions.get(key) === version) {
57
- this.loadResultDependencies.set(key, new Set(entry.result.dependencyPackages ?? []));
60
+ this.replaceLoadResultDependencies(key, entry.result.dependencyPackages ?? []);
58
61
  }
59
62
  try {
60
63
  const committedResult = entry.commit?.();
@@ -226,39 +229,46 @@ export class ModuleStyleGraphRequestCache {
226
229
  return key.split('\0')[0];
227
230
  }
228
231
  invalidateLoadResults(packageName) {
229
- const invalidPackageNames = new Set([packageName]);
230
- let changed = true;
231
- while (changed) {
232
- changed = false;
233
- for (const [key, dependencyPackages] of this.loadResultDependencies) {
234
- const resultPackageName = this.getLoadResultPackageName(key);
235
- const shouldInvalidate = invalidPackageNames.has(resultPackageName) ||
236
- Array.from(dependencyPackages).some((dependencyPackage) => invalidPackageNames.has(dependencyPackage));
237
- if (!shouldInvalidate)
238
- continue;
239
- if (!invalidPackageNames.has(resultPackageName)) {
240
- invalidPackageNames.add(resultPackageName);
241
- changed = true;
242
- }
243
- }
244
- }
245
- for (const key of this.loadResults.keys()) {
246
- if (!invalidPackageNames.has(this.getLoadResultPackageName(key))) {
247
- const dependencyPackages = this.loadResultDependencies.get(key);
248
- if (!dependencyPackages ||
249
- !Array.from(dependencyPackages).some((dependencyPackage) => invalidPackageNames.has(dependencyPackage))) {
232
+ const pendingKeys = [
233
+ ...(this.loadResultsByPackage.get(packageName) ?? []),
234
+ ...(this.loadResultDependents.get(packageName) ?? []),
235
+ ];
236
+ const processedKeys = new Set();
237
+ while (pendingKeys.length) {
238
+ const key = pendingKeys.pop();
239
+ if (!key || processedKeys.has(key))
240
+ continue;
241
+ processedKeys.add(key);
242
+ const dependentPackageName = this.discardLoadResult(key);
243
+ if (!dependentPackageName)
244
+ continue;
245
+ for (const dependentKey of Array.from(this.loadResultDependents.get(dependentPackageName) ?? [])) {
246
+ if (processedKeys.has(dependentKey))
250
247
  continue;
251
- }
248
+ pendingKeys.push(dependentKey);
252
249
  }
253
- this.discardLoadResult(key);
254
250
  }
255
251
  }
256
252
  discardLoadResult(key) {
253
+ const packageName = this.getLoadResultPackageName(key);
254
+ const dependencyPackages = this.loadResultDependencies.get(key);
255
+ const settledResult = this.loadResults.get(key) ?? null;
256
+ if (!settledResult &&
257
+ !dependencyPackages &&
258
+ !this.settledLoadResults.has(key)) {
259
+ return null;
260
+ }
257
261
  this.bumpGraphVersion();
258
262
  this.bumpLoadResultVersion(key);
259
263
  this.loadResults.delete(key);
260
- this.loadResultDependencies.delete(key);
261
264
  this.settledLoadResults.delete(key);
265
+ this.deleteLoadResultKey(this.loadResultsByPackage, packageName, key);
266
+ const previousDependencies = dependencyPackages ?? new Set();
267
+ for (const dependencyPackage of previousDependencies) {
268
+ this.deleteLoadResultKey(this.loadResultDependents, dependencyPackage, key);
269
+ }
270
+ this.loadResultDependencies.delete(key);
271
+ return packageName;
262
272
  }
263
273
  peekLoadResult(parsed) {
264
274
  return this.settledLoadResults.get(this.getLoadResultKey(parsed)) ?? null;
@@ -275,4 +285,33 @@ export class ModuleStyleGraphRequestCache {
275
285
  this.loadResultVersions.set(key, nextVersion);
276
286
  return nextVersion;
277
287
  }
288
+ addLoadResultKey(map, key, value) {
289
+ const values = map.get(key) ?? new Set();
290
+ values.add(value);
291
+ map.set(key, values);
292
+ }
293
+ deleteLoadResultKey(map, key, value) {
294
+ const values = map.get(key);
295
+ if (!values)
296
+ return;
297
+ values.delete(value);
298
+ if (!values.size) {
299
+ map.delete(key);
300
+ }
301
+ }
302
+ replaceLoadResultDependencies(key, dependencyPackages) {
303
+ const nextDependencies = new Set(dependencyPackages);
304
+ const previousDependencies = this.loadResultDependencies.get(key);
305
+ if (previousDependencies) {
306
+ for (const dependencyPackage of previousDependencies) {
307
+ if (nextDependencies.has(dependencyPackage))
308
+ continue;
309
+ this.deleteLoadResultKey(this.loadResultDependents, dependencyPackage, key);
310
+ }
311
+ }
312
+ this.loadResultDependencies.set(key, nextDependencies);
313
+ for (const dependencyPackage of nextDependencies) {
314
+ this.addLoadResultKey(this.loadResultDependents, dependencyPackage, key);
315
+ }
316
+ }
278
317
  }
@@ -14,6 +14,7 @@ export declare class StyleCodeFactory {
14
14
  private createModuleStyleCode;
15
15
  private createSourceModuleStyleCode;
16
16
  private createOwnSourceStyleCode;
17
+ private collectSourceStyleWatchFiles;
17
18
  private toDevModuleImportSpecifier;
18
19
  private toDevExternalStyleSpecifier;
19
20
  private parsePackageStyleIdInRequest;
@@ -1,3 +1,4 @@
1
+ import fs from 'node:fs';
1
2
  import path from 'node:path';
2
3
  import postcss from 'postcss';
3
4
  import { mergeLoadResults } from '#auklet/css/vite/moduleGraph/loadResult';
@@ -166,7 +167,7 @@ export class StyleCodeFactory {
166
167
  async createSourceModuleStyleCode(context, cache, stylePath) {
167
168
  context.packageContext.assertPreservedLocalStyleImports();
168
169
  const sourceModuleDir = removeStyleExtension(stylePath);
169
- const { styleFiles, sourceFiles } = context.packageContext;
170
+ const { sourceFiles } = context.packageContext;
170
171
  const entry = createModuleStyleEntryPlan(context.packageContext, sourceModuleDir);
171
172
  const sourceStyleDir = path.join(context.sourceRoot, sourceModuleDir, this.config.output.styleDir);
172
173
  const moduleStyleResults = [];
@@ -189,16 +190,31 @@ export class StyleCodeFactory {
189
190
  }
190
191
  }
191
192
  const ownStyleCode = this.createOwnSourceStyleCode(context, entry.ownStyleFiles);
193
+ const sourceWatchFiles = this.collectSourceStyleWatchFiles(context, entry.ownStyleFiles);
192
194
  return mergeLoadResults(...moduleStyleResults, {
193
195
  code: [createImportCode(moduleStyleSpecifiers), ownStyleCode]
194
196
  .filter((code) => code.trim())
195
197
  .join('\n'),
196
198
  watchFiles: [
197
199
  ...context.configPaths,
198
- ...styleFiles,
200
+ ...sourceWatchFiles.map((item) => item.file),
199
201
  ...moduleStyleWatchFiles,
200
202
  ...sourceFiles.filter((file) => /\.(ts|tsx)$/.test(file)),
201
203
  ],
204
+ watchFileKinds: [
205
+ ...context.configPaths.map((file) => ({
206
+ file,
207
+ kind: 'dependency',
208
+ })),
209
+ ...sourceWatchFiles,
210
+ ...moduleStyleWatchFiles.map((file) => ({
211
+ file,
212
+ kind: 'dependency',
213
+ })),
214
+ ...sourceFiles
215
+ .filter((file) => /\.(ts|tsx)$/.test(file))
216
+ .map((file) => ({ file, kind: 'dependency' })),
217
+ ],
202
218
  cacheInputFiles: moduleStyleCacheInputFiles,
203
219
  });
204
220
  }
@@ -220,6 +236,42 @@ export class StyleCodeFactory {
220
236
  }
221
237
  return root.nodes?.length ? context.styleProcessor.stringify(root) : '';
222
238
  }
239
+ collectSourceStyleWatchFiles(context, styleFiles) {
240
+ const watchFiles = new Map();
241
+ const pending = styleFiles.map((file) => ({
242
+ file,
243
+ kind: 'entry',
244
+ }));
245
+ const visited = new Set();
246
+ while (pending.length) {
247
+ const current = pending.pop();
248
+ if (!current)
249
+ continue;
250
+ const styleFile = current.file;
251
+ const normalized = path.resolve(styleFile);
252
+ if (visited.has(normalized))
253
+ continue;
254
+ visited.add(normalized);
255
+ const previousKind = watchFiles.get(normalized);
256
+ watchFiles.set(normalized, previousKind === 'entry' || current.kind === 'entry'
257
+ ? 'entry'
258
+ : 'dependency');
259
+ for (const reference of context.styleProcessor.collectStyleImportReferences([normalized])) {
260
+ if (!context.resolver.isStyleFile(reference.imported) ||
261
+ !fs.existsSync(reference.imported)) {
262
+ continue;
263
+ }
264
+ pending.push({
265
+ file: reference.imported,
266
+ kind: 'dependency',
267
+ });
268
+ }
269
+ }
270
+ return Array.from(watchFiles, ([file, kind]) => ({
271
+ file,
272
+ kind,
273
+ }));
274
+ }
223
275
  toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir) {
224
276
  return createDevModuleStyleSpecifier(specifier, {
225
277
  sourceStyleDir,
@@ -9,10 +9,16 @@ export type PackageStyleId = {
9
9
  packageName: string;
10
10
  stylePath: string;
11
11
  };
12
+ export type PackageStyleWatchFileKind = 'entry' | 'dependency';
13
+ export type PackageStyleWatchFile = {
14
+ file: string;
15
+ kind: PackageStyleWatchFileKind;
16
+ };
12
17
  export type PackageStyleLoadResult = {
13
18
  code: string;
14
19
  cacheInputFiles?: Array<string>;
15
20
  watchFiles: Array<string>;
21
+ watchFileKinds?: Array<PackageStyleWatchFile>;
16
22
  dependencyPackages?: Array<string>;
17
23
  };
18
24
  export type LoadAukletConfig = (packageRoot: string, options?: {
@@ -113,7 +113,7 @@ export function aukletStylePlugin(options = {}) {
113
113
  if (moduleGraph) {
114
114
  hmr.pruneStaleVirtualDependencies(moduleGraph);
115
115
  }
116
- hmr.replaceVirtualStyleDependency(id, result.watchFiles);
116
+ hmr.replaceVirtualStyleDependency(id, result.watchFiles, result.watchFileKinds);
117
117
  for (const file of result.watchFiles) {
118
118
  this.addWatchFile?.(file);
119
119
  }
@@ -150,8 +150,7 @@ export function aukletStylePlugin(options = {}) {
150
150
  reloadStyleGraph(file);
151
151
  }
152
152
  else if (graph.isStyleFile(file)) {
153
- graph.invalidateFile(file);
154
- if (hmr.hasTrackedStyleDependency(file, server.moduleGraph)) {
153
+ if (hmr.hasTrackedStyleDependency(file)) {
155
154
  await hmr.handleStyleHotUpdate({
156
155
  file,
157
156
  modules: [],
@@ -161,6 +160,9 @@ export function aukletStylePlugin(options = {}) {
161
160
  read: async () => '',
162
161
  });
163
162
  }
163
+ else {
164
+ graph.invalidateFile(file);
165
+ }
164
166
  }
165
167
  else if (graph.isSourceModuleFile(file)) {
166
168
  await hmr.handleSourceModuleChange(server, file);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auklet",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "author": "chentao.arthur",
6
6
  "description": "Build utilities for TypeScript packages and module CSS output.",