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