@parcel/transformer-css 2.0.0-nightly.97 → 2.0.0-nightly.982
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/CSSTransformer.js +343 -78
- package/package.json +18 -9
- package/src/CSSTransformer.js +267 -82
package/lib/CSSTransformer.js
CHANGED
|
@@ -5,30 +5,133 @@ 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
|
+
}
|
|
17
|
+
|
|
18
|
+
function _sourceMap() {
|
|
19
|
+
const data = _interopRequireDefault(require("@parcel/source-map"));
|
|
20
|
+
|
|
21
|
+
_sourceMap = function () {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _plugin() {
|
|
29
|
+
const data = require("@parcel/plugin");
|
|
30
|
+
|
|
31
|
+
_plugin = function () {
|
|
32
|
+
return data;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _utils() {
|
|
39
|
+
const data = require("@parcel/utils");
|
|
40
|
+
|
|
41
|
+
_utils = function () {
|
|
42
|
+
return data;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function _postcss() {
|
|
49
|
+
const data = _interopRequireDefault(require("postcss"));
|
|
50
|
+
|
|
51
|
+
_postcss = function () {
|
|
52
|
+
return data;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _nullthrows() {
|
|
59
|
+
const data = _interopRequireDefault(require("nullthrows"));
|
|
60
|
+
|
|
61
|
+
_nullthrows = function () {
|
|
62
|
+
return data;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return data;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function _postcssValueParser() {
|
|
69
|
+
const data = _interopRequireDefault(require("postcss-value-parser"));
|
|
70
|
+
|
|
71
|
+
_postcssValueParser = function () {
|
|
72
|
+
return data;
|
|
73
|
+
};
|
|
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
|
+
return data;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function _fileSystemLoader() {
|
|
89
|
+
const data = _interopRequireDefault(require("css-modules-loader-core/lib/file-system-loader"));
|
|
90
|
+
|
|
91
|
+
_fileSystemLoader = function () {
|
|
92
|
+
return data;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function _semver() {
|
|
99
|
+
const data = _interopRequireDefault(require("semver"));
|
|
100
|
+
|
|
101
|
+
_semver = function () {
|
|
102
|
+
return data;
|
|
103
|
+
};
|
|
13
104
|
|
|
14
|
-
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function _path() {
|
|
109
|
+
const data = _interopRequireDefault(require("path"));
|
|
15
110
|
|
|
16
|
-
|
|
111
|
+
_path = function () {
|
|
112
|
+
return data;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return data;
|
|
116
|
+
}
|
|
17
117
|
|
|
18
118
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
119
|
|
|
20
120
|
const URL_RE = /url\s*\("?(?![a-z]+:)/;
|
|
21
121
|
const IMPORT_RE = /@import/;
|
|
122
|
+
const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/;
|
|
123
|
+
const FROM_IMPORT_RE = /.+from\s*(?:"|')(.*)(?:"|')\s*;?/;
|
|
124
|
+
const MODULE_BY_NAME_RE = /\.module\./;
|
|
22
125
|
|
|
23
126
|
function canHaveDependencies(filePath, code) {
|
|
24
127
|
return !/\.css$/.test(filePath) || IMPORT_RE.test(code) || URL_RE.test(code);
|
|
25
128
|
}
|
|
26
129
|
|
|
27
|
-
var _default = new _plugin.Transformer({
|
|
130
|
+
var _default = new (_plugin().Transformer)({
|
|
28
131
|
canReuseAST({
|
|
29
132
|
ast
|
|
30
133
|
}) {
|
|
31
|
-
return ast.type === 'postcss' && _semver.default.satisfies(ast.version, '^
|
|
134
|
+
return ast.type === 'postcss' && _semver().default.satisfies(ast.version, '^8.2.1');
|
|
32
135
|
},
|
|
33
136
|
|
|
34
137
|
async parse({
|
|
@@ -40,137 +143,299 @@ var _default = new _plugin.Transformer({
|
|
|
40
143
|
// to be filled in later. When the CSS transformer runs, it would pick that up and try to
|
|
41
144
|
// resolve a dependency for the id which obviously doesn't exist. Also, it's faster to do
|
|
42
145
|
// it this way since the resulting CSS doesn't need to be re-parsed.
|
|
43
|
-
|
|
146
|
+
let isCSSModule = asset.meta.cssModulesCompiled !== true && MODULE_BY_NAME_RE.test(asset.filePath);
|
|
147
|
+
|
|
148
|
+
if (asset.meta.hasDependencies === false && !isCSSModule) {
|
|
44
149
|
return null;
|
|
45
150
|
}
|
|
46
151
|
|
|
47
152
|
let code = await asset.getCode();
|
|
48
153
|
|
|
49
|
-
if (!canHaveDependencies(asset.filePath, code)) {
|
|
154
|
+
if (code != null && !canHaveDependencies(asset.filePath, code) && !isCSSModule) {
|
|
50
155
|
return null;
|
|
51
156
|
}
|
|
52
157
|
|
|
53
158
|
return {
|
|
54
159
|
type: 'postcss',
|
|
55
|
-
version: '
|
|
56
|
-
|
|
57
|
-
program: _postcss.default.parse(code, {
|
|
160
|
+
version: '8.2.1',
|
|
161
|
+
program: _postcss().default.parse(code, {
|
|
58
162
|
from: asset.filePath
|
|
59
|
-
})
|
|
163
|
+
}).toJSON()
|
|
60
164
|
};
|
|
61
165
|
},
|
|
62
166
|
|
|
63
|
-
transform({
|
|
64
|
-
asset
|
|
167
|
+
async transform({
|
|
168
|
+
asset,
|
|
169
|
+
resolve,
|
|
170
|
+
options
|
|
65
171
|
}) {
|
|
66
172
|
// Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated.
|
|
67
173
|
// For example, with ESModule and CommonJS targets, only a single shared CSS bundle should be produced.
|
|
174
|
+
let env = asset.env;
|
|
68
175
|
asset.setEnvironment({
|
|
69
176
|
context: 'browser',
|
|
70
177
|
engines: {
|
|
71
178
|
browsers: asset.env.engines.browsers
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
asset.isSplittable = true;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
let ast = asset.ast; // Check for `hasDependencies` being false here as well, as it's possible
|
|
179
|
+
},
|
|
180
|
+
shouldOptimize: asset.env.shouldOptimize,
|
|
181
|
+
sourceMap: asset.env.sourceMap
|
|
182
|
+
});
|
|
183
|
+
let isCSSModule = asset.meta.cssModulesCompiled !== true && MODULE_BY_NAME_RE.test(asset.filePath); // Check for `hasDependencies` being false here as well, as it's possible
|
|
81
184
|
// another transformer (such as PostCSSTransformer) has already parsed an
|
|
82
185
|
// ast and CSSTransformer's parse was never called.
|
|
83
186
|
|
|
84
|
-
|
|
187
|
+
let ast = await asset.getAST();
|
|
188
|
+
|
|
189
|
+
if (!ast || asset.meta.hasDependencies === false && !isCSSModule) {
|
|
85
190
|
return [asset];
|
|
86
191
|
}
|
|
87
192
|
|
|
88
|
-
ast.program
|
|
89
|
-
|
|
193
|
+
let program = _postcss().default.fromJSON(ast.program);
|
|
194
|
+
|
|
195
|
+
let assets = [asset];
|
|
196
|
+
|
|
197
|
+
if (isCSSModule) {
|
|
198
|
+
assets = await compileCSSModules(asset, env, program, resolve, options);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (asset.meta.hasDependencies === false) {
|
|
202
|
+
return assets;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let originalSourceMap = await asset.getMap();
|
|
206
|
+
|
|
207
|
+
let createLoc = (start, specifier, lineOffset, colOffset, o) => {
|
|
208
|
+
let loc = (0, _utils().createDependencyLocation)(start, specifier, lineOffset, colOffset, o);
|
|
209
|
+
|
|
210
|
+
if (originalSourceMap) {
|
|
211
|
+
loc = (0, _utils().remapSourceLocation)(loc, originalSourceMap);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return loc;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
let isDirty = false;
|
|
218
|
+
program.walkAtRules('import', rule => {
|
|
219
|
+
let params = (0, _postcssValueParser().default)(rule.params);
|
|
90
220
|
let [name, ...media] = params.nodes;
|
|
91
|
-
let
|
|
221
|
+
let specifier;
|
|
92
222
|
|
|
93
223
|
if (name.type === 'function' && name.value === 'url' && name.nodes.length) {
|
|
94
224
|
name = name.nodes[0];
|
|
95
225
|
}
|
|
96
226
|
|
|
97
|
-
|
|
227
|
+
specifier = name.value;
|
|
98
228
|
|
|
99
|
-
if (!
|
|
100
|
-
throw new Error('Could not find import name for ' + rule);
|
|
101
|
-
}
|
|
229
|
+
if (!specifier) {
|
|
230
|
+
throw new Error('Could not find import name for ' + String(rule));
|
|
231
|
+
} // If this came from an inline <style> tag, don't inline the imported file. Replace with the correct URL instead.
|
|
232
|
+
// TODO: run CSSPackager on inline style tags.
|
|
233
|
+
// let inlineHTML =
|
|
234
|
+
// this.options.rendition && this.options.rendition.inlineHTML;
|
|
235
|
+
// if (inlineHTML) {
|
|
236
|
+
// name.value = asset.addURLDependency(dep, {loc: rule.source.start});
|
|
237
|
+
// rule.params = params.toString();
|
|
238
|
+
// } else {
|
|
102
239
|
|
|
103
|
-
if ((0, _utils.isURL)(moduleSpecifier)) {
|
|
104
|
-
name.value = asset.addURLDependency(moduleSpecifier, {
|
|
105
|
-
loc: (0, _utils.createDependencyLocation)(rule.source.start, moduleSpecifier, 0, 8)
|
|
106
|
-
});
|
|
107
|
-
} else {
|
|
108
|
-
// If this came from an inline <style> tag, don't inline the imported file. Replace with the correct URL instead.
|
|
109
|
-
// TODO: run CSSPackager on inline style tags.
|
|
110
|
-
// let inlineHTML =
|
|
111
|
-
// this.options.rendition && this.options.rendition.inlineHTML;
|
|
112
|
-
// if (inlineHTML) {
|
|
113
|
-
// name.value = asset.addURLDependency(dep, {loc: rule.source.start});
|
|
114
|
-
// rule.params = params.toString();
|
|
115
|
-
// } else {
|
|
116
|
-
media = _postcssValueParser.default.stringify(media).trim();
|
|
117
|
-
let dep = {
|
|
118
|
-
moduleSpecifier,
|
|
119
|
-
// Offset by 8 as it does not include `@import `
|
|
120
|
-
loc: (0, _utils.createDependencyLocation)(rule.source.start, moduleSpecifier, 0, 8),
|
|
121
|
-
meta: {
|
|
122
|
-
media
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
asset.addDependency(dep);
|
|
126
|
-
rule.remove(); // }
|
|
127
|
-
}
|
|
128
240
|
|
|
129
|
-
|
|
241
|
+
media = _postcssValueParser().default.stringify(media).trim();
|
|
242
|
+
let dep = {
|
|
243
|
+
specifier,
|
|
244
|
+
specifierType: 'url',
|
|
245
|
+
// Offset by 8 as it does not include `@import `
|
|
246
|
+
loc: createLoc((0, _nullthrows().default)(rule.source.start), specifier, 0, 8),
|
|
247
|
+
meta: {
|
|
248
|
+
// For the glob resolver to distinguish between `@import` and other URL dependencies.
|
|
249
|
+
isCSSImport: true,
|
|
250
|
+
media
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
asset.addDependency(dep);
|
|
254
|
+
rule.remove(); // }
|
|
255
|
+
|
|
256
|
+
isDirty = true;
|
|
130
257
|
});
|
|
131
|
-
|
|
258
|
+
program.walkDecls(decl => {
|
|
132
259
|
if (URL_RE.test(decl.value)) {
|
|
133
|
-
let parsed = (0, _postcssValueParser.default)(decl.value);
|
|
134
|
-
let
|
|
260
|
+
let parsed = (0, _postcssValueParser().default)(decl.value);
|
|
261
|
+
let isDeclDirty = false;
|
|
135
262
|
parsed.walk(node => {
|
|
136
263
|
if (node.type === 'function' && node.value === 'url' && node.nodes.length > 0 && !node.nodes[0].value.startsWith('#') // IE's `behavior: url(#default#VML)`
|
|
137
264
|
) {
|
|
138
|
-
|
|
139
|
-
|
|
265
|
+
let urlNode = node.nodes[0];
|
|
266
|
+
let url = asset.addURLDependency(urlNode.value, {
|
|
267
|
+
loc: decl.source && decl.source.start && createLoc(decl.source.start, urlNode.value, 0, decl.source.start.offset + urlNode.sourceIndex + 1, 0)
|
|
140
268
|
});
|
|
141
|
-
|
|
269
|
+
isDeclDirty = urlNode.value !== url;
|
|
270
|
+
urlNode.type = 'word';
|
|
271
|
+
urlNode.value = url;
|
|
142
272
|
}
|
|
143
273
|
});
|
|
144
274
|
|
|
145
|
-
if (
|
|
275
|
+
if (isDeclDirty) {
|
|
146
276
|
decl.value = parsed.toString();
|
|
147
|
-
|
|
277
|
+
isDirty = true;
|
|
148
278
|
}
|
|
149
279
|
}
|
|
150
280
|
});
|
|
151
|
-
|
|
281
|
+
|
|
282
|
+
if (isDirty) {
|
|
283
|
+
asset.setAST({ ...ast,
|
|
284
|
+
program: program.toJSON()
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return assets;
|
|
152
289
|
},
|
|
153
290
|
|
|
154
291
|
async generate({
|
|
155
|
-
asset
|
|
292
|
+
asset,
|
|
293
|
+
ast,
|
|
294
|
+
options
|
|
156
295
|
}) {
|
|
157
|
-
let
|
|
296
|
+
let result = await (0, _postcss().default)().process(_postcss().default.fromJSON(ast.program), {
|
|
297
|
+
from: undefined,
|
|
298
|
+
to: options.projectRoot + '/index',
|
|
299
|
+
map: {
|
|
300
|
+
annotation: false,
|
|
301
|
+
inline: false,
|
|
302
|
+
sourcesContent: false
|
|
303
|
+
},
|
|
304
|
+
// Pass postcss's own stringifier to it to silence its warning
|
|
305
|
+
// as we don't want to perform any transformations -- only generate
|
|
306
|
+
stringifier: _postcss().default.stringify
|
|
307
|
+
});
|
|
308
|
+
let map = null;
|
|
309
|
+
let originalSourceMap = await asset.getMap();
|
|
158
310
|
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
code = '';
|
|
311
|
+
if (result.map != null) {
|
|
312
|
+
map = new (_sourceMap().default)(options.projectRoot);
|
|
313
|
+
map.addVLQMap(result.map.toJSON());
|
|
163
314
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
315
|
+
if (originalSourceMap) {
|
|
316
|
+
map.extends(originalSourceMap.toBuffer());
|
|
317
|
+
}
|
|
318
|
+
} else {
|
|
319
|
+
map = originalSourceMap;
|
|
167
320
|
}
|
|
168
321
|
|
|
169
322
|
return {
|
|
170
|
-
|
|
323
|
+
content: result.css,
|
|
324
|
+
map
|
|
171
325
|
};
|
|
172
326
|
}
|
|
173
327
|
|
|
174
328
|
});
|
|
175
329
|
|
|
176
|
-
exports.default = _default;
|
|
330
|
+
exports.default = _default;
|
|
331
|
+
|
|
332
|
+
async function compileCSSModules(asset, env, program, resolve, options) {
|
|
333
|
+
let cssModules;
|
|
334
|
+
let code = asset.isASTDirty() ? null : await asset.getCode();
|
|
335
|
+
|
|
336
|
+
if (code == null || COMPOSES_RE.test(code)) {
|
|
337
|
+
program.walkDecls(decl => {
|
|
338
|
+
let [, importPath] = FROM_IMPORT_RE.exec(decl.value) || [];
|
|
339
|
+
|
|
340
|
+
if (decl.prop === 'composes' && importPath != null) {
|
|
341
|
+
let parsed = (0, _postcssValueParser().default)(decl.value);
|
|
342
|
+
let start = decl.source.start;
|
|
343
|
+
parsed.walk(node => {
|
|
344
|
+
if (node.type === 'string') {
|
|
345
|
+
asset.addDependency({
|
|
346
|
+
specifier: importPath,
|
|
347
|
+
specifierType: 'url',
|
|
348
|
+
loc: start ? {
|
|
349
|
+
filePath: asset.filePath,
|
|
350
|
+
start,
|
|
351
|
+
end: {
|
|
352
|
+
line: start.line,
|
|
353
|
+
column: start.column + importPath.length
|
|
354
|
+
}
|
|
355
|
+
} : undefined
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
let {
|
|
364
|
+
root
|
|
365
|
+
} = await (0, _postcss().default)([(0, _postcssModules().default)({
|
|
366
|
+
getJSON: (filename, json) => cssModules = json,
|
|
367
|
+
Loader: createLoader(asset, resolve),
|
|
368
|
+
generateScopedName: (name, filename) => `${name}_${(0, _hash().hashString)(_path().default.relative(options.projectRoot, filename)).substr(0, 6)}`
|
|
369
|
+
})]).process(program, {
|
|
370
|
+
from: asset.filePath,
|
|
371
|
+
to: asset.filePath
|
|
372
|
+
});
|
|
373
|
+
asset.setAST({
|
|
374
|
+
type: 'postcss',
|
|
375
|
+
version: '8.2.1',
|
|
376
|
+
program: root.toJSON()
|
|
377
|
+
});
|
|
378
|
+
let assets = [asset];
|
|
379
|
+
|
|
380
|
+
if (cssModules) {
|
|
381
|
+
// $FlowFixMe
|
|
382
|
+
let cssModulesList = Object.entries(cssModules);
|
|
383
|
+
let deps = asset.getDependencies().filter(dep => dep.priority === 'sync');
|
|
384
|
+
let code;
|
|
385
|
+
|
|
386
|
+
if (deps.length > 0) {
|
|
387
|
+
code = `
|
|
388
|
+
module.exports = Object.assign({}, ${deps.map(dep => `require(${JSON.stringify(dep.specifier)})`).join(', ')}, ${JSON.stringify(cssModules, null, 2)});
|
|
389
|
+
`;
|
|
390
|
+
} else {
|
|
391
|
+
code = cssModulesList.map( // This syntax enables shaking the invidual statements, so that unused classes don't even exist in JS.
|
|
392
|
+
([className, classNameHashed]) => `module.exports[${JSON.stringify(className)}] = ${JSON.stringify(classNameHashed)};`).join('\n');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
asset.symbols.ensure();
|
|
396
|
+
|
|
397
|
+
for (let [k, v] of cssModulesList) {
|
|
398
|
+
asset.symbols.set(k, v);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
asset.symbols.set('default', 'default');
|
|
402
|
+
assets.push({
|
|
403
|
+
type: 'js',
|
|
404
|
+
content: code,
|
|
405
|
+
env
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return assets;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function createLoader(asset, resolve) {
|
|
413
|
+
return class extends _fileSystemLoader().default {
|
|
414
|
+
async fetch(composesPath, relativeTo) {
|
|
415
|
+
let importPath = composesPath.replace(/^["']|["']$/g, '');
|
|
416
|
+
let resolved = await resolve(relativeTo, importPath);
|
|
417
|
+
|
|
418
|
+
let rootRelativePath = _path().default.resolve(_path().default.dirname(relativeTo), resolved);
|
|
419
|
+
|
|
420
|
+
let root = _path().default.resolve('/'); // fixes an issue on windows which is part of the css-modules-loader-core
|
|
421
|
+
// see https://github.com/css-modules/css-modules-loader-core/issues/230
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
if (rootRelativePath.startsWith(root)) {
|
|
425
|
+
rootRelativePath = rootRelativePath.substr(root.length);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
let source = await asset.fs.readFile(resolved, 'utf-8');
|
|
429
|
+
let {
|
|
430
|
+
exportTokens
|
|
431
|
+
} = await this.core.load(source, rootRelativePath, undefined, // $FlowFixMe[method-unbinding]
|
|
432
|
+
this.fetch.bind(this));
|
|
433
|
+
return exportTokens;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
get finalSource() {
|
|
437
|
+
return '';
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
};
|
|
441
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/transformer-css",
|
|
3
|
-
"version": "2.0.0-nightly.
|
|
3
|
+
"version": "2.0.0-nightly.982+4745cd30",
|
|
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,15 +16,20 @@
|
|
|
12
16
|
"main": "lib/CSSTransformer.js",
|
|
13
17
|
"source": "src/CSSTransformer.js",
|
|
14
18
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
16
|
-
"parcel": "
|
|
19
|
+
"node": ">= 12.0.0",
|
|
20
|
+
"parcel": "2.0.0-nightly.980+4745cd30"
|
|
17
21
|
},
|
|
18
22
|
"dependencies": {
|
|
19
|
-
"@parcel/
|
|
20
|
-
"@parcel/
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
23
|
+
"@parcel/hash": "2.2.1-nightly.2605+4745cd30",
|
|
24
|
+
"@parcel/plugin": "2.0.0-nightly.982+4745cd30",
|
|
25
|
+
"@parcel/source-map": "^2.0.0",
|
|
26
|
+
"@parcel/utils": "2.0.0-nightly.982+4745cd30",
|
|
27
|
+
"css-modules-loader-core": "^1.1.0",
|
|
28
|
+
"nullthrows": "^1.1.1",
|
|
29
|
+
"postcss": "^8.3.0",
|
|
30
|
+
"postcss-modules": "^3.2.2",
|
|
31
|
+
"postcss-value-parser": "^4.1.0",
|
|
32
|
+
"semver": "^5.7.1"
|
|
24
33
|
},
|
|
25
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "4745cd3023f8d5a5adcf9e565d5b82d1418dc262"
|
|
26
35
|
}
|
package/src/CSSTransformer.js
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {Root} from 'postcss';
|
|
4
|
+
import type {FilePath, MutableAsset} from '@parcel/types';
|
|
4
5
|
|
|
6
|
+
import {hashString} from '@parcel/hash';
|
|
7
|
+
import SourceMap from '@parcel/source-map';
|
|
5
8
|
import {Transformer} from '@parcel/plugin';
|
|
6
|
-
import {createDependencyLocation,
|
|
9
|
+
import {createDependencyLocation, remapSourceLocation} from '@parcel/utils';
|
|
7
10
|
import postcss from 'postcss';
|
|
11
|
+
import nullthrows from 'nullthrows';
|
|
8
12
|
import valueParser from 'postcss-value-parser';
|
|
13
|
+
import postcssModules from 'postcss-modules';
|
|
14
|
+
import FileSystemLoader from 'css-modules-loader-core/lib/file-system-loader';
|
|
9
15
|
import semver from 'semver';
|
|
16
|
+
import path from 'path';
|
|
10
17
|
|
|
11
18
|
const URL_RE = /url\s*\("?(?![a-z]+:)/;
|
|
12
19
|
const IMPORT_RE = /@import/;
|
|
20
|
+
const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/;
|
|
21
|
+
const FROM_IMPORT_RE = /.+from\s*(?:"|')(.*)(?:"|')\s*;?/;
|
|
22
|
+
const MODULE_BY_NAME_RE = /\.module\./;
|
|
13
23
|
|
|
14
24
|
function canHaveDependencies(filePath: FilePath, code: string) {
|
|
15
25
|
return !/\.css$/.test(filePath) || IMPORT_RE.test(code) || URL_RE.test(code);
|
|
16
26
|
}
|
|
17
27
|
|
|
18
|
-
export default new Transformer({
|
|
28
|
+
export default (new Transformer({
|
|
19
29
|
canReuseAST({ast}) {
|
|
20
|
-
return ast.type === 'postcss' && semver.satisfies(ast.version, '^
|
|
30
|
+
return ast.type === 'postcss' && semver.satisfies(ast.version, '^8.2.1');
|
|
21
31
|
},
|
|
22
32
|
|
|
23
33
|
async parse({asset}) {
|
|
@@ -27,53 +37,88 @@ export default new Transformer({
|
|
|
27
37
|
// to be filled in later. When the CSS transformer runs, it would pick that up and try to
|
|
28
38
|
// resolve a dependency for the id which obviously doesn't exist. Also, it's faster to do
|
|
29
39
|
// it this way since the resulting CSS doesn't need to be re-parsed.
|
|
30
|
-
|
|
40
|
+
let isCSSModule =
|
|
41
|
+
asset.meta.cssModulesCompiled !== true &&
|
|
42
|
+
MODULE_BY_NAME_RE.test(asset.filePath);
|
|
43
|
+
if (asset.meta.hasDependencies === false && !isCSSModule) {
|
|
31
44
|
return null;
|
|
32
45
|
}
|
|
33
46
|
|
|
34
47
|
let code = await asset.getCode();
|
|
35
|
-
if (
|
|
48
|
+
if (
|
|
49
|
+
code != null &&
|
|
50
|
+
!canHaveDependencies(asset.filePath, code) &&
|
|
51
|
+
!isCSSModule
|
|
52
|
+
) {
|
|
36
53
|
return null;
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
return {
|
|
40
57
|
type: 'postcss',
|
|
41
|
-
version: '
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
version: '8.2.1',
|
|
59
|
+
program: postcss
|
|
60
|
+
.parse(code, {
|
|
61
|
+
from: asset.filePath,
|
|
62
|
+
})
|
|
63
|
+
.toJSON(),
|
|
46
64
|
};
|
|
47
65
|
},
|
|
48
66
|
|
|
49
|
-
transform({asset}) {
|
|
67
|
+
async transform({asset, resolve, options}) {
|
|
50
68
|
// Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated.
|
|
51
69
|
// For example, with ESModule and CommonJS targets, only a single shared CSS bundle should be produced.
|
|
70
|
+
let env = asset.env;
|
|
52
71
|
asset.setEnvironment({
|
|
53
72
|
context: 'browser',
|
|
54
73
|
engines: {
|
|
55
74
|
browsers: asset.env.engines.browsers,
|
|
56
75
|
},
|
|
76
|
+
shouldOptimize: asset.env.shouldOptimize,
|
|
77
|
+
sourceMap: asset.env.sourceMap,
|
|
57
78
|
});
|
|
58
79
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
asset.isSplittable = true;
|
|
63
|
-
}
|
|
80
|
+
let isCSSModule =
|
|
81
|
+
asset.meta.cssModulesCompiled !== true &&
|
|
82
|
+
MODULE_BY_NAME_RE.test(asset.filePath);
|
|
64
83
|
|
|
65
|
-
let ast = asset.ast;
|
|
66
84
|
// Check for `hasDependencies` being false here as well, as it's possible
|
|
67
85
|
// another transformer (such as PostCSSTransformer) has already parsed an
|
|
68
86
|
// ast and CSSTransformer's parse was never called.
|
|
69
|
-
|
|
87
|
+
let ast = await asset.getAST();
|
|
88
|
+
if (!ast || (asset.meta.hasDependencies === false && !isCSSModule)) {
|
|
70
89
|
return [asset];
|
|
71
90
|
}
|
|
72
91
|
|
|
73
|
-
|
|
92
|
+
let program: Root = postcss.fromJSON(ast.program);
|
|
93
|
+
let assets = [asset];
|
|
94
|
+
if (isCSSModule) {
|
|
95
|
+
assets = await compileCSSModules(asset, env, program, resolve, options);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (asset.meta.hasDependencies === false) {
|
|
99
|
+
return assets;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let originalSourceMap = await asset.getMap();
|
|
103
|
+
let createLoc = (start, specifier, lineOffset, colOffset, o) => {
|
|
104
|
+
let loc = createDependencyLocation(
|
|
105
|
+
start,
|
|
106
|
+
specifier,
|
|
107
|
+
lineOffset,
|
|
108
|
+
colOffset,
|
|
109
|
+
o,
|
|
110
|
+
);
|
|
111
|
+
if (originalSourceMap) {
|
|
112
|
+
loc = remapSourceLocation(loc, originalSourceMap);
|
|
113
|
+
}
|
|
114
|
+
return loc;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
let isDirty = false;
|
|
118
|
+
program.walkAtRules('import', rule => {
|
|
74
119
|
let params = valueParser(rule.params);
|
|
75
120
|
let [name, ...media] = params.nodes;
|
|
76
|
-
let
|
|
121
|
+
let specifier;
|
|
77
122
|
if (
|
|
78
123
|
name.type === 'function' &&
|
|
79
124
|
name.value === 'url' &&
|
|
@@ -82,55 +127,42 @@ export default new Transformer({
|
|
|
82
127
|
name = name.nodes[0];
|
|
83
128
|
}
|
|
84
129
|
|
|
85
|
-
|
|
130
|
+
specifier = name.value;
|
|
86
131
|
|
|
87
|
-
if (!
|
|
88
|
-
throw new Error('Could not find import name for ' + rule);
|
|
132
|
+
if (!specifier) {
|
|
133
|
+
throw new Error('Could not find import name for ' + String(rule));
|
|
89
134
|
}
|
|
90
135
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
moduleSpecifier,
|
|
116
|
-
0,
|
|
117
|
-
8,
|
|
118
|
-
),
|
|
119
|
-
meta: {
|
|
120
|
-
media,
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
asset.addDependency(dep);
|
|
124
|
-
rule.remove();
|
|
125
|
-
// }
|
|
126
|
-
}
|
|
127
|
-
ast.isDirty = true;
|
|
136
|
+
// If this came from an inline <style> tag, don't inline the imported file. Replace with the correct URL instead.
|
|
137
|
+
// TODO: run CSSPackager on inline style tags.
|
|
138
|
+
// let inlineHTML =
|
|
139
|
+
// this.options.rendition && this.options.rendition.inlineHTML;
|
|
140
|
+
// if (inlineHTML) {
|
|
141
|
+
// name.value = asset.addURLDependency(dep, {loc: rule.source.start});
|
|
142
|
+
// rule.params = params.toString();
|
|
143
|
+
// } else {
|
|
144
|
+
media = valueParser.stringify(media).trim();
|
|
145
|
+
let dep = {
|
|
146
|
+
specifier,
|
|
147
|
+
specifierType: 'url',
|
|
148
|
+
// Offset by 8 as it does not include `@import `
|
|
149
|
+
loc: createLoc(nullthrows(rule.source.start), specifier, 0, 8),
|
|
150
|
+
meta: {
|
|
151
|
+
// For the glob resolver to distinguish between `@import` and other URL dependencies.
|
|
152
|
+
isCSSImport: true,
|
|
153
|
+
media,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
asset.addDependency(dep);
|
|
157
|
+
rule.remove();
|
|
158
|
+
// }
|
|
159
|
+
isDirty = true;
|
|
128
160
|
});
|
|
129
161
|
|
|
130
|
-
|
|
162
|
+
program.walkDecls(decl => {
|
|
131
163
|
if (URL_RE.test(decl.value)) {
|
|
132
164
|
let parsed = valueParser(decl.value);
|
|
133
|
-
let
|
|
165
|
+
let isDeclDirty = false;
|
|
134
166
|
|
|
135
167
|
parsed.walk(node => {
|
|
136
168
|
if (
|
|
@@ -139,39 +171,192 @@ export default new Transformer({
|
|
|
139
171
|
node.nodes.length > 0 &&
|
|
140
172
|
!node.nodes[0].value.startsWith('#') // IE's `behavior: url(#default#VML)`
|
|
141
173
|
) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
174
|
+
let urlNode = node.nodes[0];
|
|
175
|
+
let url = asset.addURLDependency(urlNode.value, {
|
|
176
|
+
loc:
|
|
177
|
+
decl.source &&
|
|
178
|
+
decl.source.start &&
|
|
179
|
+
createLoc(
|
|
180
|
+
decl.source.start,
|
|
181
|
+
urlNode.value,
|
|
182
|
+
0,
|
|
183
|
+
decl.source.start.offset + urlNode.sourceIndex + 1,
|
|
184
|
+
0,
|
|
185
|
+
),
|
|
147
186
|
});
|
|
148
|
-
|
|
187
|
+
isDeclDirty = urlNode.value !== url;
|
|
188
|
+
urlNode.type = 'word';
|
|
189
|
+
urlNode.value = url;
|
|
149
190
|
}
|
|
150
191
|
});
|
|
151
192
|
|
|
152
|
-
if (
|
|
193
|
+
if (isDeclDirty) {
|
|
153
194
|
decl.value = parsed.toString();
|
|
154
|
-
|
|
195
|
+
isDirty = true;
|
|
155
196
|
}
|
|
156
197
|
}
|
|
157
198
|
});
|
|
158
199
|
|
|
159
|
-
|
|
200
|
+
if (isDirty) {
|
|
201
|
+
asset.setAST({
|
|
202
|
+
...ast,
|
|
203
|
+
program: program.toJSON(),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return assets;
|
|
160
208
|
},
|
|
161
209
|
|
|
162
|
-
async generate({asset}) {
|
|
163
|
-
let
|
|
164
|
-
|
|
165
|
-
|
|
210
|
+
async generate({asset, ast, options}) {
|
|
211
|
+
let result = await postcss().process(postcss.fromJSON(ast.program), {
|
|
212
|
+
from: undefined,
|
|
213
|
+
to: options.projectRoot + '/index',
|
|
214
|
+
map: {
|
|
215
|
+
annotation: false,
|
|
216
|
+
inline: false,
|
|
217
|
+
sourcesContent: false,
|
|
218
|
+
},
|
|
219
|
+
// Pass postcss's own stringifier to it to silence its warning
|
|
220
|
+
// as we don't want to perform any transformations -- only generate
|
|
221
|
+
stringifier: postcss.stringify,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
let map = null;
|
|
225
|
+
let originalSourceMap = await asset.getMap();
|
|
226
|
+
if (result.map != null) {
|
|
227
|
+
map = new SourceMap(options.projectRoot);
|
|
228
|
+
map.addVLQMap(result.map.toJSON());
|
|
229
|
+
if (originalSourceMap) {
|
|
230
|
+
map.extends(originalSourceMap.toBuffer());
|
|
231
|
+
}
|
|
166
232
|
} else {
|
|
167
|
-
|
|
168
|
-
postcss.stringify(asset.ast.program, c => {
|
|
169
|
-
code += c;
|
|
170
|
-
});
|
|
233
|
+
map = originalSourceMap;
|
|
171
234
|
}
|
|
172
235
|
|
|
173
236
|
return {
|
|
174
|
-
|
|
237
|
+
content: result.css,
|
|
238
|
+
map,
|
|
175
239
|
};
|
|
176
240
|
},
|
|
177
|
-
});
|
|
241
|
+
}): Transformer);
|
|
242
|
+
|
|
243
|
+
async function compileCSSModules(asset, env, program, resolve, options) {
|
|
244
|
+
let cssModules;
|
|
245
|
+
|
|
246
|
+
let code = asset.isASTDirty() ? null : await asset.getCode();
|
|
247
|
+
if (code == null || COMPOSES_RE.test(code)) {
|
|
248
|
+
program.walkDecls(decl => {
|
|
249
|
+
let [, importPath] = FROM_IMPORT_RE.exec(decl.value) || [];
|
|
250
|
+
if (decl.prop === 'composes' && importPath != null) {
|
|
251
|
+
let parsed = valueParser(decl.value);
|
|
252
|
+
let start = (decl.source.start: any);
|
|
253
|
+
|
|
254
|
+
parsed.walk(node => {
|
|
255
|
+
if (node.type === 'string') {
|
|
256
|
+
asset.addDependency({
|
|
257
|
+
specifier: importPath,
|
|
258
|
+
specifierType: 'url',
|
|
259
|
+
loc: start
|
|
260
|
+
? {
|
|
261
|
+
filePath: asset.filePath,
|
|
262
|
+
start,
|
|
263
|
+
end: {
|
|
264
|
+
line: start.line,
|
|
265
|
+
column: start.column + importPath.length,
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
: undefined,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let {root} = await postcss([
|
|
277
|
+
postcssModules({
|
|
278
|
+
getJSON: (filename, json) => (cssModules = json),
|
|
279
|
+
Loader: createLoader(asset, resolve),
|
|
280
|
+
generateScopedName: (name, filename) =>
|
|
281
|
+
`${name}_${hashString(
|
|
282
|
+
path.relative(options.projectRoot, filename),
|
|
283
|
+
).substr(0, 6)}`,
|
|
284
|
+
}),
|
|
285
|
+
]).process(program, {from: asset.filePath, to: asset.filePath});
|
|
286
|
+
asset.setAST({
|
|
287
|
+
type: 'postcss',
|
|
288
|
+
version: '8.2.1',
|
|
289
|
+
program: root.toJSON(),
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
let assets = [asset];
|
|
293
|
+
if (cssModules) {
|
|
294
|
+
// $FlowFixMe
|
|
295
|
+
let cssModulesList = (Object.entries(cssModules): Array<[string, string]>);
|
|
296
|
+
let deps = asset.getDependencies().filter(dep => dep.priority === 'sync');
|
|
297
|
+
let code: string;
|
|
298
|
+
if (deps.length > 0) {
|
|
299
|
+
code = `
|
|
300
|
+
module.exports = Object.assign({}, ${deps
|
|
301
|
+
.map(dep => `require(${JSON.stringify(dep.specifier)})`)
|
|
302
|
+
.join(', ')}, ${JSON.stringify(cssModules, null, 2)});
|
|
303
|
+
`;
|
|
304
|
+
} else {
|
|
305
|
+
code = cssModulesList
|
|
306
|
+
.map(
|
|
307
|
+
// This syntax enables shaking the invidual statements, so that unused classes don't even exist in JS.
|
|
308
|
+
([className, classNameHashed]) =>
|
|
309
|
+
`module.exports[${JSON.stringify(className)}] = ${JSON.stringify(
|
|
310
|
+
classNameHashed,
|
|
311
|
+
)};`,
|
|
312
|
+
)
|
|
313
|
+
.join('\n');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
asset.symbols.ensure();
|
|
317
|
+
for (let [k, v] of cssModulesList) {
|
|
318
|
+
asset.symbols.set(k, v);
|
|
319
|
+
}
|
|
320
|
+
asset.symbols.set('default', 'default');
|
|
321
|
+
|
|
322
|
+
assets.push({
|
|
323
|
+
type: 'js',
|
|
324
|
+
content: code,
|
|
325
|
+
env,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
return assets;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function createLoader(
|
|
332
|
+
asset: MutableAsset,
|
|
333
|
+
resolve: (from: FilePath, to: string) => Promise<FilePath>,
|
|
334
|
+
) {
|
|
335
|
+
return class ParcelFileSystemLoader extends FileSystemLoader {
|
|
336
|
+
async fetch(composesPath, relativeTo) {
|
|
337
|
+
let importPath = composesPath.replace(/^["']|["']$/g, '');
|
|
338
|
+
let resolved = await resolve(relativeTo, importPath);
|
|
339
|
+
let rootRelativePath = path.resolve(path.dirname(relativeTo), resolved);
|
|
340
|
+
let root = path.resolve('/');
|
|
341
|
+
// fixes an issue on windows which is part of the css-modules-loader-core
|
|
342
|
+
// see https://github.com/css-modules/css-modules-loader-core/issues/230
|
|
343
|
+
if (rootRelativePath.startsWith(root)) {
|
|
344
|
+
rootRelativePath = rootRelativePath.substr(root.length);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
let source = await asset.fs.readFile(resolved, 'utf-8');
|
|
348
|
+
let {exportTokens} = await this.core.load(
|
|
349
|
+
source,
|
|
350
|
+
rootRelativePath,
|
|
351
|
+
undefined,
|
|
352
|
+
// $FlowFixMe[method-unbinding]
|
|
353
|
+
this.fetch.bind(this),
|
|
354
|
+
);
|
|
355
|
+
return exportTokens;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
get finalSource() {
|
|
359
|
+
return '';
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|