@ecopages/postcss-processor 0.2.0-alpha.10 → 0.2.0-alpha.12
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/CHANGELOG.md +3 -5
- package/package.json +6 -6
- package/src/index.d.ts +2 -2
- package/src/index.js +2 -2
- package/src/plugin.d.ts +34 -1
- package/src/plugin.js +98 -4
- package/src/presets/index.d.ts +2 -2
- package/src/presets/index.js +2 -2
- package/src/runtime/css-loader-plugin.d.ts +1 -1
- package/src/runtime/css-loader-plugin.js +1 -1
- package/src/runtime/css-loader.bun.d.ts +1 -1
- package/src/runtime/css-loader.bun.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,14 +8,12 @@ All notable changes to `@ecopages/postcss-processor` are documented here.
|
|
|
8
8
|
|
|
9
9
|
### Features
|
|
10
10
|
|
|
11
|
-
- Added runtime CSS
|
|
12
|
-
- Added esbuild build adapter registration and dependency graph integration to the PostCSS processor plugin.
|
|
11
|
+
- Added reusable runtime CSS loading, a public `PostcssProcessor` class, and build-adapter registration for the plugin.
|
|
13
12
|
|
|
14
13
|
### Bug Fixes
|
|
15
14
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- Disabled Tailwind v4 PostCSS optimization in the official plugin preset so preview/build no longer rewrites nested BEM selectors into invalid output.
|
|
15
|
+
- Fixed runtime PostCSS config loading and stylesheet rebuilds for Tailwind-driven template changes.
|
|
16
|
+
- Fixed direct stylesheet processing and preset output so Tailwind v4 preserves injected references and nested BEM selectors.
|
|
19
17
|
|
|
20
18
|
### Tests
|
|
21
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/postcss-processor",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.12",
|
|
4
4
|
"description": "Postcss processor, transform string or postcss file to css",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"postcss",
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
"directory": "packages/processors/postcss-processor"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@ecopages/file-system": "0.2.0-alpha.
|
|
21
|
-
"@ecopages/logger": "
|
|
20
|
+
"@ecopages/file-system": "0.2.0-alpha.12",
|
|
21
|
+
"@ecopages/logger": "^0.2.3",
|
|
22
22
|
"autoprefixer": "^10.4.0",
|
|
23
23
|
"browserslist": "^4.28.1",
|
|
24
|
-
"cssnano": "^
|
|
24
|
+
"cssnano": "^7.1.4",
|
|
25
25
|
"postcss": "^8.4.32",
|
|
26
|
-
"postcss-import": "^
|
|
26
|
+
"postcss-import": "^16.1.1",
|
|
27
27
|
"postcss-nested": "^7.0.2"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@ecopages/core": "0.2.0-alpha.
|
|
30
|
+
"@ecopages/core": "0.2.0-alpha.12",
|
|
31
31
|
"@tailwindcss/postcss": ">=4",
|
|
32
32
|
"tailwindcss": ">=3"
|
|
33
33
|
},
|
package/src/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './plugin';
|
|
2
|
-
export * from './postcss-processor';
|
|
1
|
+
export * from './plugin.js';
|
|
2
|
+
export * from './postcss-processor.js';
|
package/src/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./plugin";
|
|
2
|
-
export * from "./postcss-processor";
|
|
1
|
+
export * from "./plugin.js";
|
|
2
|
+
export * from "./postcss-processor.js";
|
package/src/plugin.d.ts
CHANGED
|
@@ -67,11 +67,38 @@ export declare class PostCssProcessorPlugin extends Processor<PostCssProcessorPl
|
|
|
67
67
|
private readonly runtimeCssCache;
|
|
68
68
|
private readonly trackedCssFiles;
|
|
69
69
|
private watchQueue;
|
|
70
|
+
/**
|
|
71
|
+
* Maps an imported CSS file path → set of tracked CSS entry files that import it.
|
|
72
|
+
* Used to resolve which parent entry files need re-processing when a dependency changes.
|
|
73
|
+
*/
|
|
74
|
+
private readonly cssDependencyMap;
|
|
70
75
|
private getCssFilter;
|
|
71
76
|
private resolveProcessedCssPath;
|
|
72
77
|
private readProcessedCssFromDist;
|
|
73
78
|
private persistProcessedCss;
|
|
74
79
|
private prewarmRuntimeCssCache;
|
|
80
|
+
/**
|
|
81
|
+
* Regex to match CSS @import statements and extract the path.
|
|
82
|
+
* Handles: @import './foo.css'; @import "./foo.css"; @import url('./foo.css');
|
|
83
|
+
*/
|
|
84
|
+
private static readonly CSS_IMPORT_REGEX;
|
|
85
|
+
/**
|
|
86
|
+
* Builds the CSS dependency map by scanning tracked CSS files for @import directives.
|
|
87
|
+
* Maps each imported file to the set of tracked entry files that import it (directly or transitively).
|
|
88
|
+
*/
|
|
89
|
+
private buildCssDependencyMap;
|
|
90
|
+
/**
|
|
91
|
+
* Extracts resolved absolute paths of CSS files imported via @import in the given CSS content.
|
|
92
|
+
* Recursively follows imports to capture transitive dependencies.
|
|
93
|
+
* It skips bare module imports like @import 'tailwindcss'.
|
|
94
|
+
* It recursively follows imports to capture transitive dependencies.
|
|
95
|
+
*/
|
|
96
|
+
private extractCssImports;
|
|
97
|
+
/**
|
|
98
|
+
* Resolves a changed CSS file to its parent entry file(s) if it is an @import dependency.
|
|
99
|
+
* Returns an empty array if the file is not an import dependency (i.e., it's an entry file itself).
|
|
100
|
+
*/
|
|
101
|
+
private resolveEntryFiles;
|
|
75
102
|
private transformCssSync;
|
|
76
103
|
private transformCssAsync;
|
|
77
104
|
matchesFileFilter(filepath: string): boolean;
|
|
@@ -83,9 +110,15 @@ export declare class PostCssProcessorPlugin extends Processor<PostCssProcessorPl
|
|
|
83
110
|
constructor(config?: Omit<ProcessorConfig<PostCssProcessorPluginConfig>, 'name' | 'description'>);
|
|
84
111
|
/**
|
|
85
112
|
* Handles CSS file changes during development.
|
|
86
|
-
*
|
|
113
|
+
* If the file is an @import dependency, re-processes the parent entry file(s) instead.
|
|
114
|
+
* Broadcasts a css-update event for hot reloading.
|
|
87
115
|
*/
|
|
88
116
|
private handleCssChange;
|
|
117
|
+
/**
|
|
118
|
+
* Processes a CSS file and broadcasts a css-update event.
|
|
119
|
+
* Skips broadcast if the processed output hasn't changed.
|
|
120
|
+
*/
|
|
121
|
+
private processAndBroadcast;
|
|
89
122
|
get buildPlugins(): EcoBuildPlugin[];
|
|
90
123
|
get plugins(): EcoBuildPlugin[];
|
|
91
124
|
/**
|
package/src/plugin.js
CHANGED
|
@@ -2,8 +2,8 @@ import path from "node:path";
|
|
|
2
2
|
import { fileSystem } from "@ecopages/file-system";
|
|
3
3
|
import { Processor } from "@ecopages/core/plugins/processor";
|
|
4
4
|
import { Logger } from "@ecopages/logger";
|
|
5
|
-
import { PostCssProcessor } from "./postcss-processor";
|
|
6
|
-
import { createCssLoaderPlugin } from "./runtime/css-loader-plugin";
|
|
5
|
+
import { PostCssProcessor } from "./postcss-processor.js";
|
|
6
|
+
import { createCssLoaderPlugin } from "./runtime/css-loader-plugin.js";
|
|
7
7
|
const logger = new Logger("[@ecopages/postcss-processor]", {
|
|
8
8
|
debug: process.env.ECOPAGES_LOGGER_DEBUG === "true"
|
|
9
9
|
});
|
|
@@ -17,6 +17,11 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
17
17
|
runtimeCssCache = /* @__PURE__ */ new Map();
|
|
18
18
|
trackedCssFiles = /* @__PURE__ */ new Set();
|
|
19
19
|
watchQueue = Promise.resolve();
|
|
20
|
+
/**
|
|
21
|
+
* Maps an imported CSS file path → set of tracked CSS entry files that import it.
|
|
22
|
+
* Used to resolve which parent entry files need re-processing when a dependency changes.
|
|
23
|
+
*/
|
|
24
|
+
cssDependencyMap = /* @__PURE__ */ new Map();
|
|
20
25
|
getCssFilter() {
|
|
21
26
|
return this.options?.filter ?? PostCssProcessorPlugin.DEFAULT_OPTIONS.filter;
|
|
22
27
|
}
|
|
@@ -67,6 +72,69 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
67
72
|
this.runtimeCssCache.set(filePath, processed);
|
|
68
73
|
await this.persistProcessedCss(filePath, processed);
|
|
69
74
|
}
|
|
75
|
+
this.buildCssDependencyMap();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Regex to match CSS @import statements and extract the path.
|
|
79
|
+
* Handles: @import './foo.css'; @import "./foo.css"; @import url('./foo.css');
|
|
80
|
+
*/
|
|
81
|
+
static CSS_IMPORT_REGEX = /@import\s+(?:url\(\s*)?['"]([^'"]+\.css)['"](?:\s*\))?\s*;/gm;
|
|
82
|
+
/**
|
|
83
|
+
* Builds the CSS dependency map by scanning tracked CSS files for @import directives.
|
|
84
|
+
* Maps each imported file to the set of tracked entry files that import it (directly or transitively).
|
|
85
|
+
*/
|
|
86
|
+
buildCssDependencyMap() {
|
|
87
|
+
this.cssDependencyMap.clear();
|
|
88
|
+
for (const entryFile of this.trackedCssFiles) {
|
|
89
|
+
if (!fileSystem.exists(entryFile)) continue;
|
|
90
|
+
const rawContents = fileSystem.readFileAsBuffer(entryFile).toString("utf-8");
|
|
91
|
+
const imports = this.extractCssImports(rawContents, entryFile);
|
|
92
|
+
for (const importedFile of imports) {
|
|
93
|
+
if (!this.cssDependencyMap.has(importedFile)) {
|
|
94
|
+
this.cssDependencyMap.set(importedFile, /* @__PURE__ */ new Set());
|
|
95
|
+
}
|
|
96
|
+
this.cssDependencyMap.get(importedFile).add(entryFile);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Extracts resolved absolute paths of CSS files imported via @import in the given CSS content.
|
|
102
|
+
* Recursively follows imports to capture transitive dependencies.
|
|
103
|
+
* It skips bare module imports like @import 'tailwindcss'.
|
|
104
|
+
* It recursively follows imports to capture transitive dependencies.
|
|
105
|
+
*/
|
|
106
|
+
extractCssImports(cssContent, fromFile, visited = /* @__PURE__ */ new Set()) {
|
|
107
|
+
const dir = path.dirname(fromFile);
|
|
108
|
+
const imports = [];
|
|
109
|
+
let match;
|
|
110
|
+
const regex = new RegExp(PostCssProcessorPlugin.CSS_IMPORT_REGEX.source, "gm");
|
|
111
|
+
while ((match = regex.exec(cssContent)) !== null) {
|
|
112
|
+
const importPath = match[1];
|
|
113
|
+
if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const resolvedPath = path.resolve(dir, importPath);
|
|
117
|
+
if (visited.has(resolvedPath)) continue;
|
|
118
|
+
visited.add(resolvedPath);
|
|
119
|
+
imports.push(resolvedPath);
|
|
120
|
+
if (fileSystem.exists(resolvedPath)) {
|
|
121
|
+
const nestedContent = fileSystem.readFileAsBuffer(resolvedPath).toString("utf-8");
|
|
122
|
+
const nestedImports = this.extractCssImports(nestedContent, resolvedPath, visited);
|
|
123
|
+
imports.push(...nestedImports);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return imports;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Resolves a changed CSS file to its parent entry file(s) if it is an @import dependency.
|
|
130
|
+
* Returns an empty array if the file is not an import dependency (i.e., it's an entry file itself).
|
|
131
|
+
*/
|
|
132
|
+
resolveEntryFiles(filePath) {
|
|
133
|
+
const entries = this.cssDependencyMap.get(filePath);
|
|
134
|
+
if (!entries || entries.size === 0) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
return Array.from(entries);
|
|
70
138
|
}
|
|
71
139
|
transformCssSync(input) {
|
|
72
140
|
const cached = this.runtimeCssCache.get(input.filePath);
|
|
@@ -169,6 +237,8 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
169
237
|
onCreate: async ({ path: path2, bridge }) => {
|
|
170
238
|
await this.enqueueWatchTask(async () => {
|
|
171
239
|
if (this.matchesFileFilter(path2)) {
|
|
240
|
+
this.trackedCssFiles.add(path2);
|
|
241
|
+
this.buildCssDependencyMap();
|
|
172
242
|
await this.handleCssChange(path2, bridge);
|
|
173
243
|
return;
|
|
174
244
|
}
|
|
@@ -180,6 +250,8 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
180
250
|
if (this.matchesFileFilter(path2)) {
|
|
181
251
|
this.runtimeCssCache.delete(path2);
|
|
182
252
|
this.trackedCssFiles.delete(path2);
|
|
253
|
+
this.cssDependencyMap.delete(path2);
|
|
254
|
+
this.buildCssDependencyMap();
|
|
183
255
|
return;
|
|
184
256
|
}
|
|
185
257
|
await this.handleDependencyChange(bridge);
|
|
@@ -191,9 +263,28 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
191
263
|
}
|
|
192
264
|
/**
|
|
193
265
|
* Handles CSS file changes during development.
|
|
194
|
-
*
|
|
266
|
+
* If the file is an @import dependency, re-processes the parent entry file(s) instead.
|
|
267
|
+
* Broadcasts a css-update event for hot reloading.
|
|
195
268
|
*/
|
|
196
269
|
async handleCssChange(filePath, bridge, refreshPlugins = true) {
|
|
270
|
+
if (!this.context) return;
|
|
271
|
+
if (!fileSystem.exists(filePath)) return;
|
|
272
|
+
const entryFiles = this.resolveEntryFiles(filePath);
|
|
273
|
+
if (entryFiles.length > 0) {
|
|
274
|
+
logger.debug(`CSS dependency changed: ${filePath}, re-processing ${entryFiles.length} parent(s)`);
|
|
275
|
+
for (const entryFile of entryFiles) {
|
|
276
|
+
this.runtimeCssCache.delete(entryFile);
|
|
277
|
+
await this.processAndBroadcast(entryFile, bridge, refreshPlugins);
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
await this.processAndBroadcast(filePath, bridge, refreshPlugins);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Processes a CSS file and broadcasts a css-update event.
|
|
285
|
+
* Skips broadcast if the processed output hasn't changed.
|
|
286
|
+
*/
|
|
287
|
+
async processAndBroadcast(filePath, bridge, refreshPlugins = true) {
|
|
197
288
|
if (!this.context) return;
|
|
198
289
|
if (!fileSystem.exists(filePath)) return;
|
|
199
290
|
try {
|
|
@@ -281,7 +372,10 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
281
372
|
if (foundConfigPath) {
|
|
282
373
|
try {
|
|
283
374
|
logger.debug(`Loading PostCSS config from: ${foundConfigPath}`);
|
|
284
|
-
const postcssConfigModule = await import(
|
|
375
|
+
const postcssConfigModule = await import(
|
|
376
|
+
/* @vite-ignore */
|
|
377
|
+
foundConfigPath
|
|
378
|
+
);
|
|
285
379
|
const postcssConfig = postcssConfigModule.default || postcssConfigModule;
|
|
286
380
|
if (postcssConfig && typeof postcssConfig.pluginFactories === "object" && postcssConfig.pluginFactories !== null) {
|
|
287
381
|
loadedPluginFactories = postcssConfig.pluginFactories;
|
package/src/presets/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* PostCSS Processor Presets
|
|
3
3
|
* @module @ecopages/postcss-processor/presets
|
|
4
4
|
*/
|
|
5
|
-
export { tailwindV3Preset } from './tailwind-v3';
|
|
6
|
-
export { tailwindV4Preset, type TailwindV4PresetOptions } from './tailwind-v4';
|
|
5
|
+
export { tailwindV3Preset } from './tailwind-v3.js';
|
|
6
|
+
export { tailwindV4Preset, type TailwindV4PresetOptions } from './tailwind-v4.js';
|
package/src/presets/index.js
CHANGED