@parcel/transformer-postcss 2.0.0-nightly.92 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/PostCSSTransformer.js +180 -101
- package/lib/constants.js +8 -0
- package/lib/loadConfig.js +159 -0
- package/lib/loadPlugins.js +6 -4
- package/package.json +17 -8
- package/src/PostCSSTransformer.js +106 -122
- package/src/constants.js +3 -0
- package/src/loadConfig.js +160 -0
- package/src/loadPlugins.js +20 -3
|
@@ -5,139 +5,185 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
function _hash() {
|
|
9
|
+
const data = require("@parcel/hash");
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
_hash = function () {
|
|
12
|
+
return data;
|
|
13
|
+
};
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
function _utils() {
|
|
19
|
+
const data = require("@parcel/utils");
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
_utils = function () {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
function _plugin() {
|
|
29
|
+
const data = require("@parcel/plugin");
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
_plugin = function () {
|
|
32
|
+
return data;
|
|
33
|
+
};
|
|
23
34
|
|
|
24
|
-
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
25
37
|
|
|
26
|
-
function
|
|
38
|
+
function _fileSystemLoader() {
|
|
39
|
+
const data = _interopRequireDefault(require("css-modules-loader-core/lib/file-system-loader"));
|
|
27
40
|
|
|
28
|
-
|
|
41
|
+
_fileSystemLoader = function () {
|
|
42
|
+
return data;
|
|
43
|
+
};
|
|
29
44
|
|
|
30
|
-
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
31
47
|
|
|
32
|
-
function
|
|
48
|
+
function _nullthrows() {
|
|
49
|
+
const data = _interopRequireDefault(require("nullthrows"));
|
|
33
50
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
_nullthrows = function () {
|
|
52
|
+
return data;
|
|
53
|
+
};
|
|
37
54
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
asset,
|
|
41
|
-
resolve,
|
|
42
|
-
options
|
|
43
|
-
}) {
|
|
44
|
-
let configFile = await asset.getConfig(['.postcssrc', '.postcssrc.json', '.postcssrc.js', 'postcss.config.js'], {
|
|
45
|
-
packageKey: 'postcss'
|
|
46
|
-
}); // Use a basic, modules-only PostCSS config if the file opts in by a name
|
|
47
|
-
// like foo.module.css
|
|
48
|
-
|
|
49
|
-
if (configFile == null && asset.filePath.match(MODULE_BY_NAME_RE)) {
|
|
50
|
-
configFile = {
|
|
51
|
-
plugins: {
|
|
52
|
-
'postcss-modules': {}
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
}
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
58
|
+
function _path() {
|
|
59
|
+
const data = _interopRequireDefault(require("path"));
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
_path = function () {
|
|
62
|
+
return data;
|
|
63
|
+
};
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
65
|
+
return data;
|
|
66
|
+
}
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
function _semver() {
|
|
69
|
+
const data = _interopRequireDefault(require("semver"));
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
_semver = function () {
|
|
72
|
+
return data;
|
|
73
|
+
};
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
return data;
|
|
76
|
+
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
function _postcssValueParser() {
|
|
79
|
+
const data = _interopRequireDefault(require("postcss-value-parser"));
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
getJSON: (filename, json) => asset.meta.cssModules = json,
|
|
84
|
-
Loader: createLoader(asset, resolve),
|
|
85
|
-
generateScopedName: (name, filename, css) => `_${name}_${(0, _utils.md5FromString)(filename + css).substr(0, 5)}`
|
|
86
|
-
}, originalModulesConfig)));
|
|
87
|
-
}
|
|
81
|
+
_postcssValueParser = function () {
|
|
82
|
+
return data;
|
|
83
|
+
};
|
|
88
84
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
return data;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function _postcssModules() {
|
|
89
|
+
const data = _interopRequireDefault(require("postcss-modules"));
|
|
90
|
+
|
|
91
|
+
_postcssModules = function () {
|
|
92
|
+
return data;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var _loadConfig = require("./loadConfig");
|
|
99
|
+
|
|
100
|
+
var _constants = require("./constants");
|
|
101
|
+
|
|
102
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
103
|
+
|
|
104
|
+
const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/;
|
|
105
|
+
const FROM_IMPORT_RE = /.+from\s*(?:"|')(.*)(?:"|')\s*;?/;
|
|
106
|
+
|
|
107
|
+
var _default = new (_plugin().Transformer)({
|
|
108
|
+
loadConfig({
|
|
109
|
+
config,
|
|
110
|
+
options,
|
|
111
|
+
logger
|
|
112
|
+
}) {
|
|
113
|
+
return (0, _loadConfig.load)({
|
|
114
|
+
config,
|
|
115
|
+
options,
|
|
116
|
+
logger
|
|
117
|
+
});
|
|
94
118
|
},
|
|
95
119
|
|
|
96
120
|
canReuseAST({
|
|
97
121
|
ast
|
|
98
122
|
}) {
|
|
99
|
-
return ast.type === 'postcss' && _semver.default.satisfies(ast.version,
|
|
123
|
+
return ast.type === 'postcss' && _semver().default.satisfies(ast.version, _constants.POSTCSS_RANGE);
|
|
100
124
|
},
|
|
101
125
|
|
|
102
126
|
async parse({
|
|
103
127
|
asset,
|
|
104
|
-
config
|
|
128
|
+
config,
|
|
129
|
+
options
|
|
105
130
|
}) {
|
|
106
131
|
if (!config) {
|
|
107
132
|
return;
|
|
108
133
|
}
|
|
109
134
|
|
|
135
|
+
const postcss = await loadPostcss(options, asset.filePath);
|
|
110
136
|
return {
|
|
111
137
|
type: 'postcss',
|
|
112
|
-
version: '
|
|
113
|
-
program:
|
|
138
|
+
version: '8.2.1',
|
|
139
|
+
program: postcss.parse(await asset.getCode(), {
|
|
114
140
|
from: asset.filePath
|
|
115
|
-
})
|
|
141
|
+
}).toJSON()
|
|
116
142
|
};
|
|
117
143
|
},
|
|
118
144
|
|
|
119
145
|
async transform({
|
|
120
146
|
asset,
|
|
121
|
-
config
|
|
147
|
+
config,
|
|
148
|
+
options,
|
|
149
|
+
resolve
|
|
122
150
|
}) {
|
|
151
|
+
asset.type = 'css';
|
|
152
|
+
|
|
123
153
|
if (!config) {
|
|
124
154
|
return [asset];
|
|
125
155
|
}
|
|
126
156
|
|
|
127
|
-
|
|
157
|
+
const postcss = await loadPostcss(options, asset.filePath);
|
|
158
|
+
let plugins = [...config.hydrated.plugins];
|
|
159
|
+
let cssModules = null;
|
|
128
160
|
|
|
129
|
-
if (
|
|
130
|
-
|
|
161
|
+
if (config.hydrated.modules) {
|
|
162
|
+
plugins.push((0, _postcssModules().default)({
|
|
163
|
+
getJSON: (filename, json) => cssModules = json,
|
|
164
|
+
Loader: createLoader(asset, resolve),
|
|
165
|
+
generateScopedName: (name, filename) => `_${name}_${(0, _hash().hashString)(_path().default.relative(options.projectRoot, filename)).substr(0, 6)}`,
|
|
166
|
+
...config.hydrated.modules
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let ast = (0, _nullthrows().default)(await asset.getAST());
|
|
171
|
+
let program = postcss.fromJSON(ast.program);
|
|
172
|
+
let code = asset.isASTDirty() ? null : await asset.getCode();
|
|
173
|
+
|
|
174
|
+
if (code == null || COMPOSES_RE.test(code)) {
|
|
175
|
+
program.walkDecls(decl => {
|
|
131
176
|
let [, importPath] = FROM_IMPORT_RE.exec(decl.value) || [];
|
|
132
177
|
|
|
133
178
|
if (decl.prop === 'composes' && importPath != null) {
|
|
134
|
-
let parsed = (0, _postcssValueParser.default)(decl.value);
|
|
179
|
+
let parsed = (0, _postcssValueParser().default)(decl.value);
|
|
135
180
|
parsed.walk(node => {
|
|
136
181
|
if (node.type === 'string') {
|
|
137
182
|
asset.addDependency({
|
|
138
|
-
|
|
183
|
+
specifier: importPath,
|
|
184
|
+
specifierType: 'url',
|
|
139
185
|
loc: {
|
|
140
|
-
filePath:
|
|
186
|
+
filePath: asset.filePath,
|
|
141
187
|
start: decl.source.start,
|
|
142
188
|
end: {
|
|
143
189
|
line: decl.source.start.line,
|
|
@@ -149,61 +195,85 @@ var _default = new _plugin.Transformer({
|
|
|
149
195
|
});
|
|
150
196
|
}
|
|
151
197
|
});
|
|
152
|
-
}
|
|
198
|
+
} // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
|
|
199
|
+
|
|
153
200
|
|
|
154
201
|
let {
|
|
155
202
|
messages,
|
|
156
203
|
root
|
|
157
|
-
} = await (
|
|
158
|
-
|
|
159
|
-
|
|
204
|
+
} = await postcss(plugins).process(program, config.hydrated);
|
|
205
|
+
asset.setAST({
|
|
206
|
+
type: 'postcss',
|
|
207
|
+
version: '8.2.1',
|
|
208
|
+
program: root.toJSON()
|
|
209
|
+
});
|
|
160
210
|
|
|
161
211
|
for (let msg of messages) {
|
|
162
212
|
if (msg.type === 'dependency') {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
213
|
+
asset.invalidateOnFileChange(msg.file);
|
|
214
|
+
} else if (msg.type === 'dir-dependency') {
|
|
215
|
+
var _msg$glob;
|
|
216
|
+
|
|
217
|
+
let pattern = `${msg.dir}/${(_msg$glob = msg.glob) !== null && _msg$glob !== void 0 ? _msg$glob : '**/*'}`;
|
|
218
|
+
let files = await (0, _utils().glob)(pattern, asset.fs, {
|
|
219
|
+
onlyFiles: true
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
for (let file of files) {
|
|
223
|
+
asset.invalidateOnFileChange(_path().default.normalize(file));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
asset.invalidateOnFileCreate({
|
|
227
|
+
glob: pattern
|
|
167
228
|
});
|
|
168
229
|
}
|
|
169
230
|
}
|
|
170
231
|
|
|
171
232
|
let assets = [asset];
|
|
172
233
|
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
let
|
|
234
|
+
if (cssModules) {
|
|
235
|
+
// $FlowFixMe
|
|
236
|
+
let cssModulesList = Object.entries(cssModules);
|
|
237
|
+
let deps = asset.getDependencies().filter(dep => dep.priority === 'sync');
|
|
238
|
+
let code;
|
|
176
239
|
|
|
177
240
|
if (deps.length > 0) {
|
|
178
241
|
code = `
|
|
179
|
-
module.exports = Object.assign({}, ${deps.map(dep => `require(${JSON.stringify(dep.
|
|
242
|
+
module.exports = Object.assign({}, ${deps.map(dep => `require(${JSON.stringify(dep.specifier)})`).join(', ')}, ${JSON.stringify(cssModules, null, 2)});
|
|
180
243
|
`;
|
|
181
244
|
} else {
|
|
182
|
-
code =
|
|
245
|
+
code = cssModulesList.map( // This syntax enables shaking the invidual statements, so that unused classes don't even exist in JS.
|
|
246
|
+
([className, classNameHashed]) => `module.exports[${JSON.stringify(className)}] = ${JSON.stringify(classNameHashed)};`).join('\n');
|
|
183
247
|
}
|
|
184
248
|
|
|
249
|
+
asset.symbols.ensure();
|
|
250
|
+
|
|
251
|
+
for (let [k, v] of cssModulesList) {
|
|
252
|
+
asset.symbols.set(k, v);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
asset.symbols.set('default', 'default');
|
|
185
256
|
assets.push({
|
|
186
257
|
type: 'js',
|
|
187
|
-
|
|
188
|
-
code
|
|
258
|
+
content: code
|
|
189
259
|
});
|
|
190
260
|
}
|
|
191
261
|
|
|
192
262
|
return assets;
|
|
193
263
|
},
|
|
194
264
|
|
|
195
|
-
generate({
|
|
196
|
-
asset
|
|
265
|
+
async generate({
|
|
266
|
+
asset,
|
|
267
|
+
ast,
|
|
268
|
+
options
|
|
197
269
|
}) {
|
|
198
|
-
|
|
270
|
+
const postcss = await loadPostcss(options, asset.filePath);
|
|
199
271
|
let code = '';
|
|
200
|
-
|
|
201
|
-
_postcss.default.stringify(ast.program, c => {
|
|
272
|
+
postcss.stringify(postcss.fromJSON(ast.program), c => {
|
|
202
273
|
code += c;
|
|
203
274
|
});
|
|
204
|
-
|
|
205
275
|
return {
|
|
206
|
-
code
|
|
276
|
+
content: code
|
|
207
277
|
};
|
|
208
278
|
}
|
|
209
279
|
|
|
@@ -212,14 +282,14 @@ var _default = new _plugin.Transformer({
|
|
|
212
282
|
exports.default = _default;
|
|
213
283
|
|
|
214
284
|
function createLoader(asset, resolve) {
|
|
215
|
-
return class extends _fileSystemLoader.default {
|
|
285
|
+
return class extends _fileSystemLoader().default {
|
|
216
286
|
async fetch(composesPath, relativeTo) {
|
|
217
287
|
let importPath = composesPath.replace(/^["']|["']$/g, '');
|
|
218
288
|
let resolved = await resolve(relativeTo, importPath);
|
|
219
289
|
|
|
220
|
-
let rootRelativePath = _path.default.resolve(_path.default.dirname(relativeTo), resolved);
|
|
290
|
+
let rootRelativePath = _path().default.resolve(_path().default.dirname(relativeTo), resolved);
|
|
221
291
|
|
|
222
|
-
let root = _path.default.resolve('/'); // fixes an issue on windows which is part of the css-modules-loader-core
|
|
292
|
+
let root = _path().default.resolve('/'); // fixes an issue on windows which is part of the css-modules-loader-core
|
|
223
293
|
// see https://github.com/css-modules/css-modules-loader-core/issues/230
|
|
224
294
|
|
|
225
295
|
|
|
@@ -230,7 +300,8 @@ function createLoader(asset, resolve) {
|
|
|
230
300
|
let source = await asset.fs.readFile(resolved, 'utf-8');
|
|
231
301
|
let {
|
|
232
302
|
exportTokens
|
|
233
|
-
} = await this.core.load(source, rootRelativePath, undefined,
|
|
303
|
+
} = await this.core.load(source, rootRelativePath, undefined, // $FlowFixMe[method-unbinding]
|
|
304
|
+
this.fetch.bind(this));
|
|
234
305
|
return exportTokens;
|
|
235
306
|
}
|
|
236
307
|
|
|
@@ -239,4 +310,12 @@ function createLoader(asset, resolve) {
|
|
|
239
310
|
}
|
|
240
311
|
|
|
241
312
|
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function loadPostcss(options, from) {
|
|
316
|
+
return options.packageManager.require('postcss', from, {
|
|
317
|
+
range: _constants.POSTCSS_RANGE,
|
|
318
|
+
saveDev: true,
|
|
319
|
+
shouldAutoInstall: options.shouldAutoInstall
|
|
320
|
+
});
|
|
242
321
|
}
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.load = load;
|
|
7
|
+
|
|
8
|
+
function _path() {
|
|
9
|
+
const data = _interopRequireDefault(require("path"));
|
|
10
|
+
|
|
11
|
+
_path = function () {
|
|
12
|
+
return data;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return data;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function _utils() {
|
|
19
|
+
const data = require("@parcel/utils");
|
|
20
|
+
|
|
21
|
+
_utils = function () {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _nullthrows() {
|
|
29
|
+
const data = _interopRequireDefault(require("nullthrows"));
|
|
30
|
+
|
|
31
|
+
_nullthrows = function () {
|
|
32
|
+
return data;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _clone() {
|
|
39
|
+
const data = _interopRequireDefault(require("clone"));
|
|
40
|
+
|
|
41
|
+
_clone = function () {
|
|
42
|
+
return data;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var _constants = require("./constants");
|
|
49
|
+
|
|
50
|
+
var _loadPlugins = _interopRequireDefault(require("./loadPlugins"));
|
|
51
|
+
|
|
52
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
53
|
+
|
|
54
|
+
const MODULE_BY_NAME_RE = /\.module\./;
|
|
55
|
+
|
|
56
|
+
async function configHydrator(configFile, config, resolveFrom, options) {
|
|
57
|
+
// Use a basic, modules-only PostCSS config if the file opts in by a name
|
|
58
|
+
// like foo.module.css
|
|
59
|
+
if (configFile == null && config.searchPath.match(MODULE_BY_NAME_RE)) {
|
|
60
|
+
configFile = {
|
|
61
|
+
plugins: {
|
|
62
|
+
'postcss-modules': {}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
resolveFrom = __filename;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (configFile == null) {
|
|
69
|
+
return;
|
|
70
|
+
} // Load the custom config...
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
let modulesConfig;
|
|
74
|
+
let configFilePlugins = (0, _clone().default)(configFile.plugins);
|
|
75
|
+
|
|
76
|
+
if (configFilePlugins != null && typeof configFilePlugins === 'object' && configFilePlugins['postcss-modules'] != null) {
|
|
77
|
+
modulesConfig = configFilePlugins['postcss-modules'];
|
|
78
|
+
delete configFilePlugins['postcss-modules'];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!modulesConfig && configFile.modules) {
|
|
82
|
+
modulesConfig = {};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let plugins = await (0, _loadPlugins.default)(configFilePlugins, (0, _nullthrows().default)(resolveFrom), options); // contents is either:
|
|
86
|
+
// from JSON: { plugins: { 'postcss-foo': { ...opts } } }
|
|
87
|
+
// from JS (v8): { plugins: [ { postcssPlugin: 'postcss-foo', ...visitor callback functions } ]
|
|
88
|
+
// from JS (v7): { plugins: [ [Function: ...] ]
|
|
89
|
+
|
|
90
|
+
let pluginArray = Array.isArray(configFilePlugins) ? configFilePlugins : Object.keys(configFilePlugins);
|
|
91
|
+
|
|
92
|
+
for (let p of pluginArray) {
|
|
93
|
+
if (typeof p === 'string') {
|
|
94
|
+
config.addDevDependency({
|
|
95
|
+
specifier: p,
|
|
96
|
+
resolveFrom: (0, _nullthrows().default)(resolveFrom)
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
raw: configFile,
|
|
103
|
+
hydrated: {
|
|
104
|
+
plugins,
|
|
105
|
+
from: config.searchPath,
|
|
106
|
+
to: config.searchPath,
|
|
107
|
+
modules: modulesConfig
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function load({
|
|
113
|
+
config,
|
|
114
|
+
options,
|
|
115
|
+
logger
|
|
116
|
+
}) {
|
|
117
|
+
if (!config.isSource) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let configFile = await config.getConfig(['.postcssrc', '.postcssrc.json', '.postcssrc.js', 'postcss.config.js'], {
|
|
122
|
+
packageKey: 'postcss'
|
|
123
|
+
});
|
|
124
|
+
let contents = null;
|
|
125
|
+
|
|
126
|
+
if (configFile) {
|
|
127
|
+
config.addDevDependency({
|
|
128
|
+
specifier: 'postcss',
|
|
129
|
+
resolveFrom: config.searchPath,
|
|
130
|
+
range: _constants.POSTCSS_RANGE
|
|
131
|
+
});
|
|
132
|
+
contents = configFile.contents;
|
|
133
|
+
let isDynamic = configFile && _path().default.extname(configFile.filePath) === '.js';
|
|
134
|
+
|
|
135
|
+
if (isDynamic) {
|
|
136
|
+
// We have to invalidate on startup in case the config is non-deterministic,
|
|
137
|
+
// e.g. using unknown environment variables, reading from the filesystem, etc.
|
|
138
|
+
logger.warn({
|
|
139
|
+
message: 'WARNING: Using a JavaScript PostCSS config file means losing out on caching features of Parcel. Use a .postcssrc(.json) file whenever possible.'
|
|
140
|
+
});
|
|
141
|
+
config.invalidateOnStartup(); // Also add the config as a dev dependency so we attempt to reload in watch mode.
|
|
142
|
+
|
|
143
|
+
config.addDevDependency({
|
|
144
|
+
specifier: (0, _utils().relativePath)(_path().default.dirname(config.searchPath), configFile.filePath),
|
|
145
|
+
resolveFrom: config.searchPath
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (typeof contents !== 'object') {
|
|
150
|
+
throw new Error('PostCSS config should be an object.');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (contents.plugins == null || typeof contents.plugins !== 'object' || Object.keys(contents.plugins).length === 0) {
|
|
154
|
+
throw new Error('PostCSS config must have plugins');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return configHydrator(contents, config, configFile === null || configFile === void 0 ? void 0 : configFile.filePath, options);
|
|
159
|
+
}
|
package/lib/loadPlugins.js
CHANGED
|
@@ -7,21 +7,23 @@ exports.default = loadExternalPlugins;
|
|
|
7
7
|
|
|
8
8
|
async function loadExternalPlugins(plugins, relative, options) {
|
|
9
9
|
if (Array.isArray(plugins)) {
|
|
10
|
-
return Promise.all(plugins.map(p => loadPlugin(p, relative, null, options.packageManager)).filter(Boolean));
|
|
10
|
+
return Promise.all(plugins.map(p => loadPlugin(p, relative, null, options.packageManager, options.shouldAutoInstall)).filter(Boolean));
|
|
11
11
|
} else if (typeof plugins === 'object') {
|
|
12
|
-
let mapPlugins = await Promise.all(Object.keys(plugins).map(p => loadPlugin(p, relative, plugins[p], options.packageManager)));
|
|
12
|
+
let mapPlugins = await Promise.all(Object.keys(plugins).map(p => loadPlugin(p, relative, plugins[p], options.packageManager, options.shouldAutoInstall)));
|
|
13
13
|
return mapPlugins.filter(Boolean);
|
|
14
14
|
} else {
|
|
15
15
|
return [];
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
async function loadPlugin(pluginArg, relative, options = {}, packageManager) {
|
|
19
|
+
async function loadPlugin(pluginArg, relative, options = {}, packageManager, shouldAutoInstall) {
|
|
20
20
|
if (typeof pluginArg !== 'string') {
|
|
21
21
|
return pluginArg;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
let plugin = await packageManager.require(pluginArg, relative
|
|
24
|
+
let plugin = await packageManager.require(pluginArg, relative, {
|
|
25
|
+
shouldAutoInstall
|
|
26
|
+
});
|
|
25
27
|
plugin = plugin.default || plugin;
|
|
26
28
|
|
|
27
29
|
if (options != null && typeof options === 'object' && Object.keys(options).length > 0) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/transformer-postcss",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
+
"funding": {
|
|
9
|
+
"type": "opencollective",
|
|
10
|
+
"url": "https://opencollective.com/parcel"
|
|
11
|
+
},
|
|
8
12
|
"repository": {
|
|
9
13
|
"type": "git",
|
|
10
14
|
"url": "https://github.com/parcel-bundler/parcel.git"
|
|
@@ -12,17 +16,22 @@
|
|
|
12
16
|
"main": "lib/PostCSSTransformer.js",
|
|
13
17
|
"source": "src/PostCSSTransformer.js",
|
|
14
18
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
16
|
-
"parcel": "^2.0.
|
|
19
|
+
"node": ">= 12.0.0",
|
|
20
|
+
"parcel": "^2.0.1"
|
|
17
21
|
},
|
|
18
22
|
"dependencies": {
|
|
19
|
-
"@parcel/
|
|
20
|
-
"@parcel/
|
|
23
|
+
"@parcel/hash": "^2.0.1",
|
|
24
|
+
"@parcel/plugin": "^2.0.1",
|
|
25
|
+
"@parcel/utils": "^2.0.1",
|
|
26
|
+
"clone": "^2.1.1",
|
|
21
27
|
"css-modules-loader-core": "^1.1.0",
|
|
22
28
|
"nullthrows": "^1.1.1",
|
|
23
|
-
"postcss": "^
|
|
24
|
-
"postcss-value-parser": "^
|
|
29
|
+
"postcss-modules": "^3.2.2",
|
|
30
|
+
"postcss-value-parser": "^4.1.0",
|
|
25
31
|
"semver": "^5.4.1"
|
|
26
32
|
},
|
|
27
|
-
"
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"postcss": "^8.3.0"
|
|
35
|
+
},
|
|
36
|
+
"gitHead": "28b47e6bdca7de2a06b7cc39a4a0b1df89f3fe15"
|
|
28
37
|
}
|
|
@@ -1,126 +1,82 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import type {FilePath, MutableAsset} from '@parcel/types';
|
|
3
|
+
import type {FilePath, MutableAsset, PluginOptions} from '@parcel/types';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {hashString} from '@parcel/hash';
|
|
6
|
+
import {glob} from '@parcel/utils';
|
|
6
7
|
import {Transformer} from '@parcel/plugin';
|
|
7
8
|
import FileSystemLoader from 'css-modules-loader-core/lib/file-system-loader';
|
|
8
9
|
import nullthrows from 'nullthrows';
|
|
9
10
|
import path from 'path';
|
|
10
|
-
import postcss from 'postcss';
|
|
11
11
|
import semver from 'semver';
|
|
12
12
|
import valueParser from 'postcss-value-parser';
|
|
13
|
+
import postcssModules from 'postcss-modules';
|
|
14
|
+
import typeof * as Postcss from 'postcss';
|
|
13
15
|
|
|
14
|
-
import
|
|
16
|
+
import {load} from './loadConfig';
|
|
17
|
+
import {POSTCSS_RANGE} from './constants';
|
|
15
18
|
|
|
16
19
|
const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/;
|
|
17
20
|
const FROM_IMPORT_RE = /.+from\s*(?:"|')(.*)(?:"|')\s*;?/;
|
|
18
|
-
const MODULE_BY_NAME_RE = /\.module\./;
|
|
19
|
-
|
|
20
|
-
type ParcelPostCSSConfig = {
|
|
21
|
-
plugins: Array<mixed>,
|
|
22
|
-
from: FilePath,
|
|
23
|
-
to: FilePath,
|
|
24
|
-
...
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default new Transformer({
|
|
28
|
-
async getConfig({asset, resolve, options}): Promise<?ParcelPostCSSConfig> {
|
|
29
|
-
let configFile: mixed = await asset.getConfig(
|
|
30
|
-
['.postcssrc', '.postcssrc.json', '.postcssrc.js', 'postcss.config.js'],
|
|
31
|
-
{packageKey: 'postcss'},
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// Use a basic, modules-only PostCSS config if the file opts in by a name
|
|
35
|
-
// like foo.module.css
|
|
36
|
-
if (configFile == null && asset.filePath.match(MODULE_BY_NAME_RE)) {
|
|
37
|
-
configFile = {
|
|
38
|
-
plugins: {
|
|
39
|
-
'postcss-modules': {},
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (configFile == null) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (typeof configFile !== 'object') {
|
|
49
|
-
throw new Error('PostCSS config should be an object.');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
configFile.plugins == null ||
|
|
54
|
-
typeof configFile.plugins !== 'object' ||
|
|
55
|
-
Object.keys(configFile.plugins) === 0
|
|
56
|
-
) {
|
|
57
|
-
throw new Error('PostCSS config must have plugins');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let originalModulesConfig;
|
|
61
|
-
let configFilePlugins = configFile.plugins;
|
|
62
|
-
if (
|
|
63
|
-
configFilePlugins != null &&
|
|
64
|
-
typeof configFilePlugins === 'object' &&
|
|
65
|
-
configFilePlugins['postcss-modules'] != null
|
|
66
|
-
) {
|
|
67
|
-
originalModulesConfig = configFilePlugins['postcss-modules'];
|
|
68
|
-
// $FlowFixMe
|
|
69
|
-
delete configFilePlugins['postcss-modules'];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let plugins = await loadPlugins(configFilePlugins, asset.filePath, options);
|
|
73
21
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
asset.filePath,
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
plugins.push(
|
|
81
|
-
postcssModules({
|
|
82
|
-
getJSON: (filename, json) => (asset.meta.cssModules = json),
|
|
83
|
-
Loader: createLoader(asset, resolve),
|
|
84
|
-
generateScopedName: (name, filename, css) =>
|
|
85
|
-
`_${name}_${md5FromString(filename + css).substr(0, 5)}`,
|
|
86
|
-
...originalModulesConfig,
|
|
87
|
-
}),
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
plugins,
|
|
93
|
-
from: asset.filePath,
|
|
94
|
-
to: asset.filePath,
|
|
95
|
-
};
|
|
22
|
+
export default (new Transformer({
|
|
23
|
+
loadConfig({config, options, logger}) {
|
|
24
|
+
return load({config, options, logger});
|
|
96
25
|
},
|
|
97
26
|
|
|
98
27
|
canReuseAST({ast}) {
|
|
99
|
-
return
|
|
28
|
+
return (
|
|
29
|
+
ast.type === 'postcss' && semver.satisfies(ast.version, POSTCSS_RANGE)
|
|
30
|
+
);
|
|
100
31
|
},
|
|
101
32
|
|
|
102
|
-
async parse({asset, config}) {
|
|
33
|
+
async parse({asset, config, options}) {
|
|
103
34
|
if (!config) {
|
|
104
35
|
return;
|
|
105
36
|
}
|
|
106
37
|
|
|
38
|
+
const postcss = await loadPostcss(options, asset.filePath);
|
|
39
|
+
|
|
107
40
|
return {
|
|
108
41
|
type: 'postcss',
|
|
109
|
-
version: '
|
|
110
|
-
program: postcss
|
|
111
|
-
|
|
112
|
-
|
|
42
|
+
version: '8.2.1',
|
|
43
|
+
program: postcss
|
|
44
|
+
.parse(await asset.getCode(), {
|
|
45
|
+
from: asset.filePath,
|
|
46
|
+
})
|
|
47
|
+
.toJSON(),
|
|
113
48
|
};
|
|
114
49
|
},
|
|
115
50
|
|
|
116
|
-
async transform({asset, config}) {
|
|
51
|
+
async transform({asset, config, options, resolve}) {
|
|
52
|
+
asset.type = 'css';
|
|
117
53
|
if (!config) {
|
|
118
54
|
return [asset];
|
|
119
55
|
}
|
|
120
56
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
57
|
+
const postcss: Postcss = await loadPostcss(options, asset.filePath);
|
|
58
|
+
|
|
59
|
+
let plugins = [...config.hydrated.plugins];
|
|
60
|
+
let cssModules: ?{|[string]: string|} = null;
|
|
61
|
+
if (config.hydrated.modules) {
|
|
62
|
+
plugins.push(
|
|
63
|
+
postcssModules({
|
|
64
|
+
getJSON: (filename, json) => (cssModules = json),
|
|
65
|
+
Loader: createLoader(asset, resolve),
|
|
66
|
+
generateScopedName: (name, filename) =>
|
|
67
|
+
`_${name}_${hashString(
|
|
68
|
+
path.relative(options.projectRoot, filename),
|
|
69
|
+
).substr(0, 6)}`,
|
|
70
|
+
...config.hydrated.modules,
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let ast = nullthrows(await asset.getAST());
|
|
76
|
+
let program = postcss.fromJSON(ast.program);
|
|
77
|
+
let code = asset.isASTDirty() ? null : await asset.getCode();
|
|
78
|
+
if (code == null || COMPOSES_RE.test(code)) {
|
|
79
|
+
program.walkDecls(decl => {
|
|
124
80
|
let [, importPath] = FROM_IMPORT_RE.exec(decl.value) || [];
|
|
125
81
|
if (decl.prop === 'composes' && importPath != null) {
|
|
126
82
|
let parsed = valueParser(decl.value);
|
|
@@ -128,9 +84,10 @@ export default new Transformer({
|
|
|
128
84
|
parsed.walk(node => {
|
|
129
85
|
if (node.type === 'string') {
|
|
130
86
|
asset.addDependency({
|
|
131
|
-
|
|
87
|
+
specifier: importPath,
|
|
88
|
+
specifierType: 'url',
|
|
132
89
|
loc: {
|
|
133
|
-
filePath:
|
|
90
|
+
filePath: asset.filePath,
|
|
134
91
|
start: decl.source.start,
|
|
135
92
|
end: {
|
|
136
93
|
line: decl.source.start.line,
|
|
@@ -144,64 +101,82 @@ export default new Transformer({
|
|
|
144
101
|
});
|
|
145
102
|
}
|
|
146
103
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
104
|
+
// $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
|
|
105
|
+
let {messages, root} = await postcss(plugins).process(
|
|
106
|
+
program,
|
|
107
|
+
config.hydrated,
|
|
150
108
|
);
|
|
151
|
-
|
|
152
|
-
|
|
109
|
+
asset.setAST({
|
|
110
|
+
type: 'postcss',
|
|
111
|
+
version: '8.2.1',
|
|
112
|
+
program: root.toJSON(),
|
|
113
|
+
});
|
|
153
114
|
for (let msg of messages) {
|
|
154
115
|
if (msg.type === 'dependency') {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
asset.addIncludedFile({
|
|
164
|
-
filePath: msg.file,
|
|
165
|
-
});
|
|
116
|
+
asset.invalidateOnFileChange(msg.file);
|
|
117
|
+
} else if (msg.type === 'dir-dependency') {
|
|
118
|
+
let pattern = `${msg.dir}/${msg.glob ?? '**/*'}`;
|
|
119
|
+
let files = await glob(pattern, asset.fs, {onlyFiles: true});
|
|
120
|
+
for (let file of files) {
|
|
121
|
+
asset.invalidateOnFileChange(path.normalize(file));
|
|
122
|
+
}
|
|
123
|
+
asset.invalidateOnFileCreate({glob: pattern});
|
|
166
124
|
}
|
|
167
125
|
}
|
|
168
126
|
|
|
169
127
|
let assets = [asset];
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
let
|
|
128
|
+
if (cssModules) {
|
|
129
|
+
// $FlowFixMe
|
|
130
|
+
let cssModulesList = (Object.entries(cssModules): Array<
|
|
131
|
+
[string, string],
|
|
132
|
+
>);
|
|
133
|
+
let deps = asset.getDependencies().filter(dep => dep.priority === 'sync');
|
|
134
|
+
let code: string;
|
|
173
135
|
if (deps.length > 0) {
|
|
174
136
|
code = `
|
|
175
137
|
module.exports = Object.assign({}, ${deps
|
|
176
|
-
.map(dep => `require(${JSON.stringify(dep.
|
|
177
|
-
.join(', ')}, ${
|
|
138
|
+
.map(dep => `require(${JSON.stringify(dep.specifier)})`)
|
|
139
|
+
.join(', ')}, ${JSON.stringify(cssModules, null, 2)});
|
|
178
140
|
`;
|
|
179
141
|
} else {
|
|
180
|
-
code =
|
|
142
|
+
code = cssModulesList
|
|
143
|
+
.map(
|
|
144
|
+
// This syntax enables shaking the invidual statements, so that unused classes don't even exist in JS.
|
|
145
|
+
([className, classNameHashed]) =>
|
|
146
|
+
`module.exports[${JSON.stringify(className)}] = ${JSON.stringify(
|
|
147
|
+
classNameHashed,
|
|
148
|
+
)};`,
|
|
149
|
+
)
|
|
150
|
+
.join('\n');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
asset.symbols.ensure();
|
|
154
|
+
for (let [k, v] of cssModulesList) {
|
|
155
|
+
asset.symbols.set(k, v);
|
|
181
156
|
}
|
|
157
|
+
asset.symbols.set('default', 'default');
|
|
182
158
|
|
|
183
159
|
assets.push({
|
|
184
160
|
type: 'js',
|
|
185
|
-
|
|
186
|
-
code,
|
|
161
|
+
content: code,
|
|
187
162
|
});
|
|
188
163
|
}
|
|
189
164
|
return assets;
|
|
190
165
|
},
|
|
191
166
|
|
|
192
|
-
generate({asset}) {
|
|
193
|
-
|
|
167
|
+
async generate({asset, ast, options}) {
|
|
168
|
+
const postcss: Postcss = await loadPostcss(options, asset.filePath);
|
|
194
169
|
|
|
195
170
|
let code = '';
|
|
196
|
-
postcss.stringify(ast.program, c => {
|
|
171
|
+
postcss.stringify(postcss.fromJSON(ast.program), c => {
|
|
197
172
|
code += c;
|
|
198
173
|
});
|
|
199
174
|
|
|
200
175
|
return {
|
|
201
|
-
code,
|
|
176
|
+
content: code,
|
|
202
177
|
};
|
|
203
178
|
},
|
|
204
|
-
});
|
|
179
|
+
}): Transformer);
|
|
205
180
|
|
|
206
181
|
function createLoader(
|
|
207
182
|
asset: MutableAsset,
|
|
@@ -224,6 +199,7 @@ function createLoader(
|
|
|
224
199
|
source,
|
|
225
200
|
rootRelativePath,
|
|
226
201
|
undefined,
|
|
202
|
+
// $FlowFixMe[method-unbinding]
|
|
227
203
|
this.fetch.bind(this),
|
|
228
204
|
);
|
|
229
205
|
return exportTokens;
|
|
@@ -234,3 +210,11 @@ function createLoader(
|
|
|
234
210
|
}
|
|
235
211
|
};
|
|
236
212
|
}
|
|
213
|
+
|
|
214
|
+
function loadPostcss(options: PluginOptions, from: FilePath): Promise<Postcss> {
|
|
215
|
+
return options.packageManager.require('postcss', from, {
|
|
216
|
+
range: POSTCSS_RANGE,
|
|
217
|
+
saveDev: true,
|
|
218
|
+
shouldAutoInstall: options.shouldAutoInstall,
|
|
219
|
+
});
|
|
220
|
+
}
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {
|
|
3
|
+
Config,
|
|
4
|
+
FilePath,
|
|
5
|
+
PluginOptions,
|
|
6
|
+
PluginLogger,
|
|
7
|
+
} from '@parcel/types';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import {relativePath} from '@parcel/utils';
|
|
10
|
+
import nullthrows from 'nullthrows';
|
|
11
|
+
import clone from 'clone';
|
|
12
|
+
import {POSTCSS_RANGE} from './constants';
|
|
13
|
+
|
|
14
|
+
import loadExternalPlugins from './loadPlugins';
|
|
15
|
+
|
|
16
|
+
const MODULE_BY_NAME_RE = /\.module\./;
|
|
17
|
+
|
|
18
|
+
type ConfigResult = {|
|
|
19
|
+
raw: any,
|
|
20
|
+
hydrated: {|
|
|
21
|
+
plugins: Array<any>,
|
|
22
|
+
from: FilePath,
|
|
23
|
+
to: FilePath,
|
|
24
|
+
modules: any,
|
|
25
|
+
|},
|
|
26
|
+
|};
|
|
27
|
+
|
|
28
|
+
async function configHydrator(
|
|
29
|
+
configFile: any,
|
|
30
|
+
config: Config,
|
|
31
|
+
resolveFrom: ?FilePath,
|
|
32
|
+
options: PluginOptions,
|
|
33
|
+
): Promise<?ConfigResult> {
|
|
34
|
+
// Use a basic, modules-only PostCSS config if the file opts in by a name
|
|
35
|
+
// like foo.module.css
|
|
36
|
+
if (configFile == null && config.searchPath.match(MODULE_BY_NAME_RE)) {
|
|
37
|
+
configFile = {
|
|
38
|
+
plugins: {
|
|
39
|
+
'postcss-modules': {},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
resolveFrom = __filename;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (configFile == null) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Load the custom config...
|
|
50
|
+
let modulesConfig;
|
|
51
|
+
let configFilePlugins = clone(configFile.plugins);
|
|
52
|
+
if (
|
|
53
|
+
configFilePlugins != null &&
|
|
54
|
+
typeof configFilePlugins === 'object' &&
|
|
55
|
+
configFilePlugins['postcss-modules'] != null
|
|
56
|
+
) {
|
|
57
|
+
modulesConfig = configFilePlugins['postcss-modules'];
|
|
58
|
+
delete configFilePlugins['postcss-modules'];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!modulesConfig && configFile.modules) {
|
|
62
|
+
modulesConfig = {};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let plugins = await loadExternalPlugins(
|
|
66
|
+
configFilePlugins,
|
|
67
|
+
nullthrows(resolveFrom),
|
|
68
|
+
options,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// contents is either:
|
|
72
|
+
// from JSON: { plugins: { 'postcss-foo': { ...opts } } }
|
|
73
|
+
// from JS (v8): { plugins: [ { postcssPlugin: 'postcss-foo', ...visitor callback functions } ]
|
|
74
|
+
// from JS (v7): { plugins: [ [Function: ...] ]
|
|
75
|
+
let pluginArray = Array.isArray(configFilePlugins)
|
|
76
|
+
? configFilePlugins
|
|
77
|
+
: Object.keys(configFilePlugins);
|
|
78
|
+
for (let p of pluginArray) {
|
|
79
|
+
if (typeof p === 'string') {
|
|
80
|
+
config.addDevDependency({
|
|
81
|
+
specifier: p,
|
|
82
|
+
resolveFrom: nullthrows(resolveFrom),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
raw: configFile,
|
|
89
|
+
hydrated: {
|
|
90
|
+
plugins,
|
|
91
|
+
from: config.searchPath,
|
|
92
|
+
to: config.searchPath,
|
|
93
|
+
modules: modulesConfig,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function load({
|
|
99
|
+
config,
|
|
100
|
+
options,
|
|
101
|
+
logger,
|
|
102
|
+
}: {|
|
|
103
|
+
config: Config,
|
|
104
|
+
options: PluginOptions,
|
|
105
|
+
logger: PluginLogger,
|
|
106
|
+
|}): Promise<?ConfigResult> {
|
|
107
|
+
if (!config.isSource) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let configFile: any = await config.getConfig(
|
|
112
|
+
['.postcssrc', '.postcssrc.json', '.postcssrc.js', 'postcss.config.js'],
|
|
113
|
+
{packageKey: 'postcss'},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
let contents = null;
|
|
117
|
+
if (configFile) {
|
|
118
|
+
config.addDevDependency({
|
|
119
|
+
specifier: 'postcss',
|
|
120
|
+
resolveFrom: config.searchPath,
|
|
121
|
+
range: POSTCSS_RANGE,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
contents = configFile.contents;
|
|
125
|
+
let isDynamic = configFile && path.extname(configFile.filePath) === '.js';
|
|
126
|
+
if (isDynamic) {
|
|
127
|
+
// We have to invalidate on startup in case the config is non-deterministic,
|
|
128
|
+
// e.g. using unknown environment variables, reading from the filesystem, etc.
|
|
129
|
+
logger.warn({
|
|
130
|
+
message:
|
|
131
|
+
'WARNING: Using a JavaScript PostCSS config file means losing out on caching features of Parcel. Use a .postcssrc(.json) file whenever possible.',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
config.invalidateOnStartup();
|
|
135
|
+
|
|
136
|
+
// Also add the config as a dev dependency so we attempt to reload in watch mode.
|
|
137
|
+
config.addDevDependency({
|
|
138
|
+
specifier: relativePath(
|
|
139
|
+
path.dirname(config.searchPath),
|
|
140
|
+
configFile.filePath,
|
|
141
|
+
),
|
|
142
|
+
resolveFrom: config.searchPath,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (typeof contents !== 'object') {
|
|
147
|
+
throw new Error('PostCSS config should be an object.');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (
|
|
151
|
+
contents.plugins == null ||
|
|
152
|
+
typeof contents.plugins !== 'object' ||
|
|
153
|
+
Object.keys(contents.plugins).length === 0
|
|
154
|
+
) {
|
|
155
|
+
throw new Error('PostCSS config must have plugins');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return configHydrator(contents, config, configFile?.filePath, options);
|
|
160
|
+
}
|
package/src/loadPlugins.js
CHANGED
|
@@ -11,14 +11,28 @@ export default async function loadExternalPlugins(
|
|
|
11
11
|
if (Array.isArray(plugins)) {
|
|
12
12
|
return Promise.all(
|
|
13
13
|
plugins
|
|
14
|
-
.map(p =>
|
|
14
|
+
.map(p =>
|
|
15
|
+
loadPlugin(
|
|
16
|
+
p,
|
|
17
|
+
relative,
|
|
18
|
+
null,
|
|
19
|
+
options.packageManager,
|
|
20
|
+
options.shouldAutoInstall,
|
|
21
|
+
),
|
|
22
|
+
)
|
|
15
23
|
.filter(Boolean),
|
|
16
24
|
);
|
|
17
25
|
} else if (typeof plugins === 'object') {
|
|
18
26
|
let _plugins = plugins;
|
|
19
27
|
let mapPlugins = await Promise.all(
|
|
20
28
|
Object.keys(plugins).map(p =>
|
|
21
|
-
loadPlugin(
|
|
29
|
+
loadPlugin(
|
|
30
|
+
p,
|
|
31
|
+
relative,
|
|
32
|
+
_plugins[p],
|
|
33
|
+
options.packageManager,
|
|
34
|
+
options.shouldAutoInstall,
|
|
35
|
+
),
|
|
22
36
|
),
|
|
23
37
|
);
|
|
24
38
|
return mapPlugins.filter(Boolean);
|
|
@@ -32,12 +46,15 @@ async function loadPlugin(
|
|
|
32
46
|
relative: FilePath,
|
|
33
47
|
options: mixed = {},
|
|
34
48
|
packageManager: PackageManager,
|
|
49
|
+
shouldAutoInstall: boolean,
|
|
35
50
|
): mixed {
|
|
36
51
|
if (typeof pluginArg !== 'string') {
|
|
37
52
|
return pluginArg;
|
|
38
53
|
}
|
|
39
54
|
|
|
40
|
-
let plugin = await packageManager.require(pluginArg, relative
|
|
55
|
+
let plugin = await packageManager.require(pluginArg, relative, {
|
|
56
|
+
shouldAutoInstall,
|
|
57
|
+
});
|
|
41
58
|
plugin = plugin.default || plugin;
|
|
42
59
|
|
|
43
60
|
if (
|