auklet 0.0.17 → 0.0.18

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.
Files changed (37) hide show
  1. package/README.md +37 -1
  2. package/dist/css/constants.d.ts +1 -1
  3. package/dist/css/constants.js +1 -1
  4. package/dist/css/core/style/entries.d.ts +2 -2
  5. package/dist/css/core/style/entries.js +2 -2
  6. package/dist/css/core/style/specifier.d.ts +36 -0
  7. package/dist/css/core/style/specifier.js +86 -0
  8. package/dist/css/core/styleImports/autoImportRules.d.ts +13 -0
  9. package/dist/css/core/styleImports/autoImportRules.js +68 -0
  10. package/dist/css/core/styleImports/collector.d.ts +0 -5
  11. package/dist/css/core/styleImports/collector.js +13 -79
  12. package/dist/css/core/styleImports/sourceImportExportAnalyzer.d.ts +11 -0
  13. package/dist/css/core/styleImports/{sourceReference.js → sourceImportExportAnalyzer.js} +3 -3
  14. package/dist/css/core/styleModuleEntryPlanner.d.ts +1 -1
  15. package/dist/css/core/styleModuleEntryPlanner.js +3 -3
  16. package/dist/css/core/workspaceStyleResolver.d.ts +0 -1
  17. package/dist/css/core/workspaceStyleResolver.js +13 -45
  18. package/dist/css/production/format/{componentWriter.d.ts → moduleEntryWriter.d.ts} +1 -1
  19. package/dist/css/production/format/{componentWriter.js → moduleEntryWriter.js} +8 -10
  20. package/dist/css/production/format/shared.d.ts +1 -1
  21. package/dist/css/production/format/shared.js +1 -5
  22. package/dist/css/production/moduleOutputWriter.d.ts +2 -2
  23. package/dist/css/production/moduleOutputWriter.js +11 -11
  24. package/dist/css/vite/moduleGraph/graph.d.ts +1 -1
  25. package/dist/css/vite/moduleGraph/graph.js +15 -11
  26. package/dist/css/vite/moduleGraph/packageSource/monorepo.d.ts +14 -3
  27. package/dist/css/vite/moduleGraph/packageSource/monorepo.js +9 -12
  28. package/dist/css/vite/moduleGraph/packageSource/singlePackage.d.ts +21 -0
  29. package/dist/css/vite/moduleGraph/packageSource/singlePackage.js +63 -0
  30. package/dist/css/vite/moduleGraph/packageSource/types.d.ts +1 -1
  31. package/dist/css/vite/moduleGraph/styleCodeFactory.js +19 -29
  32. package/dist/css/vite/moduleGraph/types.d.ts +1 -1
  33. package/dist/css/vite/vitePlugin.d.ts +2 -2
  34. package/dist/css/vite/vitePlugin.js +11 -4
  35. package/dist/css/watch/watcher.js +2 -2
  36. package/package.json +1 -1
  37. package/dist/css/core/styleImports/sourceReference.d.ts +0 -11
package/README.md CHANGED
@@ -15,7 +15,7 @@ Build utilities for TypeScript packages and module CSS output.
15
15
  - Generate package-level and module-level CSS entries.
16
16
  - Infer component style dependencies from source imports.
17
17
  - Generate theme and external style entry files.
18
- - Provide a Vite dev plugin for virtual package CSS entries.
18
+ - Provide a Vite dev plugin for virtual package CSS entries in single-package and monorepo projects.
19
19
  - Watch source/config changes and rebuild module CSS output.
20
20
 
21
21
  ## Requirements
@@ -215,6 +215,25 @@ export default {
215
215
  };
