Socket
Socket
Sign inDemoInstall

css-loader

Package Overview
Dependencies
111
Maintainers
3
Versions
151
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 7.0.0 to 7.1.0

16

dist/index.js

@@ -174,3 +174,19 @@ "use strict";

const exportCode = (0, _utils.getExportCode)(exports, replacements, needToUseIcssPlugin, options, isTemplateLiteralSupported);
const {
getJSON
} = options.modules;
if (typeof getJSON === "function") {
try {
await getJSON({
resourcePath,
imports,
exports,
replacements
});
} catch (error) {
callback(error);
return;
}
}
callback(null, `${importCode}${moduleCode}${exportCode}`);
}

@@ -176,2 +176,7 @@ {

"type": "boolean"
},
"getJSON": {
"description": "Allows outputting of CSS modules mapping through a callback.",
"link": "https://github.com/webpack-contrib/css-loader#getJSON",
"instanceof": "Function"
}

@@ -178,0 +183,0 @@ }

4

package.json
{
"name": "css-loader",
"version": "7.0.0",
"version": "7.1.0",
"description": "css loader module for webpack",

@@ -39,3 +39,3 @@ "license": "MIT",

"test": "npm run test:coverage",
"prepare": "husky install && npm run build",
"prepare": "husky && npm run build",
"release": "standard-version"

@@ -42,0 +42,0 @@ },

@@ -50,3 +50,3 @@ <div align="center">

```js
import css from "file.css";
import * as css from "file.css";
```

@@ -331,2 +331,13 @@

exportOnlyLocals: boolean;
getJSON: ({
resourcePath,
imports,
exports,
replacements,
}: {
resourcePath: string;
imports: object[];
exports: object[];
replacements: object[];
}) => Promise<void> | void;
};

@@ -609,2 +620,3 @@ ```

exportOnlyLocals: false,
getJSON: ({ resourcePath, imports, exports, replacements }) => {},
},

@@ -1168,7 +1180,7 @@ },

// If using `exportLocalsConvention: "as-is"` (default value):
console.log(styles["foo-baz"], styles.bar);
// If using `exportLocalsConvention: "camel-case-only"`:
console.log(styles.fooBaz, styles.bar);
// If using `exportLocalsConvention: "as-is"`:
console.log(styles["foo-baz"], styles.bar);
```

@@ -1391,2 +1403,248 @@

