Skip to content

Commit abb832c

Browse files
ackwellSkReD
andauthoredMar 2, 2021
Allow preprocessing of value declarations (#30)
* Added support for css-loader ~ syntax of module imports * Add config, remove plugins after current. * Update readme * Revert breaking url resolution change * Add importsAsModuleRequests option Co-authored-by: Shipov Mikhail <mshipov@yandex.ru>
1 parent 198b0d4 commit abb832c

File tree

4 files changed

+64
-5
lines changed

4 files changed

+64
-5
lines changed
 

‎README.md

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
[postcss-calc]: https://github.com/postcss/postcss-calc
1010
[postcss-cssnext]: https://github.com/MoOx/postcss-cssnext
1111
[postcss-color-function]: https://github.com/postcss/postcss-color-function
12+
[postcss-modules-tilda]: https://github.com/princed/postcss-modules-tilda
1213
[postcss-modules-values]: https://github.com/css-modules/postcss-modules-values
1314
[modules-values-extract]: https://github.com/alexhisen/modules-values-extract
1415
[enhanced-resolve]: https://github.com/webpack/enhanced-resolve/#contributing
@@ -109,6 +110,15 @@ body { background: myBrandColor }
109110
body { background: blue }
110111
```
111112

113+
#### preprocessValues `boolean`
114+
115+
When enabled, permit plugins defined earlier in the PostCSS pipeline to modify `@value` declarations before they are recorded by this plugin.
116+
117+
#### importsAsModuleRequests `boolean`
118+
119+
When enabled, value imports will be resolved as module requests, in line with `css-loader`'s resolution logic [as of 2.0.0](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md#200-2018-12-07).
120+
If your code is written with pre-2.0 import syntax, and utilises [postcss-modules-tilda] for compatibility, this option is not required.
121+
112122
### calc() and @value
113123

114124
To enable calculations *inside* **@value**, enable media queries support in [postcss-calc]:

‎index.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const path = require('path');
33
const promisify = require('es6-promisify');
44
const { CachedInputFileSystem, NodeJsInputFileSystem, ResolverFactory } = require('enhanced-resolve');
55
const valuesParser = require('postcss-values-parser');
6+
const { urlToRequest } = require('loader-utils');
67

78
const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
89
const matchValueDefinition = /(?:\s+|^)([\w-]+)(:?\s+)(.+?)(\s*)$/g;
@@ -136,6 +137,8 @@ const factory = ({
136137
fs = nodeFs,
137138
noEmitExports = false,
138139
resolve: resolveOptions = {},
140+
preprocessValues = false,
141+
importsAsModuleRequests = false,
139142
} = {}) => async (root, rootResult) => {
140143
const resolver = ResolverFactory.createResolver(Object.assign(
141144
{ fileSystem: fs },
@@ -144,10 +147,23 @@ const factory = ({
144147
const resolve = promisify(resolver.resolve, resolver);
145148
const readFile = promisify(fs.readFile, fs);
146149

150+
let preprocessPlugins = [];
151+
if (preprocessValues) {
152+
const rootPlugins = rootResult.processor.plugins;
153+
const oursPluginIndex = rootPlugins
154+
.findIndex(plugin => plugin.postcssPlugin === PLUGIN);
155+
preprocessPlugins = rootPlugins.slice(0, oursPluginIndex);
156+
}
157+
147158
async function walkFile(from, dir, requiredDefinitions) {
148-
const resolvedFrom = await resolve(concordContext, dir, from);
159+
const request = importsAsModuleRequests ? urlToRequest(from) : from;
160+
const resolvedFrom = await resolve(concordContext, dir, request);
149161
const content = await readFile(resolvedFrom);
150-
const result = await postcss([walkerPlugin(walk, requiredDefinitions, walkFile)])
162+
const plugins = [
163+
...preprocessPlugins,
164+
walkerPlugin(walk, requiredDefinitions, walkFile),
165+
];
166+
const result = await postcss(plugins)
151167
.process(content, { from: resolvedFrom });
152168

153169
return result.messages[0].value;

‎package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"dependencies": {
2222
"enhanced-resolve": "^3.1.0",
2323
"es6-promisify": "^5.0.0",
24-
"postcss": "^6.0.1",
24+
"loader-utils": "^2.0.0",
25+
"postcss": "^7.0.0",
2526
"postcss-values-parser": "^1.3.1"
2627
},
2728
"devDependencies": {

‎test.js

+34-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,26 @@ const parserOpts = {
1111
to: resolve(__dirname, 'fixtures/to.css'),
1212
};
1313

14-
function run(t, input, output, opts = {}) {
15-
return postcss([plugin(opts)]).process(input, parserOpts).then((result) => {
14+
function run(t, input, output, opts = {}, extraPlugins = []) {
15+
return postcss([
16+
...extraPlugins,
17+
plugin(opts),
18+
]).process(input, parserOpts).then((result) => {
1619
t.is(result.css, output);
1720
t.is(result.warnings().length, 0);
1821
});
1922
}
2023

24+
// Simple plugin that replaces "black" with "purple" within @value declarations,
25+
// used to test preprocess value transformation
26+
const blackToPurplePlugin = postcss.plugin('testBlackToPurple', () => (root) => {
27+
root.walkAtRules('value', (atRule) => {
28+
atRule.replaceWith(atRule.clone({
29+
params: atRule.params.replace('black', 'purple'),
30+
}));
31+
});
32+
});
33+
2134
test('should pass through an empty string', async (t) => {
2235
await run(t, '', '');
2336
});
@@ -373,6 +386,16 @@ test('should replace an import from modules', async (t) => {
373386
);
374387
});
375388

389+
test('should apply extra plugins to inner processing', async (t) => {
390+
await run(
391+
t,
392+
'@value module from "module/module.css";\n.a { color: module; }',
393+
'@value module from "module/module.css";\n.a { color: purple; }',
394+
{ preprocessValues: true },
395+
[blackToPurplePlugin()],
396+
);
397+
});
398+
376399
test('should replace an import from main file of module', async (t) => {
377400
await run(
378401
t,
@@ -389,6 +412,15 @@ test('should replace an import from scoped modules', async (t) => {
389412
);
390413
});
391414

415+
test('should resolve imports as module requests', async (t) => {
416+
await run(
417+
t,
418+
'@value scoped-module from "~@scope/module/module.css";\n@value base from "level1.css";\n.a { color: scoped-module; width: base; }',
419+
'@value scoped-module from "~@scope/module/module.css";\n@value base from "level1.css";\n.a { color: purple; width: 10px; }',
420+
{ importsAsModuleRequests: true },
421+
);
422+
});
423+
392424
test('variables are also present in messages', async (t) => {
393425
const input = '@value myColor: blue; @value myColor2: myColor';
394426
const processor = postcss([plugin]);

0 commit comments

Comments
 (0)
Please sign in to comment.