auklet 0.2.7 → 0.2.9

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 CHANGED
@@ -181,8 +181,10 @@ pattern syntax is a small glob subset: `*`, `**`, and `?`.
181
181
 
182
182
  For example, `components/CodeBlock/index.css` may import
183
183
  `../../internal/syntaxHighlight.css` when it matches `styles.shared`; component
184
- CSS outputs inline that shared CSS and its local helper CSS imports, while
185
- package-level CSS dedupes repeated shared imports. Shared CSS cannot import
186
- component CSS or theme CSS. Component-to-component CSS imports are still
187
- rejected; package CSS dependencies should be expressed through
188
- `styles.dependencies`.
184
+ CSS outputs keep that `@import` relationship instead of expanding the shared
185
+ rules into every component output. The shared CSS file is still copied as its
186
+ own source-level CSS file. `dist/index.css` remains the full package CSS
187
+ aggregate, while format-level and component-level CSS entries preserve the
188
+ import graph as much as possible. Shared CSS cannot import component CSS or
189
+ theme CSS. Component-to-component CSS imports are still rejected; package CSS
190
+ dependencies should be expressed through `styles.dependencies`.
@@ -62,7 +62,7 @@ export class StyleModuleEntryPlanner {
62
62
  throw new Error(`[css] cross-package CSS import detected: ${importer} imports ${imported}. ` +
63
63
  'Use styles.dependencies to express package style dependencies.');
64
64
  }
65
- if (this.packageContext.shouldInlineSharedStyleImport(item))
65
+ if (this.packageContext.shouldAllowSharedStyleImport(item))
66
66
  continue;