216
216
  ```
217
217
 
218
+ The plugin defaults to `mode: 'package'`, where Vite root is treated as the
219
+ current package root. This is the expected setup for a single-package component
220
+ library.
221
+
222
+ For a workspace demo or app that imports CSS from packages under
223
+ `packages/*`, enable monorepo mode:
224
+
225
+ ```ts
226
+ import { aukletStylePlugin } from 'auklet';
227
+
228
+ export default {
229
+ plugins: [aukletStylePlugin({ mode: 'monorepo' })],
230
+ };
231
+ ```
232
+
233
+ `mode: 'monorepo'` automatically walks upward from Vite root to find
234
+ `pnpm-workspace.yaml`. A custom graph root can be passed with `root` when the
235
+ workspace root cannot be inferred.
236
+
218
237
  The plugin resolves package CSS ids such as:
219
238
 
220
239
  ```ts
@@ -229,6 +248,23 @@ resolved from the package that declares the dependency and emitted as Vite
229
248
  `/@fs/...` imports, so packages such as `katex/dist/katex.min.css` do not need
230
249
  to be installed by the consuming app.
231
250
 
251
+ ## Examples
252
+
253
+ The repository includes runnable examples for the supported project shapes:
254
+
255
+ - `examples/components`: monorepo component packages.
256
+ - `examples/libs`: monorepo TypeScript libraries without CSS output.
257
+ - `examples/single-package`: single-package component library with Vite dev mode.
258
+ - `examples/single-lib`: single-package TypeScript library without CSS output.
259
+
260
+ Useful commands:
261
+
262
+ ```bash
263
+ pnpm run build:examples
264
+ pnpm run test:examples
265
+ pnpm run dev:examples
266
+ ```
267
+
232
268
  ## Programmatic API
233
269
 
234
270
  ```ts
@@ -1,5 +1,5 @@
1
1
  export declare const NODE_MODULES_DIR = "node_modules";
2
- export declare const SOURCE_COMPONENT_MODULE_RE: RegExp;
2
+ export declare const SOURCE_MODULE_RE: RegExp;
3
3
  export declare const THEMES_DIR = "themes";
4
4
  export declare const THEMES_ENTRY_PREFIX = "themes/";
5
5
  export declare const STYLE_ENTRY = "style.css";
@@ -1,5 +1,5 @@
1
1
  export const NODE_MODULES_DIR = 'node_modules';
2
- export const SOURCE_COMPONENT_MODULE_RE = /\.tsx$/;
2
+ export const SOURCE_MODULE_RE = /\.tsx$/;
3
3
  export const THEMES_DIR = 'themes';
4
4
  export const THEMES_ENTRY_PREFIX = 'themes/';
5
5
  export const STYLE_ENTRY = 'style.css';
@@ -39,12 +39,12 @@ export declare function createExternalEntryParts(config: NormalizedAukletConfig)
39
39
  specifiers: string[];
40
40
  }[];
41
41
  export declare function collectModuleStyleImports(packageContext: StylePackageContext): Map<string, string[]>;
42
- export declare function createComponentStyleEntryPlan(packageContext: StylePackageContext, sourceDir: string): {
42
+ export declare function createModuleStyleEntryPlan(packageContext: StylePackageContext, sourceDir: string): {
43
43
  sourceDir: string;
44
44
  moduleStyleImports: string[];
45
45
  ownStyleFiles: string[];
46
46
  };
47
- export declare function createComponentStyleEntryPlans(packageContext: StylePackageContext): {
47
+ export declare function createModuleStyleEntryPlans(packageContext: StylePackageContext): {
48
48
  sourceDir: string;
49
49
  moduleStyleImports: string[];
50
50
  ownStyleFiles: string[];
@@ -27,9 +27,9 @@ export function createExternalEntryParts(config) {
27
27
  export function collectModuleStyleImports(packageContext) {
28
28
  return packageContext.importCollector.collect(packageContext.sourceFiles, packageContext.normalizedConfig);
29
29
  }
30
- export function createComponentStyleEntryPlan(packageContext, sourceDir) {
30
+ export function createModuleStyleEntryPlan(packageContext, sourceDir) {
31
31
  return new StyleModuleEntryPlanner(packageContext).createEntry(sourceDir, collectModuleStyleImports(packageContext));
32
32
  }
33
- export function createComponentStyleEntryPlans(packageContext) {
33
+ export function createModuleStyleEntryPlans(packageContext) {
34
34
  return new StyleModuleEntryPlanner(packageContext).createEntries(collectModuleStyleImports(packageContext));
35
35
  }
@@ -9,3 +9,39 @@ export declare function parsePackageStyleSpecifier(specifier: string): {
9
9
  export declare function joinDependencySpecifier(packageName: string, dependencyPath: string): string;
10
10
  export declare function createImportCode(specifiers: Array<string>): string;
11
11
  export declare function removeStyleExtension(stylePath: string): string;
12
+ export declare function toRelativeImportSpecifier(fromDir: string, file: string): string;
13
+ export declare function getStylePathOutputFormat(stylePath: string, outputFormats: Array<string>): {
14
+ format: string;
15
+ path: string;
16
+ } | null;
17
+ export declare function createOutputStyleSpecifier(specifier: string, options: {
18
+ currentOutputFormat: string;
19
+ outputFormats: Array<string>;
20
+ }): string;
21
+ export declare function createExternalStyleSpecifier(specifier: string, options: {
22
+ currentOutputFormat: string;
23
+ outputFormats: Array<string>;
24
+ styleDir: string;
25
+ indexStyleFile: string;
26
+ externalStyleFile: string;
27
+ }): string;
28
+ export declare function createDevExternalStyleSpecifier(specifier: string, options: {
29
+ isKnownPackageName: (packageName: string) => boolean;
30
+ styleDir: string;
31
+ indexStyleFile: string;
32
+ externalStyleFile?: string;
33
+ }): string;
34
+ export declare function createOutputModuleStyleSpecifier(specifier: string, styleDir: string): string;
35
+ export declare function createOutputOwnStyleSpecifier(options: {
36
+ sourceRoot: string;
37
+ outputRoot: string;
38
+ styleDir: string;
39
+ }, styleFile: string): string;
40
+ export declare function createDevModuleStyleSpecifier(specifier: string, options: {
41
+ sourceStyleDir: string;
42
+ sourceRoot: string;
43
+ packageName: string;
44
+ styleDir: string;
45
+ indexStyleFile: string;
46
+ mapExternalSpecifier: (specifier: string) => string;
47
+ }): string;
@@ -1,4 +1,6 @@
1
1
  import path from 'node:path';
2
+ import { EXTERNAL_ENTRY, STYLE_ENTRY } from '#auklet/css/constants';
3
+ import { POSIX_SEPARATOR, toFsSpecifier, toPosixPath } from '#auklet/utils';
2
4
  export function parsePackageStyleSpecifier(specifier) {
3
5
  if (specifier.startsWith('.'))
4
6
  return null;
@@ -28,3 +30,87 @@ export function createImportCode(specifiers) {
28
30
  export function removeStyleExtension(stylePath) {
29
31
  return stylePath.slice(0, -path.extname(stylePath).length);
30
32
  }
33
+ export function toRelativeImportSpecifier(fromDir, file) {
34
+ const relative = toPosixPath(path.relative(fromDir, file));
35
+ return relative.startsWith('.') ? relative : `./${relative}`;
36
+ }
37
+ export function getStylePathOutputFormat(stylePath, outputFormats) {
38
+ for (const format of outputFormats) {
39
+ const prefix = `${format}${POSIX_SEPARATOR}`;
40
+ if (!stylePath.startsWith(prefix))
41
+ continue;
42
+ return {
43
+ format,
44
+ path: stylePath.slice(prefix.length),
45
+ };
46
+ }
47
+ return null;
48
+ }
49
+ export function createOutputStyleSpecifier(specifier, options) {
50
+ const parsed = parsePackageStyleSpecifier(specifier);
51
+ if (!parsed)
52
+ return specifier;
53
+ const outputFormat = getStylePathOutputFormat(parsed.stylePath, options.outputFormats);
54
+ if (!outputFormat)
55
+ return specifier;
56
+ return [
57
+ parsed.packageName,
58
+ options.currentOutputFormat,
59
+ outputFormat.path,
60
+ ].join(POSIX_SEPARATOR);
61
+ }
62
+ export function createExternalStyleSpecifier(specifier, options) {
63
+ const parsed = parsePackageStyleSpecifier(specifier);
64
+ if (!parsed)
65
+ return specifier;
66
+ if (parsed.stylePath === STYLE_ENTRY) {
67
+ return [parsed.packageName, options.externalStyleFile].join(POSIX_SEPARATOR);
68
+ }
69
+ const outputFormat = getStylePathOutputFormat(parsed.stylePath, options.outputFormats);
70
+ const indexStylePath = [options.styleDir, options.indexStyleFile].join(POSIX_SEPARATOR);
71
+ if (!outputFormat || outputFormat.path !== indexStylePath)
72
+ return specifier;
73
+ return [
74
+ parsed.packageName,
75
+ options.currentOutputFormat,
76
+ options.styleDir,
77
+ options.externalStyleFile,
78
+ ].join(POSIX_SEPARATOR);
79
+ }
80
+ export function createDevExternalStyleSpecifier(specifier, options) {
81
+ const parsed = parsePackageStyleSpecifier(specifier);
82
+ if (!parsed)
83
+ return specifier;
84
+ if (!options.isKnownPackageName(parsed.packageName))
85
+ return specifier;
86
+ const indexStylePath = [options.styleDir, options.indexStyleFile].join(POSIX_SEPARATOR);
87
+ if (parsed.stylePath === STYLE_ENTRY || parsed.stylePath === indexStylePath) {
88
+ return [
89
+ parsed.packageName,
90
+ options.externalStyleFile ?? EXTERNAL_ENTRY,
91
+ ].join(POSIX_SEPARATOR);
92
+ }
93
+ return specifier;
94
+ }
95
+ export function createOutputModuleStyleSpecifier(specifier, styleDir) {
96
+ if (specifier.startsWith('.'))
97
+ return specifier;
98
+ if (!path.isAbsolute(specifier))
99
+ return specifier;
100
+ return toRelativeImportSpecifier(styleDir, specifier);
101
+ }
102
+ export function createOutputOwnStyleSpecifier(options, styleFile) {
103
+ return toRelativeImportSpecifier(options.styleDir, path.join(options.outputRoot, path.relative(options.sourceRoot, styleFile)));
104
+ }
105
+ export function createDevModuleStyleSpecifier(specifier, options) {
106
+ if (!specifier.startsWith('.')) {
107
+ return options.mapExternalSpecifier(specifier);
108
+ }
109
+ const outputStyleEntry = path.resolve(options.sourceStyleDir, specifier);
110
+ const styleEntrySuffix = `${path.sep}${options.styleDir}${path.sep}${options.indexStyleFile}`;
111
+ if (!outputStyleEntry.endsWith(styleEntrySuffix)) {
112
+ return toFsSpecifier(outputStyleEntry);
113
+ }
114
+ const sourceModuleDir = path.relative(options.sourceRoot, outputStyleEntry.slice(0, -styleEntrySuffix.length));
115
+ return `${options.packageName}/${toPosixPath(sourceModuleDir)}.css`;
116
+ }
@@ -0,0 +1,13 @@
1
+ import type { NormalizedAukletConfig } from '#auklet/types';
2
+ export type StyleAutoImportRule = {
3
+ packageName: string;
4
+ outputPattern: string;
5
+ };
6
+ export type StyleAutoImportRuleMatch = {
7
+ rule: StyleAutoImportRule;
8
+ values: Array<string>;
9
+ };
10
+ export declare function createStyleAutoImportRules(config: NormalizedAukletConfig): StyleAutoImportRule[];
11
+ export declare function matchStyleAutoImportRules(rules: Array<StyleAutoImportRule>, importPath: string): StyleAutoImportRuleMatch[];
12
+ export declare function createStyleAutoImportSpecifier(rule: StyleAutoImportRule, values: Array<string>, importedName: string): string;
13
+ export declare function createDirectStyleAutoImportSpecifier(rule: StyleAutoImportRule, importPath: string): string | null;
@@ -0,0 +1,68 @@
1
+ import { isArray } from 'aidly';
2
+ import { joinDependencySpecifier } from '#auklet/css/core/style/specifier';
3
+ import { POSIX_SEPARATOR } from '#auklet/utils';
4
+ const GLOBSTAR_TOKEN = '**';
5
+ export function createStyleAutoImportRules(config) {
6
+ const rules = [];
7
+ for (const [packageName, dependency] of Object.entries(config.styles.dependencies)) {
8
+ const dependencyPaths = isArray(dependency.components)
9
+ ? dependency.components
10
+ : dependency.components
11
+ ? [dependency.components]
12
+ : [];
13
+ for (const dependencyPath of dependencyPaths) {
14
+ rules.push({
15
+ packageName,
16
+ outputPattern: joinDependencySpecifier(packageName, dependencyPath),
17
+ });
18
+ }
19
+ }
20
+ return rules;
21
+ }
22
+ export function matchStyleAutoImportRules(rules, importPath) {
23
+ const matches = [];
24
+ for (const rule of rules) {
25
+ if (importPath !== rule.packageName &&
26
+ !importPath.startsWith(`${rule.packageName}${POSIX_SEPARATOR}`)) {
27
+ continue;
28
+ }
29
+ matches.push({
30
+ rule,
31
+ values: getImportPathValues(rule.packageName, importPath),
32
+ });
33
+ }
34
+ return matches;
35
+ }
36
+ export function createStyleAutoImportSpecifier(rule, values, importedName) {
37
+ const pathValues = [...values];
38
+ return rule.outputPattern.replace(/\*\*|\*/g, (token) => {
39
+ const matchedValue = pathValues.shift();
40
+ if (matchedValue)
41
+ return matchedValue;
42
+ if (token === GLOBSTAR_TOKEN)
43
+ return importedName;
44
+ return matchedValue ?? importedName;
45
+ });
46
+ }
47
+ export function createDirectStyleAutoImportSpecifier(rule, importPath) {
48
+ const wildcardIndex = rule.outputPattern.indexOf('*');
49
+ if (wildcardIndex < 0) {
50
+ return null;
51
+ }
52
+ const wildcardLength = rule.outputPattern.startsWith(GLOBSTAR_TOKEN, wildcardIndex)
53
+ ? GLOBSTAR_TOKEN.length
54
+ : 1;
55
+ const prefix = rule.outputPattern.slice(0, wildcardIndex);
56
+ const suffix = rule.outputPattern.slice(wildcardIndex + wildcardLength);
57
+ if (!importPath.startsWith(prefix)) {
58
+ return null;
59
+ }
60
+ return `${importPath}${suffix}`;
61
+ }
62
+ const getImportPathValues = (packageName, importPath) => {
63
+ return importPath
64
+ .slice(packageName.length)
65
+ .replace(new RegExp(`^${POSIX_SEPARATOR}`), '')
66
+ .split(POSIX_SEPARATOR)
67
+ .filter(Boolean);
68
+ };
@@ -13,9 +13,4 @@ export declare class ModuleStyleImportCollector {
13
13
  private resolveSourceImportPaths;
14
14
  private toSourceBase;
15
15
  private toRelativeSpecifier;
16
- private createAutoImportRules;
17
- private matchAutoImportRules;
18
- private getImportPathValues;
19
- private createStyleSpecifier;
20
- private createDirectStyleSpecifier;
21
16
  }
