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