Skip to content

Commit 4ad48c4

Browse files
committed
fix: enhance setOptions to support both ES modules and CommonJS config exports
#1340
1 parent 7ad2fb7 commit 4ad48c4

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { Command } from "commander";
2+
import * as fs from "fs";
3+
import * as path from "path";
4+
import { parseCommandOptions, getOptions } from "../../src/bin";
5+
import { setOptions } from "../../src";
6+
7+
describe("PurgeCSS CLI config file loading", () => {
8+
const testDir = path.join(__dirname, "../test_examples/config-loading");
9+
const cjsConfigPath = path.join(testDir, "purgecss.config.cjs");
10+
const cssPath = path.join(testDir, "test.css");
11+
const htmlPath = path.join(testDir, "test.html");
12+
13+
beforeAll(() => {
14+
// Create test directory and files
15+
fs.mkdirSync(testDir, { recursive: true });
16+
17+
// CommonJS config with module.exports
18+
// This tests the fix for: https://github.com/FullHuman/purgecss/issues/XXX
19+
// When using `await import()` with CommonJS, Node.js wraps the export in
20+
// `{ default: {...} }`, which needs to be properly extracted.
21+
fs.writeFileSync(
22+
cjsConfigPath,
23+
'module.exports = { blocklist: ["blocked"], fontFace: true };',
24+
);
25+
26+
// Test CSS file
27+
fs.writeFileSync(
28+
cssPath,
29+
".used { color: red; } .blocked { color: blue; }",
30+
);
31+
32+
// Test HTML file
33+
fs.writeFileSync(htmlPath, '<div class="used"></div>');
34+
});
35+
36+
afterAll(() => {
37+
// Clean up test files
38+
fs.rmSync(testDir, { recursive: true, force: true });
39+
});
40+
41+
describe("setOptions", () => {
42+
it("should correctly load CommonJS config with module.exports", async () => {
43+
const originalCwd = process.cwd();
44+
process.chdir(testDir);
45+
46+
try {
47+
const options = await setOptions("purgecss.config.cjs");
48+
expect(options.blocklist).toEqual(["blocked"]);
49+
expect(options.fontFace).toBe(true);
50+
} finally {
51+
process.chdir(originalCwd);
52+
}
53+
});
54+
});
55+
56+
describe("getOptions with config file", () => {
57+
it("should load and merge CommonJS config from --config flag", async () => {
58+
const program = parseCommandOptions(new Command());
59+
program.parse([
60+
"purgecss",
61+
"",
62+
"--css",
63+
cssPath,
64+
"--content",
65+
htmlPath,
66+
"--config",
67+
cjsConfigPath,
68+
]);
69+
70+
const options = await getOptions(program);
71+
expect(options.blocklist).toEqual(["blocked"]);
72+
expect(options.fontFace).toBe(true);
73+
});
74+
75+
it("should allow CLI options to override config file options", async () => {
76+
const program = parseCommandOptions(new Command());
77+
program.parse([
78+
"purgecss",
79+
"",
80+
"--css",
81+
cssPath,
82+
"--content",
83+
htmlPath,
84+
"--config",
85+
cjsConfigPath,
86+
"--blocklist",
87+
"overridden",
88+
]);
89+
90+
const options = await getOptions(program);
91+
// CLI blocklist should override config file blocklist
92+
expect(options.blocklist).toEqual(["overridden"]);
93+
// Config file fontFace should still be applied
94+
expect(options.fontFace).toBe(true);
95+
});
96+
});
97+
});

packages/purgecss/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,12 @@ export async function setOptions(
9090
let options: Options;
9191
try {
9292
const t = path.resolve(process.cwd(), configFile);
93-
options = await import(t);
93+
const importedConfig = await import(t);
94+
// Handle both ES modules (direct export) and CommonJS (default export)
95+
options =
96+
importedConfig.default && typeof importedConfig.default === "object"
97+
? importedConfig.default
98+
: importedConfig;
9499
} catch (err: unknown) {
95100
if (err instanceof Error) {
96101
throw new Error(`${ERROR_CONFIG_FILE_LOADING} ${err.message}`);

0 commit comments

Comments
 (0)