67
67
  if (this.packageContext.isSharedStyleFile(item.importer)) {
68
68
  const importer = this.toRelativeSourceFile(item.importer);
@@ -22,14 +22,19 @@ export declare class StylePackageContext {
22
22
  private readonly sourceModuleDirs;
23
23
  private readonly themeStyleFileKeys;
24
24
  private readonly sharedStyleFileKeys;
25
+ private hasValidatedSourceRootLocalStyleImports;
26
+ private hasValidatedPreservedLocalStyleImports;
25
27
  private moduleStyleEntryPlanner?;
26
28
  private moduleStyleImports?;
27
29
  constructor(options: StylePackageContextOptions);
28
30
  getStyleFiles(files: Array<string>): string[];
29
31
  getModuleStyleImports(): Map<string, string[]>;
30
32
  getModuleStyleEntryPlanner(): StyleModuleEntryPlanner;
33
+ getStyleEntryFiles(): string[];
31
34
  isSharedStyleFile(file: string): boolean;
32
- shouldInlineSharedStyleImport(reference: StyleFileImportReference): boolean;
35
+ shouldAllowSharedStyleImport(reference: StyleFileImportReference): boolean;
36
+ assertPreservedLocalStyleImports(): void;
37
+ assertNoSourceRootEscapingLocalStyleImports(): void;
33
38
  private isSharedHelperStyleFile;
34
39
  private getSourceModuleDirs;
35
40
  private isSourceModuleStyleFile;
@@ -23,6 +23,8 @@ export class StylePackageContext {
23
23
  sourceModuleDirs;
24
24
  themeStyleFileKeys;
25
25
  sharedStyleFileKeys;
26
+ hasValidatedSourceRootLocalStyleImports = false;
27
+ hasValidatedPreservedLocalStyleImports = false;
26
28
  moduleStyleEntryPlanner;
27
29
  moduleStyleImports;
28
30
  constructor(options) {
@@ -61,15 +63,35 @@ export class StylePackageContext {
61
63
  this.moduleStyleEntryPlanner ??= new StyleModuleEntryPlanner(this);
62
64
  return this.moduleStyleEntryPlanner;
63
65
  }
66
+ getStyleEntryFiles() {
67
+ const importedStyleFiles = this.styleProcessor.collectImportedStyleFiles(this.styleFiles);
68
+ return this.styleFiles.filter((styleFile) => !importedStyleFiles.has(path.resolve(styleFile)));
69
+ }
64
70
  isSharedStyleFile(file) {
65
71
  return this.sharedStyleFileKeys.has(normalizeFileKey(file));
66
72
  }
67
- shouldInlineSharedStyleImport(reference) {
73
+ shouldAllowSharedStyleImport(reference) {
68
74
  return ((this.isSharedStyleFile(reference.imported) &&
69
75
  this.isSharedHelperStyleFile(reference.imported)) ||
70
76
  (this.isSharedStyleFile(reference.importer) &&
71
77
  this.isSharedHelperStyleFile(reference.imported)));
72
78
  }
79
+ assertPreservedLocalStyleImports() {
80
+ if (this.hasValidatedPreservedLocalStyleImports)
81
+ return;
82
+ this.assertNoSourceRootEscapingLocalStyleImports();
83
+ this.styleProcessor.assertNoLocalStyleImportCycles(this.styleFiles);
84
+ this.hasValidatedPreservedLocalStyleImports = true;
85
+ }
86
+ assertNoSourceRootEscapingLocalStyleImports() {
87
+ if (this.hasValidatedSourceRootLocalStyleImports)
88
+ return;
89
+ this.styleProcessor.assertNoSourceRootEscapingLocalStyleImports([
90
+ ...this.styleFiles,
91
+ ...this.themeFiles.values(),
92
+ ]);
93
+ this.hasValidatedSourceRootLocalStyleImports = true;
94
+ }
73
95
  isSharedHelperStyleFile(file) {
74
96
  return (this.isInsideSourceRoot(file) &&
75
97
  !this.isThemeStyleFile(file) &&
@@ -4,8 +4,10 @@ import type { WorkspaceStyleResolver } from '#auklet/css/core/workspaceStyleReso
4
4
  export type StyleFileImportReference = {
5
5
  importer: string;
6
6
  imported: string;
7
+ specifier: string;
7
8
  };
8
9
  export type StyleFileImportExpandOptions = {
10
+ mapImportSpecifier?: (reference: StyleFileImportReference) => string;
9
11
  shouldExpandImport?: (reference: StyleFileImportReference) => boolean;
10
12
  };
11
13
  export declare class StyleProcessor {
@@ -17,9 +19,17 @@ export declare class StyleProcessor {
17
19
  stringify(root: Root): string;
18
20
  appendStyleContent(target: Root, content: string, from: string): void;
19
21
  readStyleFile(stylePath: string, seen?: Set<string>, options?: StyleFileImportExpandOptions): string;
22
+ private isSourceStyleImportSpecifier;
23
+ private throwMissingLocalStyleImport;
20
24
  collectImportedStyleFiles(styleFiles: Array<string>): Set<string>;
21
25
  collectImportedStyleFileReferences(styleFiles: Array<string>): StyleFileImportReference[];
22
26
  collectStyleImportSpecifiers(styleFiles: Array<string>): Set<string>;
27
+ assertNoLocalStyleImportCycles(styleFiles: Array<string>): void;
28
+ assertNoSourceRootEscapingLocalStyleImports(styleFiles: Array<string>): void;
23
29
  private parse;
24
30
  private parseImportSpecifier;
31
+ private resolveStyleImportReference;
32
+ private assertSourceRootLocalStyleImport;
33
+ private collectLocalStyleImportReferences;
34
+ private parseImportSpecifierReference;
25
35
  }
@@ -44,29 +44,39 @@ export class StyleProcessor {
44
44
  const root = this.parse(css, stylePath);
45
45
  const imports = [];
46
46
  root.walkAtRules('import', (rule) => {
47
- const specifier = this.parseImportSpecifier(rule.params);
48
- if (specifier)
49
- imports.push({ rule, specifier });
47
+ const reference = this.parseImportSpecifierReference(rule.params);
48
+ if (reference)
49
+ imports.push({ rule, ...reference });
50
50
  });
51
- for (const { rule, specifier } of imports) {
52
- const importedPath = this.resolver.resolveStyleDependency(specifier, path.dirname(stylePath));
53
- if (!importedPath)
54
- continue;
55
- const reference = {
56
- importer: normalizedPath,
57
- imported: path.resolve(importedPath),
58
- };
59
- if (options.shouldExpandImport?.(reference) === false)
51
+ for (const { rule, specifier, specifierStart, specifierEnd } of imports) {
52
+ const { reference, isLocalStyleImport } = this.resolveStyleImportReference(specifier, stylePath);
53
+ this.assertSourceRootLocalStyleImport(reference, isLocalStyleImport);
54
+ const mappedSpecifier = options.mapImportSpecifier?.(reference);
55
+ if (mappedSpecifier) {
56
+ rule.params = `${rule.params.slice(0, specifierStart)}${mappedSpecifier}${rule.params.slice(specifierEnd)}`;
57
+ }
58
+ if (options.shouldExpandImport?.(reference) === false) {
60
59
  continue;
61
- const content = this.readStyleFile(importedPath, seen, options);
60
+ }
61
+ const content = this.readStyleFile(reference.imported, seen, options);
62
62
  if (!content.trim()) {
63
63
  rule.remove();
64
64
  continue;
65
65
  }
66
- rule.replaceWith(...(this.parse(content, importedPath).nodes ?? []));
66
+ rule.replaceWith(...(this.parse(content, reference.imported).nodes ?? []));
67
67
  }
68
68
  return root.toString();
69
69
  }
70
+ isSourceStyleImportSpecifier(specifier, importedPath) {
71
+ if (specifier.startsWith('#'))
72
+ return true;
73
+ return (this.config.styleExtensions.includes(path.extname(importedPath ?? specifier)) &&
74
+ (specifier.startsWith('.') ||
75
+ (importedPath ? this.resolver.isInsideSourceRoot(importedPath) : false)));
76
+ }
77
+ throwMissingLocalStyleImport(specifier, stylePath) {
78
+ throw new Error(`[css] local CSS import not found: ${specifier} from ${stylePath}`);
79
+ }
70
80
  collectImportedStyleFiles(styleFiles) {
71
81
  return new Set(this.collectImportedStyleFileReferences(styleFiles).map((item) => item.imported));
72
82
  }
@@ -77,14 +87,13 @@ export class StyleProcessor {
77
87
  const root = this.parse(css, styleFile);
78
88
  root.walkAtRules('import', (rule) => {
79
89
  const specifier = this.parseImportSpecifier(rule.params);
80
- if (!specifier?.startsWith('.') ||
81
- !this.config.styleExtensions.includes(path.extname(specifier))) {
90
+ if (!specifier)
91
+ return;
92
+ const { reference, isLocalStyleImport } = this.resolveStyleImportReference(specifier, styleFile);
93
+ if (!isLocalStyleImport) {
82
94
  return;
83
95
  }
84
- imports.push({
85
- importer: path.resolve(styleFile),
86
- imported: path.resolve(path.dirname(styleFile), specifier),
87
- });
96
+ imports.push(reference);
88
97
  });
89
98
  }
90
99
  return imports;
@@ -102,17 +111,117 @@ export class StyleProcessor {
102
111
  }
103
112
  return specifiers;
104
113
  }
114
+ assertNoLocalStyleImportCycles(styleFiles) {
115
+ const visited = new Set();
116
+ const visiting = new Set();
117
+ const stack = [];
118
+ const visit = (styleFile) => {
119
+ const normalizedPath = path.resolve(styleFile);
120
+ if (visited.has(normalizedPath))
121
+ return;
122
+ if (visiting.has(normalizedPath)) {
123
+ const cycleStart = stack.indexOf(normalizedPath);
124
+ const cycle = cycleStart >= 0
125
+ ? [...stack.slice(cycleStart), normalizedPath]
126
+ : [normalizedPath, normalizedPath];
127
+ throw new Error(`[css] circular CSS import detected: ${cycle.join(' -> ')}`);
128
+ }
129
+ if (!fs.existsSync(normalizedPath))
130
+ return;
131
+ visiting.add(normalizedPath);
132
+ stack.push(normalizedPath);
133
+ for (const reference of this.collectLocalStyleImportReferences(normalizedPath)) {
134
+ visit(reference.imported);
135
+ }
136
+ stack.pop();
137
+ visiting.delete(normalizedPath);
138
+ visited.add(normalizedPath);
139
+ };
140
+ for (const styleFile of styleFiles) {
141
+ visit(styleFile);
142
+ }
143
+ }
144
+ assertNoSourceRootEscapingLocalStyleImports(styleFiles) {
145
+ for (const styleFile of styleFiles) {
146
+ if (!fs.existsSync(styleFile))
147
+ continue;
148
+ for (const reference of this.collectLocalStyleImportReferences(path.resolve(styleFile))) {
149
+ this.assertSourceRootLocalStyleImport(reference, true);
150
+ }
151
+ }
152
+ }
105
153
  parse(code, from) {
106
154
  // Keep parsing behind one method so future style languages can transform
107
155
  // to CSS before PostCSS reads the final stylesheet.
108
156
  return postcss.parse(code, { from });
109
157
  }
110
158
  parseImportSpecifier(params) {
159
+ return this.parseImportSpecifierReference(params)?.specifier ?? null;
160
+ }
161
+ resolveStyleImportReference(specifier, stylePath) {
162
+ const fromDir = path.dirname(stylePath);
163
+ const sourceStylePath = this.resolver.resolveSourceStyleDependency(specifier, fromDir);
164
+ const isSourceStyleSpecifier = this.isSourceStyleImportSpecifier(specifier, sourceStylePath);
165
+ if (isSourceStyleSpecifier) {
166
+ if (!sourceStylePath || !fs.existsSync(sourceStylePath)) {
167
+ this.throwMissingLocalStyleImport(specifier, stylePath);
168
+ }
169
+ return {
170
+ reference: {
171
+ importer: path.resolve(stylePath),
172
+ imported: path.resolve(sourceStylePath),
173
+ specifier,
174
+ },
175
+ isLocalStyleImport: true,
176
+ };
177
+ }
178
+ const importedPath = this.resolver.resolveStyleDependency(specifier, fromDir);
179
+ return {
180
+ reference: {
181
+ importer: path.resolve(stylePath),
182
+ imported: path.resolve(importedPath),
183
+ specifier,
184
+ },
185
+ isLocalStyleImport: false,
186
+ };
187
+ }
188
+ assertSourceRootLocalStyleImport(reference, isLocalStyleImport) {
189
+ if (!isLocalStyleImport ||
190
+ !this.resolver.isInsideSourceRoot(reference.importer) ||
191
+ this.resolver.isInsideSourceRoot(reference.imported)) {
192
+ return;
193
+ }
194
+ throw new Error(`[css] local CSS import escapes source root: ${reference.specifier} from ${reference.importer}`);
195
+ }
196
+ collectLocalStyleImportReferences(styleFile) {
197
+ const imports = [];
198
+ const css = fs.readFileSync(styleFile, 'utf8');
199
+ const root = this.parse(css, styleFile);
200
+ root.walkAtRules('import', (rule) => {
201
+ const specifier = this.parseImportSpecifier(rule.params);
202
+ if (!specifier)
203
+ return;
204
+ const { reference, isLocalStyleImport } = this.resolveStyleImportReference(specifier, styleFile);
205
+ if (!isLocalStyleImport) {
206
+ return;
207
+ }
208
+ imports.push(reference);
209
+ });
210
+ return imports;
211
+ }
212
+ parseImportSpecifierReference(params) {
111
213
  const value = params.trim();
214
+ const valueOffset = params.indexOf(value);
112
215
  const first = value[0];
113
216
  if (first === '"' || first === "'") {
114
217
  const end = value.indexOf(first, 1);
115
- return end > 0 ? value.slice(1, end) : null;
218
+ return end > 0
219
+ ? {
220
+ specifier: value.slice(1, end),
221
+ specifierStart: valueOffset + 1,
222
+ specifierEnd: valueOffset + end,
223
+ }
224
+ : null;
116
225
  }
117
226
  if (!value.startsWith('url(')) {
118
227
  return null;
@@ -124,8 +233,24 @@ export class StyleProcessor {
124
233
  const quote = url[0];
125
234
  if (quote === '"' || quote === "'") {
126
235
  const quoteEnd = url.indexOf(quote, 1);
127
- return quoteEnd > 0 ? url.slice(1, quoteEnd) : null;
236
+ const quotedValueStart = value.indexOf(quote, 4);
237
+ return quoteEnd > 0
238
+ ? {
239
+ specifier: url.slice(1, quoteEnd),
240
+ specifierStart: valueOffset + quotedValueStart + 1,
241
+ specifierEnd: valueOffset + quotedValueStart + quoteEnd,
242
+ }
243
+ : null;
128
244
  }
129
- return url || null;
245
+ if (!url)
246
+ return null;
247
+ const rawUrl = value.slice(4, end);
248
+ const leadingSpaces = rawUrl.length - rawUrl.trimStart().length;
249
+ const trailingSpaces = rawUrl.length - rawUrl.trimEnd().length;
250
+ return {
251
+ specifier: url,
252
+ specifierStart: valueOffset + 4 + leadingSpaces,
253
+ specifierEnd: valueOffset + end - trailingSpaces,
254
+ };
130
255
  }
131
256
  }
@@ -3,8 +3,13 @@ export declare class WorkspaceStyleResolver {
3
3
  private readonly config;
4
4
  private readonly context;
5
5
  private readonly require;
6
+ readonly sourceRoot: string;
6
7
  constructor(config: ModuleStyleBuildConfig, context: ResolvedModuleStyleBuildContext);
7
8
  resolveStyleDependency(specifier: string, fromDir?: string): string;
9
+ resolveSourceStyleDependency(specifier: string, fromDir?: string): string | null;
10
+ isInsideSourceRoot(file: string): boolean;
11
+ isStyleFile(file: string): boolean;
8
12
  toOutputStyleSpecifier(specifier: string, outRoot: string): string;
9
13
  toExternalStyleSpecifier(specifier: string, outRoot: string): string;
14
+ private resolveSourceImportPaths;
10
15
  }
@@ -1,20 +1,26 @@
1
1
  import path from 'node:path';
2
2
  import { createRequire } from 'node:module';
3
3
  import { NODE_MODULES_DIR } from '#auklet/css/constants';
4
+ import { resolvePackageImportsSourceImport } from '#auklet/css/core/resolvers/packageImports';
5
+ import { resolveTsconfigPathsSourceImport } from '#auklet/css/core/resolvers/tsconfigPaths';
4
6
  import { createExternalStyleSpecifier, createOutputStyleSpecifier, } from '#auklet/css/core/style/specifier';
5
7
  export class WorkspaceStyleResolver {
6
8
  config;
7
9
  context;
8
10
  require;
11
+ sourceRoot;
9
12
  constructor(config, context) {
10
13
  this.config = config;
11
14
  this.context = context;
15
+ this.sourceRoot = path.isAbsolute(context.sourceDir)
16
+ ? context.sourceDir
17
+ : path.join(context.packageRoot, context.sourceDir);
12
18
  this.require = createRequire(path.join(this.context.packageRoot, 'package.json'));
13
19
  }
14
20
  resolveStyleDependency(specifier, fromDir = this.context.packageRoot) {
15
- if (specifier.startsWith('.')) {
16
- return path.resolve(fromDir, specifier);
17
- }
21
+ const sourceStyleDependency = this.resolveSourceStyleDependency(specifier, fromDir);
22
+ if (sourceStyleDependency)
23
+ return sourceStyleDependency;
18
24
  try {
19
25
  return this.require.resolve(specifier, {
20
26
  paths: [this.context.packageRoot],
@@ -24,6 +30,26 @@ export class WorkspaceStyleResolver {
24
30
  return path.resolve(this.context.packageRoot, NODE_MODULES_DIR, specifier);
25
31
  }
26
32
  }
33
+ resolveSourceStyleDependency(specifier, fromDir = this.context.packageRoot) {
34
+ if (specifier.startsWith('.')) {
35
+ return path.resolve(fromDir, specifier);
36
+ }
37
+ for (const sourceRelativePath of this.resolveSourceImportPaths(specifier)) {
38
+ const file = path.join(this.sourceRoot, sourceRelativePath);
39
+ if (this.isStyleFile(file))
40
+ return file;
41
+ }
42
+ return null;
43
+ }
44
+ isInsideSourceRoot(file) {
45
+ const relative = path.relative(this.sourceRoot, file);
46
+ return (Boolean(relative) &&
47
+ !relative.startsWith('..') &&
48
+ !path.isAbsolute(relative));
49
+ }
50
+ isStyleFile(file) {
51
+ return this.config.styleExtensions.includes(path.extname(file));
52
+ }
27
53
  toOutputStyleSpecifier(specifier, outRoot) {
28
54
  return createOutputStyleSpecifier(specifier, {
29
55
  currentOutputFormat: path.basename(outRoot),
@@ -39,4 +65,10 @@ export class WorkspaceStyleResolver {
39
65
  externalStyleFile: this.config.output.externalStyleFile,
40
66
  });
41
67
  }
68
+ resolveSourceImportPaths(specifier) {
69
+ return [
70
+ ...resolvePackageImportsSourceImport(this.context.packageRoot, this.sourceRoot, specifier),
71
+ ...resolveTsconfigPathsSourceImport(this.context.packageRoot, this.sourceRoot, specifier),
72
+ ];
73
+ }
42
74
  }
@@ -21,6 +21,7 @@ export class ModuleStyleBuilder {
21
21
  const normalizedConfig = normalizeAukletConfig(rawConfig);
22
22
  const context = this.createBuildContext(normalizedConfig);
23
23
  const packageContext = this.createPackageContext(context, normalizedConfig);
24
+ packageContext.assertNoSourceRootEscapingLocalStyleImports();
24
25
  const writerOptions = {
25
26
  config: this.config,
26
27
  context,
@@ -1,5 +1,6 @@
1
1
  import { type FormatWriterOptions } from '#auklet/css/production/format/shared';
2
2
  export declare class ModuleStyleWriter {
3
+ private readonly sourceRoot;
3
4
  private readonly config;
4
5
  private readonly packageContext;
5
6
  private readonly styleProcessor;
@@ -1,23 +1,23 @@
1
1
  import path from 'node:path';
2
- import { writeStyleFile, } from '#auklet/css/production/format/shared';
2
+ import { toRelativeImportSpecifier, writeStyleFile, } from '#auklet/css/production/format/shared';
3
3
  export class ModuleStyleWriter {
4
+ sourceRoot;
4
5
  config;
5
6
  packageContext;
6
7
  styleProcessor;
7
8
  constructor(options) {
8
9
  this.config = options.config;
9
10
  this.packageContext = options.packageContext;
11
+ this.sourceRoot = options.packageContext.sourceRoot;
10
12
  this.styleProcessor = options.packageContext.styleProcessor;
11
13
  }
12
14
  write(outRoot) {
13
15
  const target = path.join(outRoot, this.config.output.styleDir, this.config.output.moduleStyleFile);
14
- const seen = new Set();
16
+ const targetDir = path.dirname(target);
15
17
  const root = this.styleProcessor.createRoot();
16
- for (const styleFile of this.packageContext.styleFiles) {
17
- const content = this.styleProcessor.readStyleFile(styleFile, seen);
18
- if (content.trim()) {
19
- this.styleProcessor.appendStyleContent(root, content, styleFile);
20
- }
18
+ for (const styleFile of this.packageContext.getStyleEntryFiles()) {
19
+ const outputStyleFile = path.join(outRoot, path.relative(this.sourceRoot, styleFile));
20
+ this.styleProcessor.appendImportRule(root, toRelativeImportSpecifier(targetDir, outputStyleFile));
21
21
  }
22
22
  if (!root.nodes?.length)
23
23
  return null;
@@ -1,7 +1,7 @@
1
1
  import { type FormatWriterOptions } from '#auklet/css/production/format/shared';
2
2
  export declare class SourceStyleFileWriter {
3
3
  private readonly sourceRoot;
4
- private readonly packageContext;
4
+ private readonly resolver;
5
5
  private readonly styleProcessor;
6
6
  constructor(options: FormatWriterOptions);
7
7
  copy(files: Array<string>, outRoot: string): void;
@@ -1,12 +1,12 @@
1
1
  import path from 'node:path';
2
- import { writeStyleFile, } from '#auklet/css/production/format/shared';
2
+ import { toRelativeImportSpecifier, writeStyleFile, } from '#auklet/css/production/format/shared';
3
3
  export class SourceStyleFileWriter {
4
4
  sourceRoot;
5
- packageContext;
5
+ resolver;
6
6
  styleProcessor;
7
7
  constructor(options) {
8
8
  this.sourceRoot = options.packageContext.sourceRoot;
9
- this.packageContext = options.packageContext;
9
+ this.resolver = options.packageContext.resolver;
10
10
  this.styleProcessor = options.packageContext.styleProcessor;
11
11
  }
12
12
  copy(files, outRoot) {
@@ -14,7 +14,13 @@ export class SourceStyleFileWriter {
14
14
  const relative = path.relative(this.sourceRoot, sourceFile);
15
15
  const target = path.join(outRoot, relative);
16
16
  const content = this.styleProcessor.readStyleFile(sourceFile, undefined, {
17
- shouldExpandImport: (reference) => this.packageContext.shouldInlineSharedStyleImport(reference),
17
+ mapImportSpecifier: (reference) => {
18
+ if (!this.resolver.isInsideSourceRoot(reference.imported)) {
19
+ return reference.specifier;
20
+ }
21
+ return toRelativeImportSpecifier(path.dirname(target), path.join(outRoot, path.relative(this.sourceRoot, reference.imported)));
22
+ },
23
+ shouldExpandImport: () => false,
18
24
  });
19
25
  writeStyleFile(target, content);
20
26
  }
@@ -29,6 +29,7 @@ export class ModuleStyleOutputWriter {
29
29
  this.moduleEntryWriter = new ModuleStyleEntryWriter(options);
30
30
  }
31
31
  write() {
32
+ this.packageContext.assertPreservedLocalStyleImports();
32
33
  const moduleEntries = this.createModuleEntries();
33
34
  const outputs = [];
34
35
  for (const format of this.config.output.outputFormats) {
@@ -10,11 +10,14 @@ export declare class StyleCodeFactory {
10
10
  private createDependencyStyleCode;
11
11
  private createExternalStyleCode;
12
12
  private createThemeStyleCode;
13
+ private createFullModuleStyleCode;
13
14
  private createModuleStyleCode;
14
15
  private createSourceModuleStyleCode;
16
+ private createOwnSourceStyleCode;
15
17
  private toDevModuleImportSpecifier;
16
18
  private toDevExternalStyleSpecifier;
17
19
  private parsePackageStyleIdInRequest;
20
+ private toBrowserVirtualStyleSpecifier;
18
21
  private withDependencyPackage;
19
22
  private normalizeTopLevelImports;
20
23
  private isTopLevelImportRule;
@@ -6,6 +6,7 @@ import { toDevDependencyImportSpecifier } from '#auklet/css/vite/moduleGraph/dev
6
6
  import { EXTERNAL_ENTRY, MODULE_ENTRY, STYLE_ENTRY, THEMES_ENTRY_PREFIX, } from '#auklet/css/constants';
7
7
  import { createModuleStyleEntryPlan, createExternalEntryParts, createStyleEntryParts, createThemeEntryParts, } from '#auklet/css/core/style/entries';
8
8
  import { createDevExternalStyleSpecifier, createDevModuleStyleSpecifier, createImportCode, removeStyleExtension, } from '#auklet/css/core/style/specifier';
9
+ import { toFsSpecifier } from '#auklet/utils';
9
10
  // 生成 Vite/dev 虚拟 CSS;production writer 共享入口语义,但写入真实文件。
10
11
  export class StyleCodeFactory {
11
12
  config;
@@ -57,7 +58,7 @@ export class StyleCodeFactory {
57
58
  results.push(await this.createThemeStyleCode(context, cache, part.themeNames, false));
58
59
  continue;
59
60
  }
60
- results.push(this.createModuleStyleCode(context));
61
+ results.push(this.createFullModuleStyleCode(context));
61
62
  }
62
63
  return mergeLoadResults(...results);
63
64
  }
@@ -125,7 +126,7 @@ export class StyleCodeFactory {
125
126
  watchFiles: [],
126
127
  });
127
128
  }
128
- createModuleStyleCode(context) {
129
+ createFullModuleStyleCode(context) {
129
130
  const { styleFiles } = context.packageContext;
130
131
  const root = context.styleProcessor.createRoot();
131
132
  const seen = new Set();
@@ -140,7 +141,19 @@ export class StyleCodeFactory {
140
141
  watchFiles: [...context.configPaths, ...styleFiles],
141
142
  };
142
143
  }
144
+ createModuleStyleCode(context) {
145
+ context.packageContext.assertPreservedLocalStyleImports();
146
+ const { styleFiles } = context.packageContext;
147
+ const imports = context.packageContext
148
+ .getStyleEntryFiles()
149
+ .map((styleFile) => toFsSpecifier(styleFile));
150
+ return {
151
+ code: createImportCode(imports),
152
+ watchFiles: [...context.configPaths, ...styleFiles],
153
+ };
154
+ }
143
155
  async createSourceModuleStyleCode(context, cache, stylePath) {
156
+ context.packageContext.assertPreservedLocalStyleImports();
144
157
  const sourceModuleDir = removeStyleExtension(stylePath);
145
158
  const { styleFiles, sourceFiles } = context.packageContext;
146
159
  const entry = createModuleStyleEntryPlan(context.packageContext, sourceModuleDir);
@@ -153,8 +166,12 @@ export class StyleCodeFactory {
153
166
  const result = this.toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir);
154
167
  const parsed = this.parsePackageStyleIdInRequest(result, cache);
155
168
  if (parsed) {
156
- const loadResult = await this.createPackageStyleCode(parsed, cache);
157
- moduleStyleResults.push(this.withDependencyPackage(loadResult, parsed.packageName));
169
+ const dependencyResult = await this.createPackageStyleCode(parsed, cache);
170
+ moduleStyleResults.push(this.withDependencyPackage({
171
+ ...dependencyResult,
172
+ code: '',
173
+ }, parsed.packageName));
174
+ moduleStyleSpecifiers.push(this.toBrowserVirtualStyleSpecifier(parsed));
158
175
  continue;
159
176
  }
160
177
  const resolvedSpecifier = toDevDependencyImportSpecifier(context, result);
@@ -164,17 +181,7 @@ export class StyleCodeFactory {
164
181
  moduleStyleWatchFiles.push(resolvedSpecifier.watchFile);
165
182
  }
166
183
  }
167
- const root = context.styleProcessor.createRoot();
168
- const seen = new Set();
169
- for (const ownStyleFile of entry.ownStyleFiles) {
170
- const content = context.styleProcessor.readStyleFile(ownStyleFile, seen);
171
- if (content.trim()) {
172
- context.styleProcessor.appendStyleContent(root, content, ownStyleFile);
173
- }
174
- }
175
- const ownStyleCode = root.nodes?.length
176
- ? context.styleProcessor.stringify(root)
177
- : '';
184
+ const ownStyleCode = this.createOwnSourceStyleCode(context, entry.ownStyleFiles);
178
185
  return mergeLoadResults(...moduleStyleResults, {
179
186
  code: [createImportCode(moduleStyleSpecifiers), ownStyleCode]
180
187
  .filter((code) => code.trim())
@@ -188,6 +195,24 @@ export class StyleCodeFactory {
188
195
  cacheInputFiles: moduleStyleCacheInputFiles,
189
196
  });
190
197
  }
198
+ createOwnSourceStyleCode(context, styleFiles) {
199
+ const root = context.styleProcessor.createRoot();
200
+ for (const styleFile of styleFiles) {
201
+ const content = context.styleProcessor.readStyleFile(styleFile, undefined, {
202
+ mapImportSpecifier: (reference) => {
203
+ if (!context.resolver.isInsideSourceRoot(reference.imported)) {
204
+ return reference.specifier;
205
+ }
206
+ return toFsSpecifier(reference.imported);
207
+ },
208
+ shouldExpandImport: () => false,
209
+ });
210
+ if (content.trim()) {
211
+ context.styleProcessor.appendStyleContent(root, content, styleFile);
212
+ }
213
+ }
214
+ return root.nodes?.length ? context.styleProcessor.stringify(root) : '';
215
+ }
191
216
  toDevModuleImportSpecifier(specifier, context, cache, sourceStyleDir) {
192
217
  return createDevModuleStyleSpecifier(specifier, {
193
218
  sourceStyleDir,
@@ -209,6 +234,9 @@ export class StyleCodeFactory {
209
234
  parsePackageStyleIdInRequest(id, cache) {
210
235
  return parsePackageStyleId(id, cache.getPackageNames());
211
236
  }
237
+ toBrowserVirtualStyleSpecifier(parsed) {
238
+ return `auklet-css:${parsed.packageName}/${parsed.stylePath}`;
239
+ }
212
240
  withDependencyPackage(result, packageName) {
213
241
  return {
214
242
  ...result,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auklet",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "type": "module",
5
5
  "author": "chentao.arthur",
6
6
  "description": "Build utilities for TypeScript packages and module CSS output.",