-
Notifications
You must be signed in to change notification settings - Fork 356
/
Copy pathpostcss.js
99 lines (81 loc) · 2.96 KB
/
postcss.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
'use strict';
const fs = require('fs');
const esprima = require('esprima');
const walk = require('esprima-walk');
const escodegen = require('escodegen');
module.exports = {
/**
* Add postcss support to the given webpack base configuration object
* @param {String} path The config file name
*/
write: function(path) {
const data = fs.readFileSync(path, 'utf8');
const ast = esprima.parse(data);
// List of css dialects we want to add postCSS for
// On regular css, we can add the loader to the end
// of the chain. If we have a preprocessor, we will add
// it before the initial loader
const cssDialects = [
'\\.cssmodule\\.css$',
'^.((?!cssmodule).)*\\.css$'
];
const preprocessorDialects = [
'\\.cssmodule\\.(sass|scss)$',
'^.((?!cssmodule).)*\\.(sass|scss)$',
'\\.cssmodule\\.less$',
'^.((?!cssmodule).)*\\.less$',
'\\.cssmodule\\.styl$',
'^.((?!cssmodule).)*\\.styl$'
];
// Prepare postCSS statement for inclusion
const postcssFunction = 'var postcss = { postcss: function() { return []; } }';
const postcssAst = esprima.parse(postcssFunction);
const postcss = postcssAst.body[0].declarations[0].init.properties[0];
// The postcss loader item to add
const postcssLoaderObject = 'var postcss = [{ loader: \'postcss-loader\'}]';
const postcssLoaderAst = esprima.parse(postcssLoaderObject);
const postcssLoader = postcssLoaderAst.body[0].declarations[0].init.elements[0];
// Add postcss to the loaders array
walk.walkAddParent(ast, (node) => {
// Add the postcss key to the global configuration
if(
node.type === 'MethodDefinition' &&
node.key.name === 'defaultSettings'
) {
const returnStatement = node.value.body.body[1];
returnStatement.argument.properties.push(postcss);
}
// Parse all property nodes that use a regex.
// This should only be available under module.(pre)loaders
if(
node.type === 'Property' &&
node.key.type === 'Identifier' &&
node.key.name === 'test' &&
typeof node.value.regex !== 'undefined'
) {
// Regular css usage
if(cssDialects.indexOf(node.value.regex.pattern) !== -1) {
const loaderData = node.parent.properties[1];
loaderData.value.elements.push(postcssLoader);
}
if(preprocessorDialects.indexOf(node.value.regex.pattern) !== -1) {
const loaderData = node.parent.properties[1];
const lastElm = loaderData.value.elements.pop();
loaderData.value.elements.push(postcssLoader);
loaderData.value.elements.push(lastElm);
}
}
});
// Prepare the final code and write it back
const finalCode = escodegen.generate(ast, {
format: {
indent: {
adjustMultilineComment: true,
style: ' '
}
},
comment: true
});
fs.writeFileSync(path, finalCode, 'utf8');
}
}