@@ -1,14 +1,12 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { isArray } from 'aidly';
4
- import { SOURCE_COMPONENT_MODULE_RE } from '#auklet/css/constants';
5
- import { joinDependencySpecifier } from '#auklet/css/core/style/specifier';
6
- import { appendUniqueMapValue, getSourceModuleDir, POSIX_SEPARATOR, } from '#auklet/utils';
7
- import { collectModuleStyleSourceReferences, getSourceReferenceImportedNames, isTypeOnlySourceReference, } from '#auklet/css/core/styleImports/sourceReference';
3
+ import { SOURCE_MODULE_RE } from '#auklet/css/constants';
4
+ import { appendUniqueMapValue, getSourceModuleDir } from '#auklet/utils';
5
+ import { isTypeOnlyModuleReference, collectModuleImportReferences, getModuleReferenceImportedNames, } from '#auklet/css/core/styleImports/sourceImportExportAnalyzer';
8
6
  import { resolveRelativeSourceImport } from '#auklet/css/core/resolvers/relative';
9
7
  import { resolvePackageImportsSourceImport } from '#auklet/css/core/resolvers/packageImports';
10
8
  import { resolveTsconfigPathsSourceImport } from '#auklet/css/core/resolvers/tsconfigPaths';
11
- const GLOBSTAR_TOKEN = '**';
9
+ import { matchStyleAutoImportRules, createStyleAutoImportRules, createStyleAutoImportSpecifier, createDirectStyleAutoImportSpecifier, } from '#auklet/css/core/styleImports/autoImportRules';
12
10
  const SOURCE_EXTENSION_RE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
13
11
  const SOURCE_INDEX_RE = new RegExp(`[/\\\\]index${SOURCE_EXTENSION_RE.source}`);
