Skip to content

Commit 14b9cb5

Browse files
committed
feat: allow implementation be passed by tooling authors
1 parent d7657e5 commit 14b9cb5

7 files changed

+153
-1
lines changed

Diff for: README.md

+31
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,37 @@ module.exports = {
593593
};
594594
```
595595

596+
### `implementation`
597+
598+
Type: `Function`
599+
600+
The special `implementation` option determines which implementation of PostCSS to use. Overrides the locally installed `peerDependency` version of `postcss`.
601+
602+
**This option is only really useful for downstream tooling authors to ease the PostCSS 7-to-8 transition.**
603+
604+
**webpack.config.js**
605+
606+
```js
607+
module.exports = {
608+
module: {
609+
rules: [
610+
{
611+
test: /\.css$/i,
612+
use: [
613+
{ loader: "style-loader" },
614+
{ loader: "css-loader" },
615+
{
616+
loader: "postcss-loader",
617+
options: { implementation: require("postcss") },
618+
},
619+
{ loader: "sass-loader" },
620+
],
621+
},
622+
],
623+
},
624+
};
625+
```
626+
596627
## Examples
597628

598629
### SugarSS

Diff for: src/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export default async function loader(content, sourceMap, meta) {
4646
? true
4747
: options.postcssOptions.config;
4848

49+
const postcssFactory = options.implementation || postcss;
50+
4951
let loadedConfig;
5052

5153
if (configOption) {
@@ -105,7 +107,10 @@ export default async function loader(content, sourceMap, meta) {
105107
let result;
106108

107109
try {
108-
result = await postcss(plugins).process(root || content, processOptions);
110+
result = await postcssFactory(plugins).process(
111+
root || content,
112+
processOptions
113+
);
109114
} catch (error) {
110115
if (error.file) {
111116
this.addDependency(error.file);

Diff for: src/options.json

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
"sourceMap": {
3636
"description": "Enables/Disables generation of source maps (https://github.com/postcss/postcss-loader#sourcemap)",
3737
"type": "boolean"
38+
},
39+
"implementation": {
40+
"description": "The implementation of postcss to use, instead of the locally installed version (https://github.com/postcss/postcss-loader#implementation)",
41+
"instanceof": "Function"
3842
}
3943
},
4044
"additionalProperties": false

Diff for: test/__snapshots__/implementation.test.js.snap

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`"implementation" option should work with a custom instance of PostCSS: css 1`] = `
4+
"a {
5+
color: black;
6+
}
7+
8+
a {
9+
color: red;
10+
}
11+
12+
a {
13+
color: green;
14+
}
15+
16+
a {
17+
color: blue;
18+
}
19+
20+
.class {
21+
-x-border-color: blue blue *;
22+
-x-color: * #fafafa;
23+
}
24+
25+
.class-foo {
26+
-z-border-color: blue blue *;
27+
-z-color: * #fafafa;
28+
}
29+
30+
.phone {
31+
&_title {
32+
width: 500px;
33+
34+
@media (max-width: 500px) {
35+
width: auto;
36+
}
37+
38+
body.is_dark & {
39+
color: white;
40+
}
41+
}
42+
43+
img {
44+
display: block;
45+
}
46+
}
47+
"
48+
`;
49+
50+
exports[`"implementation" option should work with a custom instance of PostCSS: errors 1`] = `Array []`;
51+
52+
exports[`"implementation" option should work with a custom instance of PostCSS: warnings 1`] = `Array []`;

Diff for: test/__snapshots__/validate-options.test.js.snap

+30
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,36 @@ exports[`validate options should throw an error on the "execute" option with "te
3636
-> Enables/Disables PostCSS parser support in 'CSS-in-JS' (https://github.com/postcss/postcss-loader#execute)"
3737
`;
3838

39+
exports[`validate options should throw an error on the "implementation" option with "/test/" value 1`] = `
40+
"Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
41+
- options.implementation should be an instance of function.
42+
-> The implementation of postcss to use, instead of the locally installed version (https://github.com/postcss/postcss-loader#implementation)"
43+
`;
44+
45+
exports[`validate options should throw an error on the "implementation" option with "[]" value 1`] = `
46+
"Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
47+
- options.implementation should be an instance of function.
48+
-> The implementation of postcss to use, instead of the locally installed version (https://github.com/postcss/postcss-loader#implementation)"
49+
`;
50+
51+
exports[`validate options should throw an error on the "implementation" option with "{}" value 1`] = `
52+
"Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
53+
- options.implementation should be an instance of function.
54+
-> The implementation of postcss to use, instead of the locally installed version (https://github.com/postcss/postcss-loader#implementation)"
55+
`;
56+
57+
exports[`validate options should throw an error on the "implementation" option with "1" value 1`] = `
58+
"Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
59+
- options.implementation should be an instance of function.
60+
-> The implementation of postcss to use, instead of the locally installed version (https://github.com/postcss/postcss-loader#implementation)"
61+
`;
62+
63+
exports[`validate options should throw an error on the "implementation" option with "something" value 1`] = `
64+
"Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
65+
- options.implementation should be an instance of function.
66+
-> The implementation of postcss to use, instead of the locally installed version (https://github.com/postcss/postcss-loader#implementation)"
67+
`;
68+
3969
exports[`validate options should throw an error on the "postcssOptions" option with "{"config":[]}" value 1`] = `
4070
"Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
4171
- options.postcssOptions should be one of these:

Diff for: test/implementation.test.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import postcss from "postcss";
2+
3+
import {
4+
compile,
5+
getCompiler,
6+
getErrors,
7+
getCodeFromBundle,
8+
getWarnings,
9+
} from "./helpers";
10+
11+
describe('"implementation" option', () => {
12+
it("should work with a custom instance of PostCSS", async () => {
13+
const spy = jest.fn(postcss);
14+
const compiler = getCompiler("./css/index.js", {
15+
// Wrap the spy so it is an instanceof Function
16+
implementation: (...args) => spy(...args),
17+
});
18+
const stats = await compile(compiler);
19+
const codeFromBundle = getCodeFromBundle("style.css", stats);
20+
21+
expect(spy).toHaveBeenCalledTimes(1);
22+
expect(codeFromBundle.css).toMatchSnapshot("css");
23+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
24+
expect(getErrors(stats)).toMatchSnapshot("errors");
25+
});
26+
});

Diff for: test/validate-options.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ describe("validate options", () => {
5050
success: [true, false],
5151
failure: [1, /test/, [], {}, "something"],
5252
},
53+
implementation: {
54+
success: [require("postcss")],
55+
failure: [1, /test/, [], {}, "something"],
56+
},
5357
};
5458

5559
function stringifyValue(value) {

0 commit comments

Comments
 (0)