css-loader 7.0.0 → 7.1.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/README.md +270 -6
- package/dist/index.js +16 -0
- package/dist/options.json +5 -0
- package/dist/utils.js +4 -1
- 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
|
},
|
|
@@ -1144,7 +1156,7 @@ Enables/disables ES modules named export for locals.
|
|
|
1144
1156
|
|
|
1145
1157
|
> **Warning**
|
|
1146
1158
|
>
|
|
1147
|
-
>
|
|
1159
|
+
> Because it is not allowed to use the `default` class in CSS when the `namedExport` is `true` (since ECMA modules have a reserved keyword `default` for default export), it will be automatically renamed to the `_default` class.
|
|
1148
1160
|
|
|
1149
1161
|
**styles.css**
|
|
1150
1162
|
|
|
@@ -1155,6 +1167,9 @@ Enables/disables ES modules named export for locals.
|
|
|
1155
1167
|
.bar {
|
|
1156
1168
|
color: blue;
|
|
1157
1169
|
}
|
|
1170
|
+
.default {
|
|
1171
|
+
color: green;
|
|
1172
|
+
}
|
|
1158
1173
|
```
|
|
1159
1174
|
|
|
1160
1175
|
**index.js**
|
|
@@ -1162,11 +1177,14 @@ Enables/disables ES modules named export for locals.
|
|
|
1162
1177
|
```js
|
|
1163
1178
|
import * as styles from "./styles.css";
|
|
1164
1179
|
|
|
1180
|
+
// If using `exportLocalsConvention: "as-is"` (default value):
|
|
1181
|
+
console.log(styles["foo-baz"], styles.bar);
|
|
1182
|
+
|
|
1165
1183
|
// If using `exportLocalsConvention: "camel-case-only"`:
|
|
1166
1184
|
console.log(styles.fooBaz, styles.bar);
|
|
1167
1185
|
|
|
1168
|
-
//
|
|
1169
|
-
console.log(styles["
|
|
1186
|
+
// For the `default` classname
|
|
1187
|
+
console.log(styles["_default"]);
|
|
1170
1188
|
```
|
|
1171
1189
|
|
|
1172
1190
|
You can enable a ES module named export using:
|
|
@@ -1384,6 +1402,252 @@ module.exports = {
|
|
|
1384
1402
|
};
|
|
1385
1403
|
```
|
|
1386
1404
|
|
|
1405
|
+
##### `getJSON`
|
|
1406
|
+
|
|
1407
|
+
Type:
|
|
1408
|
+
|
|
1409
|
+
```ts
|
|
1410
|
+
type getJSON = ({
|
|
1411
|
+
resourcePath,
|
|
1412
|
+
imports,
|
|
1413
|
+
exports,
|
|
1414
|
+
replacements,
|
|
1415
|
+
}: {
|
|
1416
|
+
resourcePath: string;
|
|
1417
|
+
imports: object[];
|
|
1418
|
+
exports: object[];
|
|
1419
|
+
replacements: object[];
|
|
1420
|
+
}) => Promise<void> | void;
|
|
1421
|
+
```
|
|
1422
|
+
|
|
1423
|
+
Default: `undefined`
|
|
1424
|
+
|
|
1425
|
+
Enables a callback to output the CSS modules mapping JSON. The callback is invoked with an object containing the following:
|
|
1426
|
+
|
|
1427
|
+
- `resourcePath`: the absolute path of the original resource, e.g., `/foo/bar/baz.module.css`
|
|
1428
|
+
|
|
1429
|
+
- `imports`: an array of import objects with data about import types and file paths, e.g.,
|
|
1430
|
+
|
|
1431
|
+
```json
|
|
1432
|
+
[
|
|
1433
|
+
{
|
|
1434
|
+
"type": "icss_import",
|
|
1435
|
+
"importName": "___CSS_LOADER_ICSS_IMPORT_0___",
|
|
1436
|
+
"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\"",
|
|
1437
|
+
"icss": true,
|
|
1438
|
+
"index": 0
|
|
1439
|
+
}
|
|
1440
|
+
]
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
(Note that this will include all imports, not just those relevant to CSS modules.)
|
|
1444
|
+
|
|
1445
|
+
- `exports`: an array of export objects with exported names and values, e.g.,
|
|
1446
|
+
|
|
1447
|
+
```json
|
|
1448
|
+
[
|
|
1449
|
+
{
|
|
1450
|
+
"name": "main",
|
|
1451
|
+
"value": "D2Oy"
|
|
1452
|
+
}
|
|
1453
|
+
]
|
|
1454
|
+
```
|
|
1455
|
+
|
|
1456
|
+
- `replacements`: an array of import replacement objects used for linking `imports` and `exports`, e.g.,
|
|
1457
|
+
|
|
1458
|
+
```json
|
|
1459
|
+
{
|
|
1460
|
+
"replacementName": "___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___",
|
|
1461
|
+
"importName": "___CSS_LOADER_ICSS_IMPORT_0___",
|
|
1462
|
+
"localName": "main"
|
|
1463
|
+
}
|
|
1464
|
+
```
|
|
1465
|
+
|
|
1466
|
+
Using `getJSON`, it's possible to output a files with all CSS module mappings.
|
|
1467
|
+
In the following example, we use `getJSON` to cache canonical mappings and
|
|
1468
|
+
add stand-ins for any composed values (through `composes`), and we use a custom plugin
|
|
1469
|
+
to consolidate the values and output them to a file:
|
|
1470
|
+
|
|
1471
|
+
**webpack.config.js**
|
|
1472
|
+
|
|
1473
|
+
```js
|
|
1474
|
+
const path = require("path");
|
|
1475
|
+
const fs = require("fs");
|
|
1476
|
+
|
|
1477
|
+
const CSS_LOADER_REPLACEMENT_REGEX =
|
|
1478
|
+
/(___CSS_LOADER_ICSS_IMPORT_\d+_REPLACEMENT_\d+___)/g;
|
|
1479
|
+
const REPLACEMENT_REGEX = /___REPLACEMENT\[(.*?)]\[(.*?)]___/g;
|
|
1480
|
+
const IDENTIFIER_REGEX = /\[(.*?)]\[(.*?)]/;
|
|
1481
|
+
const replacementsMap = {};
|
|
1482
|
+
const canonicalValuesMap = {};
|
|
1483
|
+
const allExportsJson = {};
|
|
1484
|
+
|
|
1485
|
+
function generateIdentifier(resourcePath, localName) {
|
|
1486
|
+
return `[${resourcePath}][${localName}]`;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
function addReplacements(resourcePath, imports, exportsJson, replacements) {
|
|
1490
|
+
const importReplacementsMap = {};
|
|
1491
|
+
|
|
1492
|
+
// create a dict to quickly identify imports and get their absolute stand-in strings in the currently loaded file
|
|
1493
|
+
// e.g., { '___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___': '___REPLACEMENT[/foo/bar/baz.css][main]___' }
|
|
1494
|
+
importReplacementsMap[resourcePath] = replacements.reduce(
|
|
1495
|
+
(acc, { replacementName, importName, localName }) => {
|
|
1496
|
+
const replacementImportUrl = imports.find(
|
|
1497
|
+
(importData) => importData.importName === importName,
|
|
1498
|
+
).url;
|
|
1499
|
+
const relativePathRe = /.*!(.*)"/;
|
|
1500
|
+
const [, relativePath] = replacementImportUrl.match(relativePathRe);
|
|
1501
|
+
const importPath = path.resolve(path.dirname(resourcePath), relativePath);
|
|
1502
|
+
const identifier = generateIdentifier(importPath, localName);
|
|
1503
|
+
return { ...acc, [replacementName]: `___REPLACEMENT${identifier}___` };
|
|
1504
|
+
},
|
|
1505
|
+
{},
|
|
1506
|
+
);
|
|
1507
|
+
|
|
1508
|
+
// iterate through the raw exports and add stand-in variables
|
|
1509
|
+
// ('___REPLACEMENT[<absolute_path>][<class_name>]___')
|
|
1510
|
+
// to be replaced in the plugin below
|
|
1511
|
+
for (const [localName, classNames] of Object.entries(exportsJson)) {
|
|
1512
|
+
const identifier = generateIdentifier(resourcePath, localName);
|
|
1513
|
+
|
|
1514
|
+
if (CSS_LOADER_REPLACEMENT_REGEX.test(classNames)) {
|
|
1515
|
+
// if there are any replacements needed in the concatenated class names,
|
|
1516
|
+
// add them all to the replacements map to be replaced altogether later
|
|
1517
|
+
replacementsMap[identifier] = classNames.replaceAll(
|
|
1518
|
+
CSS_LOADER_REPLACEMENT_REGEX,
|
|
1519
|
+
(_, replacementName) =>
|
|
1520
|
+
importReplacementsMap[resourcePath][replacementName],
|
|
1521
|
+
);
|
|
1522
|
+
} else {
|
|
1523
|
+
// otherwise, no class names need replacements so we can add them to
|
|
1524
|
+
// canonical values map and all exports JSON verbatim
|
|
1525
|
+
canonicalValuesMap[identifier] = classNames;
|
|
1526
|
+
|
|
1527
|
+
allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
|
|
1528
|
+
allExportsJson[resourcePath][localName] = classNames;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function replaceReplacements(classNames) {
|
|
1534
|
+
return classNames.replaceAll(
|
|
1535
|
+
REPLACEMENT_REGEX,
|
|
1536
|
+
(_, resourcePath, localName) => {
|
|
1537
|
+
const identifier = generateIdentifier(resourcePath, localName);
|
|
1538
|
+
|
|
1539
|
+
if (identifier in canonicalValuesMap) {
|
|
1540
|
+
return canonicalValuesMap[identifier];
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// Recurse through other stand-in that may be imports
|
|
1544
|
+
const canonicalValue = replaceReplacements(replacementsMap[identifier]);
|
|
1545
|
+
|
|
1546
|
+
canonicalValuesMap[identifier] = canonicalValue;
|
|
1547
|
+
|
|
1548
|
+
return canonicalValue;
|
|
1549
|
+
},
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
function getJSON({ resourcePath, imports, exports, replacements }) {
|
|
1554
|
+
const exportsJson = exports.reduce((acc, { name, value }) => {
|
|
1555
|
+
return { ...acc, [name]: value };
|
|
1556
|
+
}, {});
|
|
1557
|
+
|
|
1558
|
+
if (replacements.length > 0) {
|
|
1559
|
+
// replacements present --> add stand-in values for absolute paths and local names,
|
|
1560
|
+
// which will be resolved to their canonical values in the plugin below
|
|
1561
|
+
addReplacements(resourcePath, imports, exportsJson, replacements);
|
|
1562
|
+
} else {
|
|
1563
|
+
// no replacements present --> add to canonicalValuesMap verbatim
|
|
1564
|
+
// since all values here are canonical/don't need resolution
|
|
1565
|
+
for (const [key, value] of Object.entries(exportsJson)) {
|
|
1566
|
+
const id = `[${resourcePath}][${key}]`;
|
|
1567
|
+
|
|
1568
|
+
canonicalValuesMap[id] = value;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
allExportsJson[resourcePath] = exportsJson;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
class CssModulesJsonPlugin {
|
|
1576
|
+
constructor(options) {
|
|
1577
|
+
this.options = options;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// eslint-disable-next-line class-methods-use-this
|
|
1581
|
+
apply(compiler) {
|
|
1582
|
+
compiler.hooks.emit.tap("CssModulesJsonPlugin", () => {
|
|
1583
|
+
for (const [identifier, classNames] of Object.entries(replacementsMap)) {
|
|
1584
|
+
const adjustedClassNames = replaceReplacements(classNames);
|
|
1585
|
+
|
|
1586
|
+
replacementsMap[identifier] = adjustedClassNames;
|
|
1587
|
+
|
|
1588
|
+
const [, resourcePath, localName] = identifier.match(IDENTIFIER_REGEX);
|
|
1589
|
+
|
|
1590
|
+
allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
|
|
1591
|
+
allExportsJson[resourcePath][localName] = adjustedClassNames;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
fs.writeFileSync(
|
|
1595
|
+
this.options.filepath,
|
|
1596
|
+
JSON.stringify(
|
|
1597
|
+
// Make path to be relative to `context` (your project root)
|
|
1598
|
+
Object.fromEntries(
|
|
1599
|
+
Object.entries(allExportsJson).map((key) => {
|
|
1600
|
+
key[0] = path
|
|
1601
|
+
.relative(compiler.context, key[0])
|
|
1602
|
+
.replace(/\\/g, "/");
|
|
1603
|
+
|
|
1604
|
+
return key;
|
|
1605
|
+
}),
|
|
1606
|
+
),
|
|
1607
|
+
null,
|
|
1608
|
+
2,
|
|
1609
|
+
),
|
|
1610
|
+
"utf8",
|
|
1611
|
+
);
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
module.exports = {
|
|
1617
|
+
module: {
|
|
1618
|
+
rules: [
|
|
1619
|
+
{
|
|
1620
|
+
test: /\.css$/i,
|
|
1621
|
+
loader: "css-loader",
|
|
1622
|
+
options: { modules: { getJSON } },
|
|
1623
|
+
},
|
|
1624
|
+
],
|
|
1625
|
+
},
|
|
1626
|
+
plugins: [
|
|
1627
|
+
new CssModulesJsonPlugin({
|
|
1628
|
+
filepath: path.resolve(__dirname, "./output.css.json"),
|
|
1629
|
+
}),
|
|
1630
|
+
],
|
|
1631
|
+
};
|
|
1632
|
+
```
|
|
1633
|
+
|
|
1634
|
+
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`:
|
|
1635
|
+
|
|
1636
|
+
```json
|
|
1637
|
+
{
|
|
1638
|
+
"foo/bar/baz.module.css": {
|
|
1639
|
+
"main": "D2Oy",
|
|
1640
|
+
"header": "thNN"
|
|
1641
|
+
},
|
|
1642
|
+
"foot/bear/bath.module.css": {
|
|
1643
|
+
"logo": "sqiR",
|
|
1644
|
+
"info": "XMyI"
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
```
|
|
1648
|
+
|
|
1649
|
+
This is saved to a local file named `output.css.json`.
|
|
1650
|
+
|
|
1387
1651
|
### `importLoaders`
|
|
1388
1652
|
|
|
1389
1653
|
Type:
|
|
@@ -2033,8 +2297,8 @@ File treated as `CSS Module`.
|
|
|
2033
2297
|
Using both `CSS Module` functionality as well as SCSS variables directly in JavaScript.
|
|
2034
2298
|
|
|
2035
2299
|
```jsx
|
|
2036
|
-
import svars from "variables.scss";
|
|
2037
|
-
import styles from "Component.module.scss";
|
|
2300
|
+
import * as svars from "variables.scss";
|
|
2301
|
+
import * as styles from "Component.module.scss";
|
|
2038
2302
|
|
|
2039
2303
|
// Render DOM with CSS modules class name
|
|
2040
2304
|
// <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/dist/utils.js
CHANGED
|
@@ -845,9 +845,12 @@ function getExportCode(exports, replacements, icssPluginUsed, options, isTemplat
|
|
|
845
845
|
let identifierId = 0;
|
|
846
846
|
const addExportToLocalsCode = (names, value) => {
|
|
847
847
|
const normalizedNames = Array.isArray(names) ? new Set(names) : new Set([names]);
|
|
848
|
-
for (
|
|
848
|
+
for (let name of normalizedNames) {
|
|
849
849
|
const serializedValue = isTemplateLiteralSupported ? convertToTemplateLiteral(value) : JSON.stringify(value);
|
|
850
850
|
if (options.modules.namedExport) {
|
|
851
|
+
if (name === "default") {
|
|
852
|
+
name = `_${name}`;
|
|
853
|
+
}
|
|
851
854
|
if (!validIdentifier.test(name) || keywords.has(name)) {
|
|
852
855
|
identifierId += 1;
|
|
853
856
|
const id = `_${identifierId.toString(16)}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "css-loader",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.1",
|
|
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": [
|