14
12
  export class ModuleStyleImportCollector {
@@ -24,26 +22,26 @@ export class ModuleStyleImportCollector {
24
22
  }
25
23
  collect(files, config) {
26
24
  const entries = new Map();
27
- const rules = this.createAutoImportRules(config);
25
+ const rules = createStyleAutoImportRules(config);
28
26
  for (const file of files) {
29
- if (!SOURCE_COMPONENT_MODULE_RE.test(file)) {
27
+ if (!SOURCE_MODULE_RE.test(file)) {
30
28
  continue;
31
29
  }
32
30
  const sourceRelative = path.relative(this.srcRoot, file);
33
31
  const sourceDir = path.dirname(sourceRelative);
34
32
  const sourceModuleDir = getSourceModuleDir(sourceRelative);
35
33
  const code = fs.readFileSync(file, 'utf8');
36
- const imports = collectModuleStyleSourceReferences(file, code);
34
+ const imports = collectModuleImportReferences(file, code);
37
35
  for (const item of imports) {
38
36
  this.collectSourceImportStyle(entries, sourceDir, sourceModuleDir, item);
39
- if (isTypeOnlySourceReference(item))
37
+ if (isTypeOnlyModuleReference(item))
40
38
  continue;
41
39
  const importPath = item.importPath;
42
- const ruleMatches = this.matchAutoImportRules(rules, importPath);
40
+ const ruleMatches = matchStyleAutoImportRules(rules, importPath);
43
41
  if (!ruleMatches.length)
44
42
  continue;
45
43
  const directSpecifiers = ruleMatches.flatMap((ruleMatch) => {
46
- const specifier = this.createDirectStyleSpecifier(ruleMatch.rule, importPath);
44
+ const specifier = createDirectStyleAutoImportSpecifier(ruleMatch.rule, importPath);
47
45
  return specifier ? [specifier] : [];
48
46
  });
49
47
  if (directSpecifiers.length) {
@@ -56,9 +54,9 @@ export class ModuleStyleImportCollector {
56
54
  continue;
57
55
  }
58
56
  for (const ruleMatch of ruleMatches) {
59
- const importedNames = getSourceReferenceImportedNames(file, item);
57
+ const importedNames = getModuleReferenceImportedNames(file, item);
60
58
  for (const importedName of importedNames) {
61
- const specifier = this.createStyleSpecifier(ruleMatch.rule, ruleMatch.values, importedName);
59
+ const specifier = createStyleAutoImportSpecifier(ruleMatch.rule, ruleMatch.values, importedName);
62
60
  const cssFile = this.resolver.resolveStyleDependency(specifier);
63
61
  if (!fs.existsSync(cssFile)) {
64
62
  continue;
@@ -71,7 +69,7 @@ export class ModuleStyleImportCollector {
71
69
  return entries;
72
70
  }
73
71
  collectSourceImportStyle(entries, sourceDir, sourceModuleDir, item) {
74
- if (isTypeOnlySourceReference(item))
72
+ if (isTypeOnlyModuleReference(item))
75
73
  return;
76
74
  const importedStyleEntry = this.resolveSourceImportStyleEntry(sourceDir, item.importPath);
77
75
  if (!importedStyleEntry)
@@ -119,68 +117,4 @@ export class ModuleStyleImportCollector {
119
117
  const relative = path.relative(fromDir, file).split(path.sep).join('/');
120
118
  return relative.startsWith('.') ? relative : `./${relative}`;
121
119
  }
122
- createAutoImportRules(config) {
123
- const rules = [];
124
- for (const [packageName, dependency] of Object.entries(config.styles.dependencies)) {
125
- const dependencyPaths = isArray(dependency.components)
126
- ? dependency.components
127
- : dependency.components
128
- ? [dependency.components]
129
- : [];
130
- for (const dependencyPath of dependencyPaths) {
131
- rules.push({
132
- packageName,
133
- outputPattern: joinDependencySpecifier(packageName, dependencyPath),
134
- });
135
- }
136
- }
137
- return rules;
138
- }
139
- matchAutoImportRules(rules, importPath) {
140
- const matches = [];
141
- for (const rule of rules) {
142
- if (importPath !== rule.packageName &&
143
- !importPath.startsWith(`${rule.packageName}${POSIX_SEPARATOR}`)) {
144
- continue;
145
- }
146
- matches.push({
147
- rule,
148
- values: this.getImportPathValues(rule.packageName, importPath),
149
- });
150
- }
151
- return matches;
152
- }
153
- getImportPathValues(packageName, importPath) {
154
- return importPath
155
- .slice(packageName.length)
156
- .replace(new RegExp(`^${POSIX_SEPARATOR}`), '')
157
- .split(POSIX_SEPARATOR)
158
- .filter(Boolean);
159
- }
160
- createStyleSpecifier(rule, values, importedName) {
161
- const pathValues = [...values];
162
- return rule.outputPattern.replace(/\*\*|\*/g, (token) => {
163
- const matchedValue = pathValues.shift();
164
- if (matchedValue)
165
- return matchedValue;
166
- if (token === GLOBSTAR_TOKEN)
167
- return importedName;
168
- return matchedValue ?? importedName;
169
- });
170
- }
171
- createDirectStyleSpecifier(rule, importPath) {
172
- const wildcardIndex = rule.outputPattern.indexOf('*');
173
- if (wildcardIndex < 0) {
174
- return null;
175
- }
176
- const wildcardLength = rule.outputPattern.startsWith(GLOBSTAR_TOKEN, wildcardIndex)
177
- ? GLOBSTAR_TOKEN.length
178
- : 1;
179
- const prefix = rule.outputPattern.slice(0, wildcardIndex);
180
- const suffix = rule.outputPattern.slice(wildcardIndex + wildcardLength);
181
- if (!importPath.startsWith(prefix)) {
182
- return null;
183
- }
184
- return `${importPath}${suffix}`;
185
- }
186
120
  }
@@ -0,0 +1,11 @@
1
+ import ts from 'typescript';
2
+ export type ModuleImportReference = {
3
+ importPath: string;
4
+ importClause?: ts.ImportClause;
5
+ importedNames?: Array<string>;
6
+ isTypeOnly?: boolean;
7
+ hasNamespaceImport?: boolean;
8
+ };
9
+ export declare function collectModuleImportReferences(file: string, code: string): ModuleImportReference[];
10
+ export declare function isTypeOnlyModuleReference(item: ModuleImportReference): boolean | undefined;
11
+ export declare function getModuleReferenceImportedNames(file: string, item: ModuleImportReference): string[];
@@ -1,5 +1,5 @@
1
1
  import ts from 'typescript';
2
- export function collectModuleStyleSourceReferences(file, code) {
2
+ export function collectModuleImportReferences(file, code) {
3
3
  const imports = [];
4
4
  const importBindings = new Map();
5
5
  const localDeclarations = new Set();
@@ -27,10 +27,10 @@ export function collectModuleStyleSourceReferences(file, code) {
27
27
  });
28
28
  return imports;
29
29
  }
30
- export function isTypeOnlySourceReference(item) {
30
+ export function isTypeOnlyModuleReference(item) {
31
31
  return isTypeOnlyImportClause(item.importClause) || item.isTypeOnly;
32
32
  }
33
- export function getSourceReferenceImportedNames(file, item) {
33
+ export function getModuleReferenceImportedNames(file, item) {
34
34
  if (item.importedNames) {
35
35
  if (item.isTypeOnly)
36
36
  return [];
@@ -6,8 +6,8 @@ export type ModuleStyleEntryPlan = {
6
6
  };
7
7
  export declare class StyleModuleEntryPlanner {
8
8
  private readonly packageContext;
9
- private readonly styleFilesByDir;
10
9
  private readonly importedStyleFiles;
10
+ private readonly styleFilesByDir;
11
11
  constructor(packageContext: StylePackageContext);
12
12
  createEntries(moduleStyleImports: Map<string, Array<string>>): {
13
13
  sourceDir: string;
@@ -1,11 +1,11 @@
1
1
  import path from 'node:path';
2
- import { SOURCE_COMPONENT_MODULE_RE } from '#auklet/css/constants';
2
+ import { SOURCE_MODULE_RE } from '#auklet/css/constants';
3
3
  import { groupStyleFilesByDir } from '#auklet/css/core/style/files';
4
4
  import { getSourceModuleDir, toPosixPath } from '#auklet/utils';
5
5
  export class StyleModuleEntryPlanner {
6
6
  packageContext;
7
- styleFilesByDir;
8
7
  importedStyleFiles;
8
+ styleFilesByDir;
9
9
  constructor(packageContext) {
10
10
  this.packageContext = packageContext;
11
11
  this.styleFilesByDir = groupStyleFilesByDir(this.packageContext.sourceRoot, this.packageContext.styleFiles);
@@ -31,7 +31,7 @@ export class StyleModuleEntryPlanner {
31
31
  }
32
32
  getSourceModuleDirs() {
33
33
  return this.packageContext.sourceFiles
34
- .filter((sourceFile) => SOURCE_COMPONENT_MODULE_RE.test(sourceFile))
34
+ .filter((sourceFile) => SOURCE_MODULE_RE.test(sourceFile))
35
35
  .map((sourceFile) => {
36
36
  return getSourceModuleDir(path.relative(this.packageContext.sourceRoot, sourceFile));
37
37
  })
@@ -7,5 +7,4 @@ export declare class WorkspaceStyleResolver {
7
7
  resolveStyleDependency(specifier: string, fromDir?: string): string;
8
8
  toOutputStyleSpecifier(specifier: string, outRoot: string): string;
9
9
  toExternalStyleSpecifier(specifier: string, outRoot: string): string;
10
- private getStylePathOutputFormat;
11
10
  }
@@ -1,8 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { createRequire } from 'node:module';
3
- import { NODE_MODULES_DIR, STYLE_ENTRY } from '#auklet/css/constants';
4
- import { POSIX_SEPARATOR } from '#auklet/utils';
5
- import { parsePackageStyleSpecifier } from '#auklet/css/core/style/specifier';
3
+ import { NODE_MODULES_DIR } from '#auklet/css/constants';
4
+ import { createExternalStyleSpecifier, createOutputStyleSpecifier, } from '#auklet/css/core/style/specifier';
6
5
  export class WorkspaceStyleResolver {
7
6
  config;
8
7
  context;
@@ -26,49 +25,18 @@ export class WorkspaceStyleResolver {
26
25
  }
27
26
  }
28
27
  toOutputStyleSpecifier(specifier, outRoot) {
29
- const parsed = parsePackageStyleSpecifier(specifier);
30
- if (!parsed)
31
- return specifier;
32
- const { packageName, stylePath } = parsed;
33
- const currentOutputFormat = path.basename(outRoot);
34
- const outputFormat = this.getStylePathOutputFormat(stylePath);
35
- if (outputFormat) {
36
- return [packageName, currentOutputFormat, outputFormat.path].join(POSIX_SEPARATOR);
37
- }
38
- return specifier;
28
+ return createOutputStyleSpecifier(specifier, {
29
+ currentOutputFormat: path.basename(outRoot),
30
+ outputFormats: this.config.output.outputFormats,
31
+ });
39
32
  }
40
33
  toExternalStyleSpecifier(specifier, outRoot) {
41
- const parsed = parsePackageStyleSpecifier(specifier);
42
- if (!parsed)
43
- return specifier;
44
- const { packageName, stylePath } = parsed;
45
- const currentOutputFormat = path.basename(outRoot);
46
- const outputFormat = this.getStylePathOutputFormat(stylePath);
47
- if (stylePath === STYLE_ENTRY) {
48
- return [packageName, this.config.output.externalStyleFile].join(POSIX_SEPARATOR);
49
- }
50
- if (outputFormat &&
51
- outputFormat.path ===
52
- [this.config.output.styleDir, this.config.output.indexStyleFile].join(POSIX_SEPARATOR)) {
53
- return [
54
- packageName,
55
- currentOutputFormat,
56
- this.config.output.styleDir,
57
- this.config.output.externalStyleFile,
58
- ].join(POSIX_SEPARATOR);
59
- }
60
- return specifier;
61
- }
62
- getStylePathOutputFormat(stylePath) {
63
- for (const format of this.config.output.outputFormats) {
64
- const prefix = `${format}${POSIX_SEPARATOR}`;
65
- if (!stylePath.startsWith(prefix))
66
- continue;
67
- return {
68
- format,
69
- path: stylePath.slice(prefix.length),
70
- };
71
- }
72
- return null;
34
+ return createExternalStyleSpecifier(specifier, {
35
+ currentOutputFormat: path.basename(outRoot),
36
+ outputFormats: this.config.output.outputFormats,
37
+ styleDir: this.config.output.styleDir,
38
+ indexStyleFile: this.config.output.indexStyleFile,
39
+ externalStyleFile: this.config.output.externalStyleFile,
40
+ });
73
41
  }
74
42
  }
@@ -1,6 +1,6 @@
1
1
  import type { ModuleStyleEntryPlan } from '#auklet/css/core/styleModuleEntryPlanner';
2
2
  import { type FormatWriterOptions } from '#auklet/css/production/format/shared';
3
- export declare class ComponentStyleEntryWriter {
3
+ export declare class ModuleStyleEntryWriter {
4
4
  private readonly config;
5
5
  private readonly sourceRoot;
6
6
  private readonly resolver;
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
+ import { createOutputModuleStyleSpecifier, createOutputOwnStyleSpecifier, } from '#auklet/css/core/style/specifier';
2
3
  import { writeStyleFile, } from '#auklet/css/production/format/shared';
3
- import { toPosixPath } from '#auklet/utils';
4
- export class ComponentStyleEntryWriter {
4
+ export class ModuleStyleEntryWriter {
5
5
  config;
6
6
  sourceRoot;
7
7
  resolver;
@@ -36,15 +36,13 @@ export class ComponentStyleEntryWriter {
36
36
  return outputs;
37
37
  }
38
38
  getModuleStyleSpecifiers(specifiers, styleDir) {
39
- return specifiers.map((specifier) => {
40
- if (specifier.startsWith('.'))
41
- return specifier;
42
- if (!path.isAbsolute(specifier))
43
- return specifier;
44
- return toPosixPath(path.relative(styleDir, specifier));
45
- });
39
+ return specifiers.map((specifier) => createOutputModuleStyleSpecifier(specifier, styleDir));
46
40
  }
47
41
  getOwnStyleSpecifiers(ownStyleFiles, styleDir, outRoot) {
48
- return ownStyleFiles.map((styleFile) => toPosixPath(path.relative(styleDir, path.join(outRoot, path.relative(this.sourceRoot, styleFile)))));
42
+ return ownStyleFiles.map((styleFile) => createOutputOwnStyleSpecifier({
43
+ sourceRoot: this.sourceRoot,
44
+ outputRoot: outRoot,
45
+ styleDir,
46
+ }, styleFile));
49
47
  }
50
48
  }
@@ -1,4 +1,5 @@
1
1
  import type { StylePackageContext } from '#auklet/css/core/stylePackageContext';
2
+ export { toRelativeImportSpecifier } from '#auklet/css/core/style/specifier';
2
3
  import type { ModuleStyleBuildConfig, ResolvedModuleStyleBuildContext } from '#auklet/types';
3
4
  export declare const emptyStyleFileComment = "/* Empty style file kept so automated tooling can resolve this CSS path. */\n";
4
5
  export type FormatWriterOptions = {
@@ -10,5 +11,4 @@ export type ThemeStyleOutput = {
10
11
  themeName: string;
11
12
  file: string;
12
13
  };
13
- export declare function toRelativeImportSpecifier(fromDir: string, file: string): string;
14
14
  export declare function writeStyleFile(file: string, code: string): void;
@@ -1,11 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { toPosixPath } from '#auklet/utils';
3
+ export { toRelativeImportSpecifier } from '#auklet/css/core/style/specifier';
4
4
  export const emptyStyleFileComment = '/* Empty style file kept so automated tooling can resolve this CSS path. */\n';
5
- export function toRelativeImportSpecifier(fromDir, file) {
6
- const relative = toPosixPath(path.relative(fromDir, file));
7
- return relative.startsWith('.') ? relative : `./${relative}`;
8
- }
9
5
  export function writeStyleFile(file, code) {
10
6
  fs.mkdirSync(path.dirname(file), { recursive: true });
11
7
  fs.writeFileSync(file, code.trim() ? code : emptyStyleFileComment);
@@ -14,10 +14,10 @@ export declare class ModuleStyleOutputWriter {
14
14
  private readonly externalWriter;
15
15
  private readonly moduleWriter;
16
16
  private readonly entryWriter;
17
- private readonly componentWriter;
17
+ private readonly moduleEntryWriter;
18
18
  constructor(options: ModuleStyleOutputWriterOptions);
19
19
  write(): string[];
20
20
  private get outputRoot();
21
- private createComponentEntries;
21
+ private createModuleEntries;
22
22
  private writeFormat;
23
23
  }
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
- import { createComponentStyleEntryPlans } from '#auklet/css/core/style/entries';
3
- import { ComponentStyleEntryWriter } from '#auklet/css/production/format/componentWriter';
2
+ import { createModuleStyleEntryPlans } from '#auklet/css/core/style/entries';
3
+ import { ModuleStyleEntryWriter } from '#auklet/css/production/format/moduleEntryWriter';
4
4
  import { StyleEntryWriter } from '#auklet/css/production/format/entryWriter';
5
5
  import { ExternalStyleWriter } from '#auklet/css/production/format/externalWriter';
6
6
  import { ModuleStyleWriter } from '#auklet/css/production/format/moduleWriter';
@@ -16,7 +16,7 @@ export class ModuleStyleOutputWriter {
16
16
  externalWriter;
17
17
  moduleWriter;
18
18
  entryWriter;
19
- componentWriter;
19
+ moduleEntryWriter;
20
20
  constructor(options) {
21
21
  this.config = options.config;
22
22
  this.context = options.context;
@@ -26,23 +26,23 @@ export class ModuleStyleOutputWriter {
26
26
  this.externalWriter = new ExternalStyleWriter(options);
27
27
  this.moduleWriter = new ModuleStyleWriter(options);
28
28
  this.entryWriter = new StyleEntryWriter(options);
29
- this.componentWriter = new ComponentStyleEntryWriter(options);
29
+ this.moduleEntryWriter = new ModuleStyleEntryWriter(options);
30
30
  }
31
31
  write() {
32
- const componentEntries = this.createComponentEntries();
32
+ const moduleEntries = this.createModuleEntries();
33
33
  const outputs = [];
34
34
  for (const format of this.config.output.outputFormats) {
35
- outputs.push(...this.writeFormat(format, componentEntries));
35
+ outputs.push(...this.writeFormat(format, moduleEntries));
36
36
  }
37
37
  return outputs;
38
38
  }
39
39
  get outputRoot() {
40
40
  return path.join(this.context.packageRoot, this.context.outputDir);
41
41
  }
42
- createComponentEntries() {
43
- return createComponentStyleEntryPlans(this.packageContext);
42
+ createModuleEntries() {
43
+ return createModuleStyleEntryPlans(this.packageContext);
44
44
  }
45
- writeFormat(format, componentEntries) {
45
+ writeFormat(format, moduleEntries) {
46
46
  const outRoot = path.join(this.outputRoot, format);
47
47
  const outputs = [];
48
48
  this.themeWriter.clean(outRoot);
@@ -53,7 +53,7 @@ export class ModuleStyleOutputWriter {
53
53
  const externalStyle = this.externalWriter.write(outRoot);
54
54
  const moduleStyle = this.moduleWriter.write(outRoot);
55
55
  const entryStyle = this.entryWriter.write(outRoot, themeStyleMap, moduleStyle);
56
- const componentStyles = this.componentWriter.write(outRoot, componentEntries);
56
+ const moduleStyleEntries = this.moduleEntryWriter.write(outRoot, moduleEntries);
57
57
  outputs.push(...themeStyles.map((themeStyle) => themeStyle.file));
58
58
  outputs.push(...themeEntries);
59
59
  if (externalStyle)
@@ -62,7 +62,7 @@ export class ModuleStyleOutputWriter {
62
62
  outputs.push(moduleStyle);
63
63
  if (entryStyle)
64
64
  outputs.push(entryStyle);
65
- outputs.push(...componentStyles);
65
+ outputs.push(...moduleStyleEntries);
66
66
  return outputs;
67
67
  }
68
68
  }
@@ -13,7 +13,7 @@ export declare class ModuleStyleGraph {
13
13
  isStyleConfigFile(file: string): boolean;
14
14
  isStyleFile(file: string): boolean;
15
15
  getPackageNames(): string[];
16
- getWatchRoots(): string[];
16
+ getWatchRoots(): Promise<string[]>;
17
17
  createPackageStyleCode(parsed: PackageStyleId): Promise<{
18
18
  code: string;
19
19
  watchFiles: string[];
@@ -5,7 +5,8 @@ import { moduleStyleBuildConfig } from '#auklet/css/config';
5
5
  import { parsePackageStyleId } from '#auklet/css/vite/moduleGraph/styleId';
6
6
  import { StyleCodeFactory } from '#auklet/css/vite/moduleGraph/styleCodeFactory';
7
7
  import { ModuleStyleGraphRequestCache } from '#auklet/css/vite/moduleGraph/requestCache';
8
- import { createMonorepoPackageSource } from '#auklet/css/vite/moduleGraph/packageSource/monorepo';
8
+ import { MonorepoPackageSource } from '#auklet/css/vite/moduleGraph/packageSource/monorepo';
9
+ import { SinglePackageSource } from '#auklet/css/vite/moduleGraph/packageSource/singlePackage';
9
10
  import { normalizeFileKey } from '#auklet/utils';
10
11
  // package style graph 的对外门面,负责 package source、watch 边界和请求分发。
11
12
  export class ModuleStyleGraph {
@@ -15,17 +16,20 @@ export class ModuleStyleGraph {
15
16
  loadAukletConfig;
16
17
  constructor(options) {
17
18
  this.config = options.config ?? moduleStyleBuildConfig;
18
- const mode = options.mode ?? 'monorepo';
19
- if (mode === 'package') {
20
- throw new Error('[auklet:css] package mode is not supported yet.');
21
- }
22
- this.packageSource = createMonorepoPackageSource({
23
- workspaceRoot: normalizeFileKey(options.workspaceRoot),
24
- packagesDir: options.packagesDir ?? 'packages',
25
- styleExtensions: this.config.styleExtensions,
26
- });
27
- this.loadAukletConfig = options.loadAukletConfig ?? loadAukletConfig;
28
19
  this.styleCodeFactory = new StyleCodeFactory(this.config);
20
+ this.loadAukletConfig = options.loadAukletConfig ?? loadAukletConfig;
21
+ this.packageSource =
22
+ (options.mode ?? 'package') === 'monorepo'
23
+ ? new MonorepoPackageSource({
24
+ root: normalizeFileKey(options.root),
25
+ packagesDir: options.packagesDir ?? 'packages',
26
+ styleExtensions: this.config.styleExtensions,
27
+ })
28
+ : new SinglePackageSource({
29
+ root: normalizeFileKey(options.root),
30
+ styleExtensions: this.config.styleExtensions,
31
+ loadAukletConfig: this.loadAukletConfig,
32
+ });
29
33
  }
30
34
  parsePackageStyleId(id) {
31
35
  return parsePackageStyleId(id, this.getPackageNames());
@@ -1,7 +1,18 @@
1
- import type { StylePackageSource } from '#auklet/css/vite/moduleGraph/packageSource/types';
1
+ import type { StylePackageInfo, StylePackageSource } from '#auklet/css/vite/moduleGraph/packageSource/types';
2
2
  export type MonorepoPackageSourceOptions = {
3
- workspaceRoot: string;
3
+ root: string;
4
4
  packagesDir: string;
5
5
  styleExtensions: Array<string>;
6
6
  };
7
- export declare function createMonorepoPackageSource(options: MonorepoPackageSourceOptions): StylePackageSource;
7
+ export declare class MonorepoPackageSource implements StylePackageSource {
8
+ private readonly options;
9
+ private packages?;
10
+ private packageNames?;
11
+ private readonly root;
12
+ constructor(options: MonorepoPackageSourceOptions);
13
+ getPackages(): StylePackageInfo[];
14
+ getPackageNames(): string[];
15
+ isKnownPackageName(packageName: string): boolean;
16
+ isSourceGraphFile(file: string): boolean;
17
+ getWatchRoots(): Promise<string[]>;
18
+ }
@@ -1,24 +1,21 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { aukletConfigFile } from '#auklet/config';
4
- import { SOURCE_COMPONENT_MODULE_RE } from '#auklet/css/constants';
4
+ import { SOURCE_MODULE_RE } from '#auklet/css/constants';
5
5
  import { normalizeFileKey, toWatchPath } from '#auklet/utils';
6
- export function createMonorepoPackageSource(options) {
7
- return new MonorepoPackageSource(options);
8
- }
9
- class MonorepoPackageSource {
6
+ export class MonorepoPackageSource {
10
7
  options;
11
8
  packages;
12
9
  packageNames;
13
- workspaceRoot;
10
+ root;
14
11
  constructor(options) {
15
12
  this.options = options;
16
- this.workspaceRoot = normalizeFileKey(options.workspaceRoot);
13
+ this.root = normalizeFileKey(options.root);
17
14
  }
18
15
  getPackages() {
19
16
  if (this.packages)
20
17
  return this.packages;
21
- const packagesRoot = path.join(this.workspaceRoot, this.options.packagesDir);
18
+ const packagesRoot = path.join(this.root, this.options.packagesDir);
22
19
  if (!fs.existsSync(packagesRoot)) {
23
20
  this.packages = [];
24
21
  return this.packages;
@@ -52,18 +49,18 @@ class MonorepoPackageSource {
52
49
  }
53
50
  isSourceGraphFile(file) {
54
51
  const normalizedFile = normalizeFileKey(file);
55
- const packagesRoot = normalizeFileKey(path.join(this.workspaceRoot, this.options.packagesDir));
52
+ const packagesRoot = normalizeFileKey(path.join(this.root, this.options.packagesDir));
56
53
  if (!normalizedFile.startsWith(`${packagesRoot}/`)) {
57
54
  return false;
58
55
  }
59
56
  if (normalizedFile.endsWith(aukletConfigFile))
60
57
  return true;
61
- if (SOURCE_COMPONENT_MODULE_RE.test(normalizedFile))
58
+ if (SOURCE_MODULE_RE.test(normalizedFile))
62
59
  return true;
63
60
  return this.options.styleExtensions.some((extension) => normalizedFile.endsWith(extension));
64
61
  }
65
- getWatchRoots() {
66
- const packagesRoot = path.join(this.workspaceRoot, this.options.packagesDir);
62
+ async getWatchRoots() {
63
+ const packagesRoot = path.join(this.root, this.options.packagesDir);
67
64
  return [
68
65
  toWatchPath(packagesRoot, '*', 'src'),
69
66
  toWatchPath(packagesRoot, '*', aukletConfigFile),
@@ -0,0 +1,21 @@
1
+ import type { StylePackageInfo, StylePackageSource } from '#auklet/css/vite/moduleGraph/packageSource/types';
2
+ import type { LoadAukletConfig } from '#auklet/css/vite/moduleGraph/types';
3
+ export type SinglePackageSourceOptions = {
4
+ root: string;
5
+ styleExtensions: Array<string>;
6
+ loadAukletConfig?: LoadAukletConfig;
7
+ };
8
+ export declare class SinglePackageSource implements StylePackageSource {
9
+ private readonly options;
10
+ private packageInfo?;
11
+ private readonly root;
12
+ private readonly loadAukletConfig;
13
+ constructor(options: SinglePackageSourceOptions);
14
+ getPackages(): StylePackageInfo[];
15
+ getPackageNames(): string[];
16
+ isKnownPackageName(packageName: string): boolean;
17
+ isSourceGraphFile(file: string): boolean;
18
+ getWatchRoots(): Promise<string[]>;
19
+ private getPackageInfo;
20
+ private isInsidePackage;
21
+ }
@@ -0,0 +1,63 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { aukletConfigFile, normalizeAukletConfig } from '#auklet/config';
4
+ import { loadAukletConfig } from '#auklet/configLoader';
5
+ import { SOURCE_MODULE_RE } from '#auklet/css/constants';
6
+ import { normalizeFileKey, toWatchPath } from '#auklet/utils';
7
+ export class SinglePackageSource {
8
+ options;
9
+ packageInfo;
10
+ root;
11
+ loadAukletConfig;
12
+ constructor(options) {
13
+ this.options = options;
14
+ this.root = normalizeFileKey(options.root);
15
+ this.loadAukletConfig = options.loadAukletConfig ?? loadAukletConfig;
16
+ }
17
+ getPackages() {
18
+ return [this.getPackageInfo()];
19
+ }
20
+ getPackageNames() {
21
+ return [this.getPackageInfo().packageName];
22
+ }
23
+ isKnownPackageName(packageName) {
24
+ return packageName === this.getPackageInfo().packageName;
25
+ }
26
+ isSourceGraphFile(file) {
27
+ const normalizedFile = normalizeFileKey(file);
28
+ if (!this.isInsidePackage(normalizedFile))
29
+ return false;
30
+ if (normalizedFile.endsWith(aukletConfigFile))
31
+ return true;
32
+ if (SOURCE_MODULE_RE.test(normalizedFile))
33
+ return true;
34
+ return this.options.styleExtensions.some((extension) => normalizedFile.endsWith(extension));
35
+ }
36
+ async getWatchRoots() {
37
+ const normalizedConfig = normalizeAukletConfig(await this.loadAukletConfig(this.root, { cacheBust: true }));
38
+ return [
39
+ toWatchPath(this.root, normalizedConfig.source),
40
+ toWatchPath(this.root, aukletConfigFile),
41
+ ];
42
+ }
43
+ getPackageInfo() {
44
+ if (this.packageInfo)
45
+ return this.packageInfo;
46
+ const packageJsonPath = path.join(this.root, 'package.json');
47
+ if (!fs.existsSync(packageJsonPath)) {
48
+ throw new Error(`[auklet:css] package mode requires a package.json at ${this.root}.`);
49
+ }
50
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
51
+ if (!pkg.name) {
52
+ throw new Error(`[auklet:css] package mode requires package.json#name at ${this.root}.`);
53
+ }
54
+ this.packageInfo = {
55
+ packageName: pkg.name,
56
+ packageRoot: this.root,
57
+ };
58
+ return this.packageInfo;
59
+ }
60
+ isInsidePackage(file) {
61
+ return file === this.root || file.startsWith(`${this.root}/`);
62
+ }
63
+ }
@@ -7,5 +7,5 @@ export interface StylePackageSource {
7
7
  getPackageNames(): Array<string>;
8
8
  isKnownPackageName(packageName: string): boolean;
9
9
  isSourceGraphFile(file: string): boolean;
10
- getWatchRoots(): Array<string>;
10
+ getWatchRoots(): Promise<Array<string>>;
11
11
  }
@@ -3,9 +3,8 @@ import { mergeLoadResults } from '#auklet/css/vite/moduleGraph/loadResult';
3
3
  import { parsePackageStyleId } from '#auklet/css/vite/moduleGraph/styleId';
4
4
  import { toDevDependencyImportSpecifier } from '#auklet/css/vite/moduleGraph/devDependency';
5
5
  import { EXTERNAL_ENTRY, MODULE_ENTRY, STYLE_ENTRY, THEMES_ENTRY_PREFIX, } from '#auklet/css/constants';
6
- import { createComponentStyleEntryPlan, createExternalEntryParts, createStyleEntryParts, createThemeEntryParts, } from '#auklet/css/core/style/entries';
7
- import { createImportCode, parsePackageStyleSpecifier, removeStyleExtension, } from '#auklet/css/core/style/specifier';
8
- import { toFsSpecifier, toPosixPath } from '#auklet/utils';
6
+ import { createModuleStyleEntryPlan, createExternalEntryParts, createStyleEntryParts, createThemeEntryParts, } from '#auklet/css/core/style/entries';
7
+ import { createDevExternalStyleSpecifier, createDevModuleStyleSpecifier, createImportCode, removeStyleExtension, } from '#auklet/css/core/style/specifier';
9
8
  // 生成 Vite/dev 虚拟 CSS;production writer 共享入口语义,但写入真实文件。
10
9
  export class StyleCodeFactory {
11
10
  config;
@@ -129,13 +128,13 @@ export class StyleCodeFactory {
129
128
  async createSourceModuleStyleCode(context, cache, stylePath) {
130
129
  const sourceModuleDir = removeStyleExtension(stylePath);
131
130
  const { styleFiles, sourceFiles } = context.packageContext;
132
- const entry = createComponentStyleEntryPlan(context.packageContext, sourceModuleDir);
131
+ const entry = createModuleStyleEntryPlan(context.packageContext, sourceModuleDir);
133
132
  const sourceStyleDir = path.join(context.sourceRoot, sourceModuleDir, this.config.output.styleDir);
134
133
  const moduleStyleResults = [];
135
134
  const moduleStyleSpecifiers = [];
136
135
  const moduleStyleWatchFiles = [];
137
136
  for (const specifier of entry.moduleStyleImports) {
138
- const result = this.toDevModuleImportSpecifier(context, cache, sourceStyleDir, specifier);
137
+ const result = this.toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir);
139
138
  const parsed = this.parsePackageStyleIdInRequest(result, cache);
140
139
  if (parsed) {
141
140
  moduleStyleResults.push(await this.createPackageStyleCode(parsed, cache));
@@ -170,32 +169,23 @@ export class StyleCodeFactory {
170
169
  ],
171
170
  });
172
171
  }
173
- toDevModuleImportSpecifier(context, cache, sourceStyleDir, specifier) {
174
- if (!specifier.startsWith('.')) {
175
- return this.toDevExternalStyleSpecifier(specifier, cache);
176
- }
177
- const outputStyleEntry = path.resolve(sourceStyleDir, specifier);
178
- const styleEntrySuffix = `${path.sep}${this.config.output.styleDir}${path.sep}${this.config.output.indexStyleFile}`;
179
- if (!outputStyleEntry.endsWith(styleEntrySuffix)) {
180
- return toFsSpecifier(outputStyleEntry);
181
- }
182
- const sourceModuleDir = path.relative(context.sourceRoot, outputStyleEntry.slice(0, -styleEntrySuffix.length));
183
- return `${context.packageName}/${toPosixPath(sourceModuleDir)}.css`;
172
+ toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir) {
173
+ return createDevModuleStyleSpecifier(specifier, {
174
+ sourceStyleDir,
175
+ sourceRoot: context.sourceRoot,
176
+ packageName: context.packageName,
177
+ styleDir: this.config.output.styleDir,
178
+ indexStyleFile: this.config.output.indexStyleFile,
179
+ mapExternalSpecifier: (externalSpecifier) => this.toDevExternalStyleSpecifier(externalSpecifier, cache),
180
+ });
184
181
  }
185
182
  toDevExternalStyleSpecifier(specifier, cache) {
186
- const parsed = parsePackageStyleSpecifier(specifier);
187
- if (!parsed)
188
- return specifier;
189
- if (cache.isKnownPackageName(parsed.packageName)) {
190
- if (parsed.stylePath === STYLE_ENTRY) {
191
- return `${parsed.packageName}/${EXTERNAL_ENTRY}`;
192
- }
193
- if (parsed.stylePath ===
194
- [this.config.output.styleDir, this.config.output.indexStyleFile].join('/')) {
195
- return `${parsed.packageName}/${EXTERNAL_ENTRY}`;
196
- }
197
- }
198
- return specifier;
183
+ return createDevExternalStyleSpecifier(specifier, {
184
+ isKnownPackageName: (packageName) => cache.isKnownPackageName(packageName),
185
+ styleDir: this.config.output.styleDir,
186
+ indexStyleFile: this.config.output.indexStyleFile,
187
+ externalStyleFile: EXTERNAL_ENTRY,
188
+ });
199
189
  }
200
190
  parsePackageStyleIdInRequest(id, cache) {
201
191
  return parsePackageStyleId(id, cache.getPackageNames());
@@ -1,6 +1,6 @@
1
1
  import type { AukletConfig, ModuleStyleBuildConfig } from '#auklet/types';
2
2
  export interface ModuleStyleGraphOptions {
3
- workspaceRoot: string;
3
+ root: string;
4
4
  packagesDir?: string;
5
5
  mode?: 'monorepo' | 'package';
6
6
  config?: ModuleStyleBuildConfig;
@@ -1,6 +1,6 @@
1
1
  import type { HotUpdateOptions, ViteDevServer } from 'vite';
2
2
  import type { ModuleStyleGraphOptions } from '#auklet/css/vite/moduleGraph/types';
3
- export type AukletStylePluginOptions = Partial<Pick<ModuleStyleGraphOptions, 'workspaceRoot' | 'mode'>> & Omit<ModuleStyleGraphOptions, 'workspaceRoot'>;
3
+ export type AukletStylePluginOptions = Partial<Pick<ModuleStyleGraphOptions, 'root' | 'mode'>> & Omit<ModuleStyleGraphOptions, 'root'>;
4
4
  export declare function aukletStylePlugin(options?: AukletStylePluginOptions): {
5
5
  name: string;
6
6
  apply: "serve";
@@ -12,7 +12,7 @@ export declare function aukletStylePlugin(options?: AukletStylePluginOptions): {
12
12
  load(this: {
13
13
  addWatchFile?: (file: string) => void;
14
14
  }, id: string): Promise<string | null>;
15
- configureServer(server: ViteDevServer): void;
15
+ configureServer(server: ViteDevServer): Promise<void>;
16
16
  hotUpdate: {
17
17
  order: "pre";
18
18
  handler(context: HotUpdateOptions): never[] | undefined;
@@ -29,12 +29,19 @@ const findWorkspaceRoot = (startDir) => {
29
29
  }
30
30
  };
31
31
  const createModuleStyleGraph = (options, viteRoot) => {
32
- const workspaceRoot = options.workspaceRoot ?? findWorkspaceRoot(viteRoot) ?? process.cwd();
32
+ const mode = options.mode ?? 'package';
33
+ const root = options.root ?? resolveGraphRoot(mode, viteRoot);
33
34
  return new ModuleStyleGraph({
34
35
  ...options,
35
- workspaceRoot,
36
+ mode,
37
+ root,
36
38
  });
37
39
  };
40
+ const resolveGraphRoot = (mode, viteRoot) => {
41
+ if (mode === 'monorepo')
42
+ return findWorkspaceRoot(viteRoot) ?? process.cwd();
43
+ return viteRoot;
44
+ };
38
45
  const invalidateVirtualModules = (server, graph) => {
39
46
  const modules = [];
40
47
  for (const packageName of graph.getPackageNames()) {
@@ -92,10 +99,10 @@ export function aukletStylePlugin(options = {}) {
92
99
  }
93
100
  return result.code;
94
101
  },
95
- configureServer(server) {
102
+ async configureServer(server) {
96
103
  const graph = getGraph();
97
104
  hmr.installFullReloadGuard(server);
98
- server.watcher.add(graph.getWatchRoots());
105
+ server.watcher.add(await graph.getWatchRoots());
99
106
  const invalidateStyleGraph = (file) => {
100
107
  if (!graph.isSourceGraphFile(file))
101
108
  return false;
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import chokidar from 'chokidar';
4
4
  import { aukletConfigFile, aukletDefaultOptions } from '#auklet/config';
5
5
  import { moduleStyleBuildConfig } from '#auklet/css/config';
6
- import { SOURCE_COMPONENT_MODULE_RE } from '#auklet/css/constants';
6
+ import { SOURCE_MODULE_RE } from '#auklet/css/constants';
7
7
  import { ModuleStyleBuilder } from '#auklet/css/production/builder';
8
8
  export class ModuleStyleWatcher {
9
9
  config;
@@ -82,7 +82,7 @@ export class ModuleStyleWatcher {
82
82
  shouldRebuildForFile(file) {
83
83
  if (path.basename(file) === aukletConfigFile)
84
84
  return true;
85
- if (SOURCE_COMPONENT_MODULE_RE.test(file))
85
+ if (SOURCE_MODULE_RE.test(file))
86
86
  return true;
87
87
  return this.config.styleExtensions.includes(path.extname(file));
88
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auklet",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "type": "module",
5
5
  "author": "chentao.arthur",
6
6
  "description": "Build utilities for TypeScript packages and module CSS output.",
@@ -1,11 +0,0 @@
1
- import ts from 'typescript';
2
- export type ModuleStyleSourceReference = {
3
- importPath: string;
4
- importClause?: ts.ImportClause;
5
- importedNames?: Array<string>;
6
- isTypeOnly?: boolean;
7
- hasNamespaceImport?: boolean;
8
- };
9
- export declare function collectModuleStyleSourceReferences(file: string, code: string): ModuleStyleSourceReference[];
10
- export declare function isTypeOnlySourceReference(item: ModuleStyleSourceReference): boolean | undefined;
11
- export declare function getSourceReferenceImportedNames(file: string, item: ModuleStyleSourceReference): string[];