Skip to content

Commit 4f6c4d9

Browse files
committed
fix(#995): preserve relative paths in source maps
1 parent aa5ac9d commit 4f6c4d9

File tree

5 files changed

+78
-3
lines changed

5 files changed

+78
-3
lines changed

packages/purgecss/__tests__/sourcemap.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,61 @@ describe("source map option", () => {
2323
},
2424
});
2525

26+
// When from and to are the same file (no explicit to), the source is just the filename
2627
expect(resultsPurge[0].sourceMap).toContain(
27-
'sources":["__tests__/test_examples/others/remove_unused.css"]',
28+
'sources":["remove_unused.css"]',
2829
);
30+
expect(resultsPurge[0].sourceMap).toContain('"file":"remove_unused.css"');
31+
});
32+
33+
it("uses correct file field when 'to' option is specified", async () => {
34+
const resultsPurge = await new PurgeCSS().purge({
35+
content: [`${ROOT_TEST_EXAMPLES}others/remove_unused.js`],
36+
css: [`${ROOT_TEST_EXAMPLES}others/remove_unused.css`],
37+
sourceMap: {
38+
inline: false,
39+
to: "output.css",
40+
},
41+
});
42+
43+
// When 'to' is specified, the file field should match
44+
expect(resultsPurge[0].sourceMap).toContain('"file":"output.css"');
45+
});
46+
47+
it("preserves relative source paths from preprocessor source maps", async () => {
48+
// This test simulates a CSS file compiled from Stylus with an inline source map
49+
// The source map has a relative path "../stylus/styles.styl"
50+
const resultsPurge = await new PurgeCSS().purge({
51+
content: [`${ROOT_TEST_EXAMPLES}sourcemap/content.html`],
52+
css: [`${ROOT_TEST_EXAMPLES}sourcemap/css/styles.css`],
53+
sourceMap: true,
54+
});
55+
56+
// Decode the inline source map from the output
57+
const css = resultsPurge[0].css;
58+
const match = css.match(
59+
/sourceMappingURL=data:application\/json;base64,([A-Za-z0-9+/=]+)/,
60+
);
61+
expect(match).not.toBeNull();
62+
63+
const sourceMap = JSON.parse(Buffer.from(match![1], "base64").toString());
64+
65+
// The relative path "../stylus/styles.styl" should be preserved exactly
66+
expect(sourceMap.sources).toContain("../stylus/styles.styl");
67+
});
68+
69+
it("preserves relative source paths with inline: false", async () => {
70+
const resultsPurge = await new PurgeCSS().purge({
71+
content: [`${ROOT_TEST_EXAMPLES}sourcemap/content.html`],
72+
css: [`${ROOT_TEST_EXAMPLES}sourcemap/css/styles.css`],
73+
sourceMap: {
74+
inline: false,
75+
},
76+
});
77+
78+
const sourceMap = JSON.parse(resultsPurge[0].sourceMap!);
79+
80+
// The relative path "../stylus/styles.styl" should be preserved exactly
81+
expect(sourceMap.sources).toContain("../stylus/styles.styl");
2982
});
3083
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<html>
2+
<body>
3+
<div class="used-class">Hello</div>
4+
</body>
5+
</html>

packages/purgecss/__tests__/test_examples/sourcemap/css/styles.css

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
$primary-color = blue
2+
3+
.used-class
4+
color: $primary-color
5+
6+
.unused-class
7+
background: red

packages/purgecss/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,9 +676,12 @@ class PurgeCSS {
676676
const postCSSResult = root.toResult({
677677
map: this.options.sourceMap,
678678
to:
679-
typeof this.options.sourceMap === "object"
679+
typeof this.options.sourceMap === "object" &&
680+
this.options.sourceMap.to
680681
? this.options.sourceMap.to
681-
: undefined,
682+
: isFromFile
683+
? option
684+
: undefined,
682685
});
683686
const result: ResultPurge = {
684687
css: postCSSResult.toString(),

0 commit comments

Comments
 (0)