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