@ecopages/postcss-processor 0.2.0-alpha.2 → 0.2.0-alpha.21
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 +6 -7
- package/README.md +32 -68
- package/package.json +6 -6
- package/src/index.d.ts +2 -2
- package/src/index.js +2 -2
- package/src/plugin.d.ts +77 -2
- package/src/plugin.js +241 -16
- package/src/presets/index.d.ts +2 -2
- package/src/presets/index.js +2 -2
- package/src/presets/tailwind-v3.d.ts +2 -0
- package/src/presets/tailwind-v3.js +10 -7
- package/src/presets/tailwind-v4.d.ts +2 -0
- package/src/presets/tailwind-v4.js +17 -7
- 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/src/index.ts +0 -2
- package/src/plugin.ts +0 -354
- package/src/postcss-processor.ts +0 -157
- package/src/presets/index.ts +0 -7
- package/src/presets/tailwind-v3.ts +0 -61
- package/src/presets/tailwind-v4.ts +0 -113
- package/src/runtime/css-loader-plugin.ts +0 -37
- package/src/runtime/css-loader.bun.ts +0 -30
- package/src/runtime/css-runtime-contract.ts +0 -6
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
|
});
|
|
@@ -11,8 +11,17 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
11
11
|
static DEFAULT_OPTIONS = {
|
|
12
12
|
filter: /\.css$/
|
|
13
13
|
};
|
|
14
|
+
buildContributionsPrepared = false;
|
|
14
15
|
postcssPlugins = [];
|
|
16
|
+
pluginFactories;
|
|
15
17
|
runtimeCssCache = /* @__PURE__ */ new Map();
|
|
18
|
+
trackedCssFiles = /* @__PURE__ */ new Set();
|
|
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();
|
|
16
25
|
getCssFilter() {
|
|
17
26
|
return this.options?.filter ?? PostCssProcessorPlugin.DEFAULT_OPTIONS.filter;
|
|
18
27
|
}
|
|
@@ -53,6 +62,7 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
53
62
|
if (!this.matchesFileFilter(filePath)) {
|
|
54
63
|
continue;
|
|
55
64
|
}
|
|
65
|
+
this.trackedCssFiles.add(filePath);
|
|
56
66
|
const rawContents = await fileSystem.readFile(filePath);
|
|
57
67
|
let transformedInput = rawContents;
|
|
58
68
|
if (this.options?.transformInput) {
|
|
@@ -62,6 +72,69 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
62
72
|
this.runtimeCssCache.set(filePath, processed);
|
|
63
73
|
await this.persistProcessedCss(filePath, processed);
|
|
64
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);
|
|
65
138
|
}
|
|
66
139
|
transformCssSync(input) {
|
|
67
140
|
const cached = this.runtimeCssCache.get(input.filePath);
|
|
@@ -92,6 +165,51 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
92
165
|
const filter = this.options?.filter ?? PostCssProcessorPlugin.DEFAULT_OPTIONS.filter;
|
|
93
166
|
return filter.test(filepath);
|
|
94
167
|
}
|
|
168
|
+
materializePluginFactories(pluginFactories) {
|
|
169
|
+
return Object.values(pluginFactories).map((factory) => factory());
|
|
170
|
+
}
|
|
171
|
+
refreshConfiguredPlugins() {
|
|
172
|
+
if (!this.pluginFactories) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.postcssPlugins = this.materializePluginFactories(this.pluginFactories);
|
|
176
|
+
}
|
|
177
|
+
enqueueWatchTask(task) {
|
|
178
|
+
const queuedTask = this.watchQueue.then(task, task);
|
|
179
|
+
this.watchQueue = queuedTask.catch(() => void 0);
|
|
180
|
+
return queuedTask;
|
|
181
|
+
}
|
|
182
|
+
getTrackedCssFiles() {
|
|
183
|
+
return Array.from(this.trackedCssFiles).filter(
|
|
184
|
+
(filePath) => this.matchesFileFilter(filePath) && fileSystem.exists(filePath)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
getTrackedCssEntryFiles() {
|
|
188
|
+
const importedCssFiles = new Set(this.cssDependencyMap.keys());
|
|
189
|
+
return this.getTrackedCssFiles().filter((filePath) => !importedCssFiles.has(filePath));
|
|
190
|
+
}
|
|
191
|
+
getDependencyEntryFiles() {
|
|
192
|
+
const configuredEntryPaths = this.options?.dependencyEntryPaths;
|
|
193
|
+
if (!configuredEntryPaths || configuredEntryPaths.length === 0) {
|
|
194
|
+
return this.getTrackedCssEntryFiles();
|
|
195
|
+
}
|
|
196
|
+
return configuredEntryPaths.filter(
|
|
197
|
+
(filePath) => this.matchesFileFilter(filePath) && fileSystem.exists(filePath)
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
async handleDependencyChange(bridge) {
|
|
201
|
+
if (!this.context) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const cssFiles = this.getDependencyEntryFiles();
|
|
205
|
+
if (cssFiles.length === 0) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
this.refreshConfiguredPlugins();
|
|
209
|
+
for (const cssFilePath of cssFiles) {
|
|
210
|
+
await this.handleCssChange(cssFilePath, bridge, false);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
95
213
|
constructor(config = {
|
|
96
214
|
options: PostCssProcessorPlugin.DEFAULT_OPTIONS
|
|
97
215
|
}) {
|
|
@@ -101,14 +219,56 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
101
219
|
capabilities: [
|
|
102
220
|
{
|
|
103
221
|
kind: "stylesheet",
|
|
104
|
-
extensions: ["*.css"]
|
|
222
|
+
extensions: ["*.{css,scss,sass,less}"]
|
|
105
223
|
}
|
|
106
224
|
],
|
|
107
225
|
watch: {
|
|
108
226
|
paths: [],
|
|
109
|
-
extensions: [
|
|
227
|
+
extensions: [
|
|
228
|
+
".css",
|
|
229
|
+
".scss",
|
|
230
|
+
".sass",
|
|
231
|
+
".less",
|
|
232
|
+
".tsx",
|
|
233
|
+
".ts",
|
|
234
|
+
".jsx",
|
|
235
|
+
".js",
|
|
236
|
+
".mdx",
|
|
237
|
+
".html",
|
|
238
|
+
".svelte",
|
|
239
|
+
".vue"
|
|
240
|
+
],
|
|
110
241
|
onChange: async ({ path: path2, bridge }) => {
|
|
111
|
-
await this.
|
|
242
|
+
await this.enqueueWatchTask(async () => {
|
|
243
|
+
if (this.matchesFileFilter(path2)) {
|
|
244
|
+
await this.handleCssChange(path2, bridge);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
await this.handleDependencyChange(bridge);
|
|
248
|
+
});
|
|
249
|
+
},
|
|
250
|
+
onCreate: async ({ path: path2, bridge }) => {
|
|
251
|
+
await this.enqueueWatchTask(async () => {
|
|
252
|
+
if (this.matchesFileFilter(path2)) {
|
|
253
|
+
this.trackedCssFiles.add(path2);
|
|
254
|
+
this.buildCssDependencyMap();
|
|
255
|
+
await this.handleCssChange(path2, bridge);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
await this.handleDependencyChange(bridge);
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
onDelete: async ({ path: path2, bridge }) => {
|
|
262
|
+
await this.enqueueWatchTask(async () => {
|
|
263
|
+
if (this.matchesFileFilter(path2)) {
|
|
264
|
+
this.runtimeCssCache.delete(path2);
|
|
265
|
+
this.trackedCssFiles.delete(path2);
|
|
266
|
+
this.cssDependencyMap.delete(path2);
|
|
267
|
+
this.buildCssDependencyMap();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
await this.handleDependencyChange(bridge);
|
|
271
|
+
});
|
|
112
272
|
}
|
|
113
273
|
},
|
|
114
274
|
...config
|
|
@@ -116,16 +276,44 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
116
276
|
}
|
|
117
277
|
/**
|
|
118
278
|
* Handles CSS file changes during development.
|
|
119
|
-
*
|
|
279
|
+
* If the file is an @import dependency, re-processes the parent entry file(s) instead.
|
|
280
|
+
* Broadcasts a css-update event for hot reloading.
|
|
281
|
+
*/
|
|
282
|
+
async handleCssChange(filePath, bridge, refreshPlugins = true) {
|
|
283
|
+
if (!this.context) return;
|
|
284
|
+
if (!fileSystem.exists(filePath)) return;
|
|
285
|
+
const entryFiles = this.resolveEntryFiles(filePath);
|
|
286
|
+
if (entryFiles.length > 0) {
|
|
287
|
+
logger.debug(`CSS dependency changed: ${filePath}, re-processing ${entryFiles.length} parent(s)`);
|
|
288
|
+
for (const entryFile of entryFiles) {
|
|
289
|
+
this.runtimeCssCache.delete(entryFile);
|
|
290
|
+
await this.processAndBroadcast(entryFile, bridge, refreshPlugins);
|
|
291
|
+
}
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
await this.processAndBroadcast(filePath, bridge, refreshPlugins);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Processes a CSS file and broadcasts a css-update event.
|
|
298
|
+
* Skips broadcast if the processed output hasn't changed.
|
|
120
299
|
*/
|
|
121
|
-
async
|
|
300
|
+
async processAndBroadcast(filePath, bridge, refreshPlugins = true) {
|
|
122
301
|
if (!this.context) return;
|
|
302
|
+
if (!fileSystem.exists(filePath)) return;
|
|
123
303
|
try {
|
|
304
|
+
this.trackedCssFiles.add(filePath);
|
|
305
|
+
if (refreshPlugins) {
|
|
306
|
+
this.refreshConfiguredPlugins();
|
|
307
|
+
}
|
|
124
308
|
let content = await fileSystem.readFile(filePath);
|
|
125
309
|
if (this.options?.transformInput) {
|
|
126
310
|
content = await this.options.transformInput(content, filePath);
|
|
127
311
|
}
|
|
128
312
|
const processed = await this.process(content, filePath);
|
|
313
|
+
const cached = this.runtimeCssCache.get(filePath);
|
|
314
|
+
if (cached === processed) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
129
317
|
this.runtimeCssCache.set(filePath, processed);
|
|
130
318
|
await this.persistProcessedCss(filePath, processed);
|
|
131
319
|
bridge.cssUpdate(filePath);
|
|
@@ -155,10 +343,24 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
155
343
|
];
|
|
156
344
|
}
|
|
157
345
|
/**
|
|
158
|
-
*
|
|
346
|
+
* Resolves the configured PostCSS plugin list before config build seals the
|
|
347
|
+
* app manifest.
|
|
348
|
+
*
|
|
349
|
+
* @remarks
|
|
350
|
+
* Runtime setup reuses this prepared list and only performs cache prewarming.
|
|
159
351
|
*/
|
|
160
|
-
async
|
|
352
|
+
async prepareBuildContributions() {
|
|
353
|
+
if (this.buildContributionsPrepared) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
161
356
|
await this.collectPostcssPlugins();
|
|
357
|
+
this.buildContributionsPrepared = true;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Prepares build contributions if not already done and prewarms the runtime CSS cache.
|
|
361
|
+
*/
|
|
362
|
+
async setup() {
|
|
363
|
+
await this.prepareBuildContributions();
|
|
162
364
|
await this.prewarmRuntimeCssCache();
|
|
163
365
|
}
|
|
164
366
|
/**
|
|
@@ -172,6 +374,7 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
172
374
|
const configExtensions = ["js", "cjs", "mjs", "ts"];
|
|
173
375
|
let foundConfigPath;
|
|
174
376
|
let loadedPlugins;
|
|
377
|
+
let loadedPluginFactories;
|
|
175
378
|
for (const ext of configExtensions) {
|
|
176
379
|
const configPath = path.join(this.context.rootDir, `postcss.config.${ext}`);
|
|
177
380
|
if (fileSystem.exists(configPath)) {
|
|
@@ -182,8 +385,14 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
182
385
|
if (foundConfigPath) {
|
|
183
386
|
try {
|
|
184
387
|
logger.debug(`Loading PostCSS config from: ${foundConfigPath}`);
|
|
185
|
-
const postcssConfigModule = await import(
|
|
388
|
+
const postcssConfigModule = await import(
|
|
389
|
+
/* @vite-ignore */
|
|
390
|
+
foundConfigPath
|
|
391
|
+
);
|
|
186
392
|
const postcssConfig = postcssConfigModule.default || postcssConfigModule;
|
|
393
|
+
if (postcssConfig && typeof postcssConfig.pluginFactories === "object" && postcssConfig.pluginFactories !== null) {
|
|
394
|
+
loadedPluginFactories = postcssConfig.pluginFactories;
|
|
395
|
+
}
|
|
187
396
|
if (postcssConfig && typeof postcssConfig.plugins === "object" && postcssConfig.plugins !== null) {
|
|
188
397
|
if (Array.isArray(postcssConfig.plugins)) {
|
|
189
398
|
loadedPlugins = postcssConfig.plugins;
|
|
@@ -203,15 +412,26 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
203
412
|
} else {
|
|
204
413
|
logger.debug("No PostCSS config file found in root directory.");
|
|
205
414
|
}
|
|
206
|
-
if (
|
|
415
|
+
if (loadedPluginFactories) {
|
|
416
|
+
this.pluginFactories = loadedPluginFactories;
|
|
417
|
+
this.postcssPlugins = this.materializePluginFactories(loadedPluginFactories);
|
|
418
|
+
} else if (loadedPlugins) {
|
|
419
|
+
this.pluginFactories = void 0;
|
|
207
420
|
this.postcssPlugins = loadedPlugins;
|
|
208
|
-
} else if (this.options?.plugins) {
|
|
209
|
-
|
|
210
|
-
|
|
421
|
+
} else if (this.options?.pluginFactories || this.options?.plugins) {
|
|
422
|
+
this.pluginFactories = this.options?.pluginFactories;
|
|
423
|
+
if (this.options?.plugins) {
|
|
424
|
+
logger.debug("Using PostCSS plugins provided in processor options.");
|
|
425
|
+
this.postcssPlugins = Object.values(this.options.plugins);
|
|
426
|
+
} else if (this.options?.pluginFactories) {
|
|
427
|
+
logger.debug("Using PostCSS plugin factories provided in processor options.");
|
|
428
|
+
this.postcssPlugins = this.materializePluginFactories(this.options.pluginFactories);
|
|
429
|
+
}
|
|
211
430
|
} else {
|
|
212
431
|
logger.warn(
|
|
213
432
|
"No PostCSS plugins configured. Use a preset like tailwindV3Preset() or tailwindV4Preset(), provide plugins via options, or create a postcss.config file."
|
|
214
433
|
);
|
|
434
|
+
this.pluginFactories = void 0;
|
|
215
435
|
this.postcssPlugins = [];
|
|
216
436
|
}
|
|
217
437
|
if (!this.postcssPlugins || this.postcssPlugins.length === 0) {
|
|
@@ -226,14 +446,19 @@ class PostCssProcessorPlugin extends Processor {
|
|
|
226
446
|
* @returns Processed CSS
|
|
227
447
|
*/
|
|
228
448
|
async process(fileAsString, filePath) {
|
|
229
|
-
|
|
449
|
+
const input = this.options?.transformInput && filePath ? await this.options.transformInput(fileAsString, filePath) : fileAsString;
|
|
450
|
+
return await PostCssProcessor.processStringOrBuffer(input, {
|
|
230
451
|
filePath,
|
|
231
452
|
plugins: this.postcssPlugins,
|
|
232
453
|
transformOutput: this.options?.transformOutput
|
|
233
454
|
});
|
|
234
455
|
}
|
|
235
456
|
processSync(fileAsString, filePath) {
|
|
236
|
-
|
|
457
|
+
const input = this.options?.transformInput && filePath ? this.options.transformInput(fileAsString, filePath) : fileAsString;
|
|
458
|
+
if (input instanceof Promise) {
|
|
459
|
+
throw new Error("transformInput must be synchronous when used with processSync");
|
|
460
|
+
}
|
|
461
|
+
return PostCssProcessor.processStringOrBufferSync(input, {
|
|
237
462
|
filePath,
|
|
238
463
|
plugins: this.postcssPlugins,
|
|
239
464
|
transformOutput: this.options?.transformOutput
|
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
|
@@ -12,6 +12,8 @@ import type { PostCssProcessorPluginConfig } from '../plugin.js';
|
|
|
12
12
|
* Features:
|
|
13
13
|
* - Uses classic Tailwind v3 plugin stack
|
|
14
14
|
* - Includes postcss-import, tailwindcss/nesting, tailwindcss, autoprefixer, cssnano
|
|
15
|
+
* - Returns both `plugins` for immediate use and `pluginFactories` so Ecopages
|
|
16
|
+
* can recreate fresh Tailwind/PostCSS plugin instances on dependency-driven rebuilds
|
|
15
17
|
*
|
|
16
18
|
* @example
|
|
17
19
|
* ```typescript
|
|
@@ -9,14 +9,17 @@ function tailwindV3Preset() {
|
|
|
9
9
|
const autoprefixerOptions = browserslistConfig ? {} : {
|
|
10
10
|
overrideBrowserslist: [">0.3%", "not ie 11", "not dead", "not op_mini all"]
|
|
11
11
|
};
|
|
12
|
-
const
|
|
13
|
-
"postcss-import": postcssImport(),
|
|
14
|
-
"tailwindcss/nesting": tailwindcssNesting(),
|
|
15
|
-
tailwindcss: tailwindcss(),
|
|
16
|
-
autoprefixer: autoprefixer(autoprefixerOptions),
|
|
17
|
-
cssnano: cssnano()
|
|
12
|
+
const pluginFactories = {
|
|
13
|
+
"postcss-import": () => postcssImport(),
|
|
14
|
+
"tailwindcss/nesting": () => tailwindcssNesting(),
|
|
15
|
+
tailwindcss: () => tailwindcss(),
|
|
16
|
+
autoprefixer: () => autoprefixer(autoprefixerOptions),
|
|
17
|
+
cssnano: () => cssnano()
|
|
18
18
|
};
|
|
19
|
-
|
|
19
|
+
const plugins = Object.fromEntries(
|
|
20
|
+
Object.entries(pluginFactories).map(([name, factory]) => [name, factory()])
|
|
21
|
+
);
|
|
22
|
+
return { plugins, pluginFactories };
|
|
20
23
|
}
|
|
21
24
|
export {
|
|
22
25
|
tailwindV3Preset
|
|
@@ -23,6 +23,8 @@ export interface TailwindV4PresetOptions {
|
|
|
23
23
|
* - Uses `@tailwindcss/postcss` plugin (v4)
|
|
24
24
|
* - Automatically injects `@reference` headers for `@apply` support
|
|
25
25
|
* - Includes cssnano for CSS minification
|
|
26
|
+
* - Returns both `plugins` for immediate use and `pluginFactories` so Ecopages
|
|
27
|
+
* can recreate fresh Tailwind/PostCSS plugin instances on dependency-driven rebuilds
|
|
26
28
|
*
|
|
27
29
|
* @example
|
|
28
30
|
* ```typescript
|
|
@@ -11,14 +11,24 @@ function tailwindV4Preset(options) {
|
|
|
11
11
|
const autoprefixerOptions = browserslistConfig ? {} : {
|
|
12
12
|
overrideBrowserslist: [">0.3%", "not ie 11", "not dead", "not op_mini all"]
|
|
13
13
|
};
|
|
14
|
+
const createTailwindPlugin = () => {
|
|
15
|
+
return tailwindcss({ optimize: false });
|
|
16
|
+
};
|
|
17
|
+
const pluginFactories = {
|
|
18
|
+
"postcss-import": () => postcssImport(),
|
|
19
|
+
"postcss-nested": () => postcssNested(),
|
|
20
|
+
"@tailwindcss/postcss": createTailwindPlugin,
|
|
21
|
+
autoprefixer: () => autoprefixer(autoprefixerOptions),
|
|
22
|
+
cssnano: () => cssnano()
|
|
23
|
+
};
|
|
14
24
|
return {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
dependencyEntryPaths: [referencePath],
|
|
26
|
+
/**
|
|
27
|
+
* Instantiate the initial plugin list for the active processor instance.
|
|
28
|
+
* Fresh instances can later be recreated from `pluginFactories`.
|
|
29
|
+
*/
|
|
30
|
+
plugins: Object.fromEntries(Object.entries(pluginFactories).map(([name, factory]) => [name, factory()])),
|
|
31
|
+
pluginFactories,
|
|
22
32
|
transformInput: async (contents, filePath) => {
|
|
23
33
|
const css = contents instanceof Buffer ? contents.toString("utf-8") : contents;
|
|
24
34
|
const normalizedFilePath = path.resolve(filePath);
|
package/src/index.ts
DELETED