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.
- package/README.md +37 -1
- package/dist/css/constants.d.ts +1 -1
- package/dist/css/constants.js +1 -1
- package/dist/css/core/style/entries.d.ts +2 -2
- package/dist/css/core/style/entries.js +2 -2
- package/dist/css/core/style/specifier.d.ts +36 -0
- package/dist/css/core/style/specifier.js +86 -0
- package/dist/css/core/styleImports/autoImportRules.d.ts +13 -0
- package/dist/css/core/styleImports/autoImportRules.js +68 -0
- package/dist/css/core/styleImports/collector.d.ts +0 -5
- package/dist/css/core/styleImports/collector.js +13 -79
- package/dist/css/core/styleImports/sourceImportExportAnalyzer.d.ts +11 -0
- package/dist/css/core/styleImports/{sourceReference.js → sourceImportExportAnalyzer.js} +3 -3
- package/dist/css/core/styleModuleEntryPlanner.d.ts +1 -1
- package/dist/css/core/styleModuleEntryPlanner.js +3 -3
- package/dist/css/core/workspaceStyleResolver.d.ts +0 -1
- package/dist/css/core/workspaceStyleResolver.js +13 -45
- package/dist/css/production/format/{componentWriter.d.ts → moduleEntryWriter.d.ts} +1 -1
- package/dist/css/production/format/{componentWriter.js → moduleEntryWriter.js} +8 -10
- package/dist/css/production/format/shared.d.ts +1 -1
- package/dist/css/production/format/shared.js +1 -5
- package/dist/css/production/moduleOutputWriter.d.ts +2 -2
- package/dist/css/production/moduleOutputWriter.js +11 -11
- package/dist/css/vite/moduleGraph/graph.d.ts +1 -1
- package/dist/css/vite/moduleGraph/graph.js +15 -11
- package/dist/css/vite/moduleGraph/packageSource/monorepo.d.ts +14 -3
- package/dist/css/vite/moduleGraph/packageSource/monorepo.js +9 -12
- package/dist/css/vite/moduleGraph/packageSource/singlePackage.d.ts +21 -0
- package/dist/css/vite/moduleGraph/packageSource/singlePackage.js +63 -0
- package/dist/css/vite/moduleGraph/packageSource/types.d.ts +1 -1
- package/dist/css/vite/moduleGraph/styleCodeFactory.js +19 -29
- package/dist/css/vite/moduleGraph/types.d.ts +1 -1
- package/dist/css/vite/vitePlugin.d.ts +2 -2
- package/dist/css/vite/vitePlugin.js +11 -4
- package/dist/css/watch/watcher.js +2 -2
- package/package.json +1 -1
- 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
|
package/dist/css/constants.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const NODE_MODULES_DIR = "node_modules";
|
|
2
|
-
export declare const
|
|
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";
|
package/dist/css/constants.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const NODE_MODULES_DIR = 'node_modules';
|
|
2
|
-
export const
|
|
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
|
|
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
|
|
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
|
|
30
|
+
export function createModuleStyleEntryPlan(packageContext, sourceDir) {
|
|
31
31
|
return new StyleModuleEntryPlanner(packageContext).createEntry(sourceDir, collectModuleStyleImports(packageContext));
|
|
32
32
|
}
|
|
33
|
-
export function
|
|
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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
-
|
|
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 =
|
|
25
|
+
const rules = createStyleAutoImportRules(config);
|
|
28
26
|
for (const file of files) {
|
|
29
|
-
if (!
|
|
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 =
|
|
34
|
+
const imports = collectModuleImportReferences(file, code);
|
|
37
35
|
for (const item of imports) {
|
|
38
36
|
this.collectSourceImportStyle(entries, sourceDir, sourceModuleDir, item);
|
|
39
|
-
if (
|
|
37
|
+
if (isTypeOnlyModuleReference(item))
|
|
40
38
|
continue;
|
|
41
39
|
const importPath = item.importPath;
|
|
42
|
-
const ruleMatches =
|
|
40
|
+
const ruleMatches = matchStyleAutoImportRules(rules, importPath);
|
|
43
41
|
if (!ruleMatches.length)
|
|
44
42
|
continue;
|
|
45
43
|
const directSpecifiers = ruleMatches.flatMap((ruleMatch) => {
|
|
46
|
-
const specifier =
|
|
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 =
|
|
57
|
+
const importedNames = getModuleReferenceImportedNames(file, item);
|
|
60
58
|
for (const importedName of importedNames) {
|
|
61
|
-
const specifier =
|
|
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 (
|
|
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
|
|
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
|
|
30
|
+
export function isTypeOnlyModuleReference(item) {
|
|
31
31
|
return isTypeOnlyImportClause(item.importClause) || item.isTypeOnly;
|
|
32
32
|
}
|
|
33
|
-
export function
|
|
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 {
|
|
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) =>
|
|
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
|
|
4
|
-
import {
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
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
|
-
|
|
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) =>
|
|
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
|
-
|
|
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
|
|
17
|
+
private readonly moduleEntryWriter;
|
|
18
18
|
constructor(options: ModuleStyleOutputWriterOptions);
|
|
19
19
|
write(): string[];
|
|
20
20
|
private get outputRoot();
|
|
21
|
-
private
|
|
21
|
+
private createModuleEntries;
|
|
22
22
|
private writeFormat;
|
|
23
23
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
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.
|
|
29
|
+
this.moduleEntryWriter = new ModuleStyleEntryWriter(options);
|
|
30
30
|
}
|
|
31
31
|
write() {
|
|
32
|
-
const
|
|
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,
|
|
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
|
-
|
|
43
|
-
return
|
|
42
|
+
createModuleEntries() {
|
|
43
|
+
return createModuleStyleEntryPlans(this.packageContext);
|
|
44
44
|
}
|
|
45
|
-
writeFormat(format,
|
|
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
|
|
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(...
|
|
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 {
|
|
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
|
-
|
|
3
|
+
root: string;
|
|
4
4
|
packagesDir: string;
|
|
5
5
|
styleExtensions: Array<string>;
|
|
6
6
|
};
|
|
7
|
-
export declare
|
|
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 {
|
|
4
|
+
import { SOURCE_MODULE_RE } from '#auklet/css/constants';
|
|
5
5
|
import { normalizeFileKey, toWatchPath } from '#auklet/utils';
|
|
6
|
-
export
|
|
7
|
-
return new MonorepoPackageSource(options);
|
|
8
|
-
}
|
|
9
|
-
class MonorepoPackageSource {
|
|
6
|
+
export class MonorepoPackageSource {
|
|
10
7
|
options;
|
|
11
8
|
packages;
|
|
12
9
|
packageNames;
|
|
13
|
-
|
|
10
|
+
root;
|
|
14
11
|
constructor(options) {
|
|
15
12
|
this.options = options;
|
|
16
|
-
this.
|
|
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.
|
|
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.
|
|
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 (
|
|
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.
|
|
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
|
+
}
|
|
@@ -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 {
|
|
7
|
-
import {
|
|
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 =
|
|
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
|
|
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
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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 { HotUpdateOptions, ViteDevServer } from 'vite';
|
|
2
2
|
import type { ModuleStyleGraphOptions } from '#auklet/css/vite/moduleGraph/types';
|
|
3
|
-
export type AukletStylePluginOptions = Partial<Pick<ModuleStyleGraphOptions, '
|
|
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
|
|
32
|
+
const mode = options.mode ?? 'package';
|
|
33
|
+
const root = options.root ?? resolveGraphRoot(mode, viteRoot);
|
|
33
34
|
return new ModuleStyleGraph({
|
|
34
35
|
...options,
|
|
35
|
-
|
|
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 {
|
|
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 (
|
|
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,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[];
|