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