css-loader 7.0.0 → 7.1.0
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/README.md +264 -6
- package/dist/index.js +16 -0
- package/dist/options.json +5 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ Then add the plugin to your `webpack` config. For example:
|
|
|
47
47
|
**file.js**
|
|
48
48
|
|
|
49
49
|
```js
|
|
50
|
-
import css from "file.css";
|
|
50
|
+
import * as css from "file.css";
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
**webpack.config.js**
|
|
@@ -327,6 +327,17 @@ type modules =
|
|
|
327
327
|
| "dashes-only"
|
|
328
328
|
| ((name: string) => string);
|
|
329
329
|
exportOnlyLocals: boolean;
|
|
330
|
+
getJSON: ({
|
|
331
|
+
resourcePath,
|
|
332
|
+
imports,
|
|
333
|
+
exports,
|
|
334
|
+
replacements,
|
|
335
|
+
}: {
|
|
336
|
+
resourcePath: string;
|
|
337
|
+
imports: object[];
|
|
338
|
+
exports: object[];
|
|
339
|
+
replacements: object[];
|
|
340
|
+
}) => Promise<void> | void;
|
|
330
341
|
};
|
|
331
342
|
```
|
|
332
343
|
|
|
@@ -604,6 +615,7 @@ module.exports = {
|
|
|
604
615
|
namedExport: true,
|
|
605
616
|
exportLocalsConvention: "as-is",
|
|
606
617
|
exportOnlyLocals: false,
|
|
618
|
+
getJSON: ({ resourcePath, imports, exports, replacements }) => {},
|
|
607
619
|
},
|
|
608
620
|
},
|
|
609
621
|
},
|
|
@@ -1162,11 +1174,11 @@ Enables/disables ES modules named export for locals.
|
|
|
1162
1174
|
```js
|
|
1163
1175
|
import * as styles from "./styles.css";
|
|
1164
1176
|
|
|
1177
|
+
// If using `exportLocalsConvention: "as-is"` (default value):
|
|
1178
|
+
console.log(styles["foo-baz"], styles.bar);
|
|
1179
|
+
|
|
1165
1180
|
// If using `exportLocalsConvention: "camel-case-only"`:
|
|
1166
1181
|
console.log(styles.fooBaz, styles.bar);
|
|
1167
|
-
|
|
1168
|
-
// If using `exportLocalsConvention: "as-is"`:
|
|
1169
|
-
console.log(styles["foo-baz"], styles.bar);
|
|
1170
1182
|
```
|
|
1171
1183
|
|
|
1172
1184
|
You can enable a ES module named export using:
|
|
@@ -1384,6 +1396,252 @@ module.exports = {
|
|
|
1384
1396
|
};
|
|
1385
1397
|
```
|
|
1386
1398
|
|
|
1399
|
+
##### `getJSON`
|
|
1400
|
+
|
|
1401
|
+
Type:
|
|
1402
|
+
|
|
1403
|
+
```ts
|
|
1404
|
+
type getJSON = ({
|
|
1405
|
+
resourcePath,
|
|
1406
|
+
imports,
|
|
1407
|
+
exports,
|
|
1408
|
+
replacements,
|
|
1409
|
+
}: {
|
|
1410
|
+
resourcePath: string;
|
|
1411
|
+
imports: object[];
|
|
1412
|
+
exports: object[];
|
|
1413
|
+
replacements: object[];
|
|
1414
|
+
}) => Promise<void> | void;
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
Default: `undefined`
|
|
1418
|
+
|
|
1419
|
+
Enables a callback to output the CSS modules mapping JSON. The callback is invoked with an object containing the following:
|
|
1420
|
+
|
|
1421
|
+
- `resourcePath`: the absolute path of the original resource, e.g., `/foo/bar/baz.module.css`
|
|
1422
|
+
|
|
1423
|
+
- `imports`: an array of import objects with data about import types and file paths, e.g.,
|
|
1424
|
+
|
|
1425
|
+
```json
|
|
1426
|
+
[
|
|
1427
|
+
{
|
|
1428
|
+
"type": "icss_import",
|
|
1429
|
+
"importName": "___CSS_LOADER_ICSS_IMPORT_0___",
|
|
1430
|
+
"url": "\"-!../../../../../node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!../../../../../node_modules/postcss-loader/dist/cjs.js!../../../../../node_modules/sass-loader/dist/cjs.js!../../../../baz.module.css\"",
|
|
1431
|
+
"icss": true,
|
|
1432
|
+
"index": 0
|
|
1433
|
+
}
|
|
1434
|
+
]
|
|
1435
|
+
```
|
|
1436
|
+
|
|
1437
|
+
(Note that this will include all imports, not just those relevant to CSS modules.)
|
|
1438
|
+
|
|
1439
|
+
- `exports`: an array of export objects with exported names and values, e.g.,
|
|
1440
|
+
|
|
1441
|
+
```json
|
|
1442
|
+
[
|
|
1443
|
+
{
|
|
1444
|
+
"name": "main",
|
|
1445
|
+
"value": "D2Oy"
|
|
1446
|
+
}
|
|
1447
|
+
]
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1450
|
+
- `replacements`: an array of import replacement objects used for linking `imports` and `exports`, e.g.,
|
|
1451
|
+
|
|
1452
|
+
```json
|
|
1453
|
+
{
|
|
1454
|
+
"replacementName": "___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___",
|
|
1455
|
+
"importName": "___CSS_LOADER_ICSS_IMPORT_0___",
|
|
1456
|
+
"localName": "main"
|
|
1457
|
+
}
|
|
1458
|
+
```
|
|
1459
|
+
|
|
1460
|
+
Using `getJSON`, it's possible to output a files with all CSS module mappings.
|
|
1461
|
+
In the following example, we use `getJSON` to cache canonical mappings and
|
|
1462
|
+
add stand-ins for any composed values (through `composes`), and we use a custom plugin
|
|
1463
|
+
to consolidate the values and output them to a file:
|
|
1464
|
+
|
|
1465
|
+
**webpack.config.js**
|
|
1466
|
+
|
|
1467
|
+
```js
|
|
1468
|
+
const path = require("path");
|
|
1469
|
+
const fs = require("fs");
|
|
1470
|
+
|
|
1471
|
+
const CSS_LOADER_REPLACEMENT_REGEX =
|
|
1472
|
+
/(___CSS_LOADER_ICSS_IMPORT_\d+_REPLACEMENT_\d+___)/g;
|
|
1473
|
+
const REPLACEMENT_REGEX = /___REPLACEMENT\[(.*?)]\[(.*?)]___/g;
|
|
1474
|
+
const IDENTIFIER_REGEX = /\[(.*?)]\[(.*?)]/;
|
|
1475
|
+
const replacementsMap = {};
|
|
1476
|
+
const canonicalValuesMap = {};
|
|
1477
|
+
const allExportsJson = {};
|
|
1478
|
+
|
|
1479
|
+
function generateIdentifier(resourcePath, localName) {
|
|
1480
|
+
return `[${resourcePath}][${localName}]`;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
function addReplacements(resourcePath, imports, exportsJson, replacements) {
|
|
1484
|
+
const importReplacementsMap = {};
|
|
1485
|
+
|
|
1486
|
+
// create a dict to quickly identify imports and get their absolute stand-in strings in the currently loaded file
|
|
1487
|
+
// e.g., { '___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___': '___REPLACEMENT[/foo/bar/baz.css][main]___' }
|
|
1488
|
+
importReplacementsMap[resourcePath] = replacements.reduce(
|
|
1489
|
+
(acc, { replacementName, importName, localName }) => {
|
|
1490
|
+
const replacementImportUrl = imports.find(
|
|
1491
|
+
(importData) => importData.importName === importName,
|
|
1492
|
+
).url;
|
|
1493
|
+
const relativePathRe = /.*!(.*)"/;
|
|
1494
|
+
const [, relativePath] = replacementImportUrl.match(relativePathRe);
|
|
1495
|
+
const importPath = path.resolve(path.dirname(resourcePath), relativePath);
|
|
1496
|
+
const identifier = generateIdentifier(importPath, localName);
|
|
1497
|
+
return { ...acc, [replacementName]: `___REPLACEMENT${identifier}___` };
|
|
1498
|
+
},
|
|
1499
|
+
{},
|
|
1500
|
+
);
|
|
1501
|
+
|
|
1502
|
+
// iterate through the raw exports and add stand-in variables
|
|
1503
|
+
// ('___REPLACEMENT[<absolute_path>][<class_name>]___')
|
|
1504
|
+
// to be replaced in the plugin below
|
|
1505
|
+
for (const [localName, classNames] of Object.entries(exportsJson)) {
|
|
1506
|
+
const identifier = generateIdentifier(resourcePath, localName);
|
|
1507
|
+
|
|
1508
|
+
if (CSS_LOADER_REPLACEMENT_REGEX.test(classNames)) {
|
|
1509
|
+
// if there are any replacements needed in the concatenated class names,
|
|
1510
|
+
// add them all to the replacements map to be replaced altogether later
|
|
1511
|
+
replacementsMap[identifier] = classNames.replaceAll(
|
|
1512
|
+
CSS_LOADER_REPLACEMENT_REGEX,
|
|
1513
|
+
(_, replacementName) =>
|
|
1514
|
+
importReplacementsMap[resourcePath][replacementName],
|
|
1515
|
+
);
|
|
1516
|
+
} else {
|
|
1517
|
+
// otherwise, no class names need replacements so we can add them to
|
|
1518
|
+
// canonical values map and all exports JSON verbatim
|
|
1519
|
+
canonicalValuesMap[identifier] = classNames;
|
|
1520
|
+
|
|
1521
|
+
allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
|
|
1522
|
+
allExportsJson[resourcePath][localName] = classNames;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
function replaceReplacements(classNames) {
|
|
1528
|
+
return classNames.replaceAll(
|
|
1529
|
+
REPLACEMENT_REGEX,
|
|
1530
|
+
(_, resourcePath, localName) => {
|
|
1531
|
+
const identifier = generateIdentifier(resourcePath, localName);
|
|
1532
|
+
|
|
1533
|
+
if (identifier in canonicalValuesMap) {
|
|
1534
|
+
return canonicalValuesMap[identifier];
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// Recurse through other stand-in that may be imports
|
|
1538
|
+
const canonicalValue = replaceReplacements(replacementsMap[identifier]);
|
|
1539
|
+
|
|
1540
|
+
canonicalValuesMap[identifier] = canonicalValue;
|
|
1541
|
+
|
|
1542
|
+
return canonicalValue;
|
|
1543
|
+
},
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
function getJSON({ resourcePath, imports, exports, replacements }) {
|
|
1548
|
+
const exportsJson = exports.reduce((acc, { name, value }) => {
|
|
1549
|
+
return { ...acc, [name]: value };
|
|
1550
|
+
}, {});
|
|
1551
|
+
|
|
1552
|
+
if (replacements.length > 0) {
|
|
1553
|
+
// replacements present --> add stand-in values for absolute paths and local names,
|
|
1554
|
+
// which will be resolved to their canonical values in the plugin below
|
|
1555
|
+
addReplacements(resourcePath, imports, exportsJson, replacements);
|
|
1556
|
+
} else {
|
|
1557
|
+
// no replacements present --> add to canonicalValuesMap verbatim
|
|
1558
|
+
// since all values here are canonical/don't need resolution
|
|
1559
|
+
for (const [key, value] of Object.entries(exportsJson)) {
|
|
1560
|
+
const id = `[${resourcePath}][${key}]`;
|
|
1561
|
+
|
|
1562
|
+
canonicalValuesMap[id] = value;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
allExportsJson[resourcePath] = exportsJson;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
class CssModulesJsonPlugin {
|
|
1570
|
+
constructor(options) {
|
|
1571
|
+
this.options = options;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
// eslint-disable-next-line class-methods-use-this
|
|
1575
|
+
apply(compiler) {
|
|
1576
|
+
compiler.hooks.emit.tap("CssModulesJsonPlugin", () => {
|
|
1577
|
+
for (const [identifier, classNames] of Object.entries(replacementsMap)) {
|
|
1578
|
+
const adjustedClassNames = replaceReplacements(classNames);
|
|
1579
|
+
|
|
1580
|
+
replacementsMap[identifier] = adjustedClassNames;
|
|
1581
|
+
|
|
1582
|
+
const [, resourcePath, localName] = identifier.match(IDENTIFIER_REGEX);
|
|
1583
|
+
|
|
1584
|
+
allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
|
|
1585
|
+
allExportsJson[resourcePath][localName] = adjustedClassNames;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
fs.writeFileSync(
|
|
1589
|
+
this.options.filepath,
|
|
1590
|
+
JSON.stringify(
|
|
1591
|
+
// Make path to be relative to `context` (your project root)
|
|
1592
|
+
Object.fromEntries(
|
|
1593
|
+
Object.entries(allExportsJson).map((key) => {
|
|
1594
|
+
key[0] = path
|
|
1595
|
+
.relative(compiler.context, key[0])
|
|
1596
|
+
.replace(/\\/g, "/");
|
|
1597
|
+
|
|
1598
|
+
return key;
|
|
1599
|
+
}),
|
|
1600
|
+
),
|
|
1601
|
+
null,
|
|
1602
|
+
2,
|
|
1603
|
+
),
|
|
1604
|
+
"utf8",
|
|
1605
|
+
);
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
module.exports = {
|
|
1611
|
+
module: {
|
|
1612
|
+
rules: [
|
|
1613
|
+
{
|
|
1614
|
+
test: /\.css$/i,
|
|
1615
|
+
loader: "css-loader",
|
|
1616
|
+
options: { modules: { getJSON } },
|
|
1617
|
+
},
|
|
1618
|
+
],
|
|
1619
|
+
},
|
|
1620
|
+
plugins: [
|
|
1621
|
+
new CssModulesJsonPlugin({
|
|
1622
|
+
filepath: path.resolve(__dirname, "./output.css.json"),
|
|
1623
|
+
}),
|
|
1624
|
+
],
|
|
1625
|
+
};
|
|
1626
|
+
```
|
|
1627
|
+
|
|
1628
|
+
In the above, all import aliases are replaced with `___REPLACEMENT[<resourcePath>][<localName>]___` in `getJSON`, and they're resolved in the custom plugin. All CSS mappings are contained in `allExportsJson`:
|
|
1629
|
+
|
|
1630
|
+
```json
|
|
1631
|
+
{
|
|
1632
|
+
"foo/bar/baz.module.css": {
|
|
1633
|
+
"main": "D2Oy",
|
|
1634
|
+
"header": "thNN"
|
|
1635
|
+
},
|
|
1636
|
+
"foot/bear/bath.module.css": {
|
|
1637
|
+
"logo": "sqiR",
|
|
1638
|
+
"info": "XMyI"
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
```
|
|
1642
|
+
|
|
1643
|
+
This is saved to a local file named `output.css.json`.
|
|
1644
|
+
|
|
1387
1645
|
### `importLoaders`
|
|
1388
1646
|
|
|
1389
1647
|
Type:
|
|
@@ -2033,8 +2291,8 @@ File treated as `CSS Module`.
|
|
|
2033
2291
|
Using both `CSS Module` functionality as well as SCSS variables directly in JavaScript.
|
|
2034
2292
|
|
|
2035
2293
|
```jsx
|
|
2036
|
-
import svars from "variables.scss";
|
|
2037
|
-
import styles from "Component.module.scss";
|
|
2294
|
+
import * as svars from "variables.scss";
|
|
2295
|
+
import * as styles from "Component.module.scss";
|
|
2038
2296
|
|
|
2039
2297
|
// Render DOM with CSS modules class name
|
|
2040
2298
|
// <div className={styles.componentClass}>
|
package/dist/index.js
CHANGED
|
@@ -171,5 +171,21 @@ async function loader(content, map, meta) {
|
|
|
171
171
|
return;
|
|
172
172
|
}
|
|
173
173
|
const exportCode = (0, _utils.getExportCode)(exports, replacements, needToUseIcssPlugin, options, isTemplateLiteralSupported);
|
|
174
|
+
const {
|
|
175
|
+
getJSON
|
|
176
|
+
} = options.modules;
|
|
177
|
+
if (typeof getJSON === "function") {
|
|
178
|
+
try {
|
|
179
|
+
await getJSON({
|
|
180
|
+
resourcePath,
|
|
181
|
+
imports,
|
|
182
|
+
exports,
|
|
183
|
+
replacements
|
|
184
|
+
});
|
|
185
|
+
} catch (error) {
|
|
186
|
+
callback(error);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
174
190
|
callback(null, `${importCode}${moduleCode}${exportCode}`);
|
|
175
191
|
}
|
package/dist/options.json
CHANGED
|
@@ -173,6 +173,11 @@
|
|
|
173
173
|
"description": "Export only locals.",
|
|
174
174
|
"link": "https://github.com/webpack-contrib/css-loader#exportonlylocals",
|
|
175
175
|
"type": "boolean"
|
|
176
|
+
},
|
|
177
|
+
"getJSON": {
|
|
178
|
+
"description": "Allows outputting of CSS modules mapping through a callback.",
|
|
179
|
+
"link": "https://github.com/webpack-contrib/css-loader#getJSON",
|
|
180
|
+
"instanceof": "Function"
|
|
176
181
|
}
|
|
177
182
|
}
|
|
178
183
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "css-loader",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "css loader module for webpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "webpack-contrib/css-loader",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
|
|
37
37
|
"pretest": "npm run lint",
|
|
38
38
|
"test": "npm run test:coverage",
|
|
39
|
-
"prepare": "husky
|
|
39
|
+
"prepare": "husky && npm run build",
|
|
40
40
|
"release": "standard-version"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|