##### `getJSON`
Type:
```ts
type getJSON = ({
resourcePath,
imports,
exports,
replacements,
}: {
resourcePath: string;
imports: object[];
exports: object[];
replacements: object[];
}) => Promise<void> | void;
```
Default: `undefined`
Enables a callback to output the CSS modules mapping JSON. The callback is invoked with an object containing the following:
- `resourcePath`: the absolute path of the original resource, e.g., `/foo/bar/baz.module.css`
- `imports`: an array of import objects with data about import types and file paths, e.g.,
```json
[
{
"type": "icss_import",
"importName": "___CSS_LOADER_ICSS_IMPORT_0___",
"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\"",
"icss": true,
"index": 0
}
]
```
(Note that this will include all imports, not just those relevant to CSS modules.)
- `exports`: an array of export objects with exported names and values, e.g.,
```json
[
{
"name": "main",
"value": "D2Oy"
}
]
```
- `replacements`: an array of import replacement objects used for linking `imports` and `exports`, e.g.,
```json
{
"replacementName": "___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___",
"importName": "___CSS_LOADER_ICSS_IMPORT_0___",
"localName": "main"
}
```
Using `getJSON`, it's possible to output a files with all CSS module mappings.
In the following example, we use `getJSON` to cache canonical mappings and
add stand-ins for any composed values (through `composes`), and we use a custom plugin
to consolidate the values and output them to a file:
**webpack.config.js**
```js
const path = require("path");
const fs = require("fs");
const CSS_LOADER_REPLACEMENT_REGEX =
/(___CSS_LOADER_ICSS_IMPORT_\d+_REPLACEMENT_\d+___)/g;
const REPLACEMENT_REGEX = /___REPLACEMENT\[(.*?)]\[(.*?)]___/g;
const IDENTIFIER_REGEX = /\[(.*?)]\[(.*?)]/;
const replacementsMap = {};
const canonicalValuesMap = {};
const allExportsJson = {};
function generateIdentifier(resourcePath, localName) {
return `[${resourcePath}][${localName}]`;
}
function addReplacements(resourcePath, imports, exportsJson, replacements) {
const importReplacementsMap = {};
// create a dict to quickly identify imports and get their absolute stand-in strings in the currently loaded file
// e.g., { '___CSS_LOADER_ICSS_IMPORT_0_REPLACEMENT_0___': '___REPLACEMENT[/foo/bar/baz.css][main]___' }
importReplacementsMap[resourcePath] = replacements.reduce(
(acc, { replacementName, importName, localName }) => {
const replacementImportUrl = imports.find(
(importData) => importData.importName === importName,
).url;
const relativePathRe = /.*!(.*)"/;
const [, relativePath] = replacementImportUrl.match(relativePathRe);
const importPath = path.resolve(path.dirname(resourcePath), relativePath);
const identifier = generateIdentifier(importPath, localName);
return { ...acc, [replacementName]: `___REPLACEMENT${identifier}___` };
},
{},
);
// iterate through the raw exports and add stand-in variables
// ('___REPLACEMENT[<absolute_path>][<class_name>]___')
// to be replaced in the plugin below
for (const [localName, classNames] of Object.entries(exportsJson)) {
const identifier = generateIdentifier(resourcePath, localName);
if (CSS_LOADER_REPLACEMENT_REGEX.test(classNames)) {
// if there are any replacements needed in the concatenated class names,
// add them all to the replacements map to be replaced altogether later
replacementsMap[identifier] = classNames.replaceAll(
CSS_LOADER_REPLACEMENT_REGEX,
(_, replacementName) =>
importReplacementsMap[resourcePath][replacementName],
);
} else {
// otherwise, no class names need replacements so we can add them to
// canonical values map and all exports JSON verbatim
canonicalValuesMap[identifier] = classNames;
allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
allExportsJson[resourcePath][localName] = classNames;
}
}
}
function replaceReplacements(classNames) {
return classNames.replaceAll(
REPLACEMENT_REGEX,
(_, resourcePath, localName) => {
const identifier = generateIdentifier(resourcePath, localName);
if (identifier in canonicalValuesMap) {
return canonicalValuesMap[identifier];
}
// Recurse through other stand-in that may be imports
const canonicalValue = replaceReplacements(replacementsMap[identifier]);
canonicalValuesMap[identifier] = canonicalValue;
return canonicalValue;
},
);
}
function getJSON({ resourcePath, imports, exports, replacements }) {
const exportsJson = exports.reduce((acc, { name, value }) => {
return { ...acc, [name]: value };
}, {});
if (replacements.length > 0) {
// replacements present --> add stand-in values for absolute paths and local names,
// which will be resolved to their canonical values in the plugin below
addReplacements(resourcePath, imports, exportsJson, replacements);
} else {
// no replacements present --> add to canonicalValuesMap verbatim
// since all values here are canonical/don't need resolution
for (const [key, value] of Object.entries(exportsJson)) {
const id = `[${resourcePath}][${key}]`;
canonicalValuesMap[id] = value;
}
allExportsJson[resourcePath] = exportsJson;
}
}
class CssModulesJsonPlugin {
constructor(options) {
this.options = options;
}
// eslint-disable-next-line class-methods-use-this
apply(compiler) {
compiler.hooks.emit.tap("CssModulesJsonPlugin", () => {
for (const [identifier, classNames] of Object.entries(replacementsMap)) {
const adjustedClassNames = replaceReplacements(classNames);
replacementsMap[identifier] = adjustedClassNames;
const [, resourcePath, localName] = identifier.match(IDENTIFIER_REGEX);
allExportsJson[resourcePath] = allExportsJson[resourcePath] || {};
allExportsJson[resourcePath][localName] = adjustedClassNames;
}
fs.writeFileSync(
this.options.filepath,
JSON.stringify(
// Make path to be relative to `context` (your project root)
Object.fromEntries(
Object.entries(allExportsJson).map((key) => {
key[0] = path
.relative(compiler.context, key[0])
.replace(/\\/g, "/");
return key;
}),
),
null,
2,
),
"utf8",
);
});
}
}
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: "css-loader",
options: { modules: { getJSON } },
},
],
},
plugins: [
new CssModulesJsonPlugin({
filepath: path.resolve(__dirname, "./output.css.json"),
}),
],
};
```
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`:
```json
{
"foo/bar/baz.module.css": {
"main": "D2Oy",
"header": "thNN"
},
"foot/bear/bath.module.css": {
"logo": "sqiR",
"info": "XMyI"
}
}
```
This is saved to a local file named `output.css.json`.
### `importLoaders`

@@ -2041,4 +2299,4 @@

```jsx
import svars from "variables.scss";
import styles from "Component.module.scss";
import * as svars from "variables.scss";
import * as styles from "Component.module.scss";

@@ -2045,0 +2303,0 @@ // Render DOM with CSS modules class name

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc