From 70550bcf256e09df6da8342e241ee997b056546c Mon Sep 17 00:00:00 2001
From: Rohit Rajendran
Date: Fri, 15 Mar 2019 17:22:10 -0400
Subject: [PATCH 01/13] Update hotmodule reloading webpack links (#241)
The links to webpack's documents on hot module reloading was out of date
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index a1bca75..543bbb9 100644
--- a/README.md
+++ b/README.md
@@ -474,17 +474,17 @@ This behaviour is enabled by default in `babel-plugin-react-css-modules`.
### How to live reload the CSS?
-`babel-plugin-react-css-modules` utilises webpack [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement.html) (HMR) to live reload the CSS.
+`babel-plugin-react-css-modules` utilises webpack [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/#root) (HMR) to live reload the CSS.
To enable live reloading of the CSS:
* Enable [`webpackHotModuleReloading`](#configuration) `babel-plugin-react-css-modules` configuration.
-* Configure `webpack` to use HMR. Use [`--hot`](https://webpack.github.io/docs/webpack-dev-server.html) option if you are using `webpack-dev-server`.
+* Configure `webpack` to use HMR. Use [`--hot`](https://webpack.js.org/configuration/dev-server/#root) option if you are using `webpack-dev-server`.
* Use [`style-loader`](https://github.com/webpack/style-loader) to load the style sheets.
> Note:
>
-> This enables live reloading of the CSS. To enable HMR of the React components, refer to the [Hot Module Replacement - React](https://webpack.js.org/guides/hmr-react/) guide.
+> This enables live reloading of the CSS. To enable HMR of the React components, refer to the [Hot Module Replacement - React](https://webpack.js.org/guides/hot-module-replacement/#other-code-and-frameworks) guide.
> Note:
>
From 05c268317e97046a915c94ff28d8ab1a63ff77cb Mon Sep 17 00:00:00 2001
From: Albert Lucianto
Date: Thu, 21 Mar 2019 19:27:00 +0800
Subject: [PATCH 02/13] fix: handle spread (#243)
* fix: handle spread
* test: handle spread
* test: add test case for spread
* spread: remove keys exclusion, avoid falsy values
* refactor: handle spread separated in another file
---
src/createSpreadMapper.js | 73 +++++++++++++++++++
src/handleSpreadClassName.js | 53 ++++++++++++++
src/index.js | 12 +++
.../output.js | 2 +-
.../handle spread attributes/foo.css | 1 +
.../handle spread attributes/input.js | 22 ++++++
.../handle spread attributes/options.json | 13 ++++
.../handle spread attributes/output.js | 16 ++++
8 files changed, 191 insertions(+), 1 deletion(-)
create mode 100644 src/createSpreadMapper.js
create mode 100644 src/handleSpreadClassName.js
create mode 100644 test/fixtures/react-css-modules/handle spread attributes/foo.css
create mode 100644 test/fixtures/react-css-modules/handle spread attributes/input.js
create mode 100644 test/fixtures/react-css-modules/handle spread attributes/options.json
create mode 100644 test/fixtures/react-css-modules/handle spread attributes/output.js
diff --git a/src/createSpreadMapper.js b/src/createSpreadMapper.js
new file mode 100644
index 0000000..7b99cf5
--- /dev/null
+++ b/src/createSpreadMapper.js
@@ -0,0 +1,73 @@
+// @flow
+
+import {
+ Expression,
+ memberExpression,
+ binaryExpression,
+ stringLiteral,
+ logicalExpression,
+ identifier
+} from '@babel/types';
+import optionsDefaults from './schemas/optionsDefaults';
+
+const createSpreadMapper = (path: *, stats: *): { [destinationName: string]: Expression } => {
+ const result = {};
+
+ let {attributeNames} = optionsDefaults;
+
+ if (stats.opts && stats.opts.attributeNames) {
+ attributeNames = Object.assign({}, attributeNames, stats.opts.attributeNames);
+ }
+
+ const attributes = Object
+ .entries(attributeNames)
+ .filter((pair) => {
+ return pair[1];
+ });
+
+ const attributeKeys = attributes.map((pair) => {
+ return pair[0];
+ });
+
+ path.traverse({
+ JSXSpreadAttribute (spreadPath: *) {
+ const spread = spreadPath.node;
+
+ for (const attributeKey of attributeKeys) {
+ const destinationName = attributeNames[attributeKey];
+
+ if (result[destinationName]) {
+ result[destinationName] = binaryExpression(
+ '+',
+ result[destinationName],
+ binaryExpression(
+ '+',
+ stringLiteral(' '),
+ logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ )
+ ),
+ );
+ } else {
+ result[destinationName] = logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ );
+ }
+ }
+ }
+ });
+
+ return result;
+};
+
+export default createSpreadMapper;
diff --git a/src/handleSpreadClassName.js b/src/handleSpreadClassName.js
new file mode 100644
index 0000000..62ea482
--- /dev/null
+++ b/src/handleSpreadClassName.js
@@ -0,0 +1,53 @@
+// @flow
+
+import {
+ Expression,
+ isStringLiteral,
+ isJSXExpressionContainer,
+ jsxExpressionContainer,
+ binaryExpression,
+ stringLiteral
+} from '@babel/types';
+
+const handleSpreadClassName = (
+ path: *,
+ destinationName: string,
+ classNamesFromSpread: Expression
+) => {
+ const destinationAttribute = path.node.openingElement.attributes
+ .find((attribute) => {
+ return typeof attribute.name !== 'undefined' && attribute.name.name === destinationName;
+ });
+
+ if (!destinationAttribute) {
+ return;
+ }
+
+ if (isStringLiteral(destinationAttribute.value)) {
+ destinationAttribute.value = jsxExpressionContainer(
+ binaryExpression(
+ '+',
+ destinationAttribute.value,
+ binaryExpression(
+ '+',
+ stringLiteral(' '),
+ classNamesFromSpread,
+ )
+ )
+ );
+ } else if (isJSXExpressionContainer(destinationAttribute.value)) {
+ destinationAttribute.value = jsxExpressionContainer(
+ binaryExpression(
+ '+',
+ destinationAttribute.value.expression,
+ binaryExpression(
+ '+',
+ stringLiteral(' '),
+ classNamesFromSpread
+ )
+ )
+ );
+ }
+};
+
+export default handleSpreadClassName;
diff --git a/src/index.js b/src/index.js
index 5c728f7..305d941 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,6 +15,8 @@ import requireCssModule from './requireCssModule';
import resolveStringLiteral from './resolveStringLiteral';
import replaceJsxExpressionContainer from './replaceJsxExpressionContainer';
import attributeNameExists from './attributeNameExists';
+import createSpreadMapper from './createSpreadMapper';
+import handleSpreadClassName from './handleSpreadClassName';
const ajv = new Ajv({
// eslint-disable-next-line id-match
@@ -216,6 +218,8 @@ export default ({
autoResolveMultipleImports = optionsDefaults.autoResolveMultipleImports
} = stats.opts || {};
+ const spreadMap = createSpreadMapper(path, stats);
+
for (const attribute of attributes) {
const destinationName = attributeNames[attribute.name.name];
@@ -246,6 +250,14 @@ export default ({
options
);
}
+
+ if (spreadMap[destinationName]) {
+ handleSpreadClassName(
+ path,
+ destinationName,
+ spreadMap[destinationName]
+ );
+ }
}
},
Program (path: *, stats: *): void {
diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
index 7613724..c2084e1 100644
--- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
+++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
@@ -5,4 +5,4 @@ require("./bar.css");
const props = {
foo: 'bar'
};
-;
+;
diff --git a/test/fixtures/react-css-modules/handle spread attributes/foo.css b/test/fixtures/react-css-modules/handle spread attributes/foo.css
new file mode 100644
index 0000000..40ebb53
--- /dev/null
+++ b/test/fixtures/react-css-modules/handle spread attributes/foo.css
@@ -0,0 +1 @@
+.a {}
\ No newline at end of file
diff --git a/test/fixtures/react-css-modules/handle spread attributes/input.js b/test/fixtures/react-css-modules/handle spread attributes/input.js
new file mode 100644
index 0000000..efb4b6d
--- /dev/null
+++ b/test/fixtures/react-css-modules/handle spread attributes/input.js
@@ -0,0 +1,22 @@
+import './foo.css';
+
+const rest = {};
+
+;
+
+;
+
+;
+
+;
+
+// Should be okay if rest is put on last
+;
+
+const rest2 = {};
+
+;
+
+// Should not do anything
+;
+;
diff --git a/test/fixtures/react-css-modules/handle spread attributes/options.json b/test/fixtures/react-css-modules/handle spread attributes/options.json
new file mode 100644
index 0000000..93a418e
--- /dev/null
+++ b/test/fixtures/react-css-modules/handle spread attributes/options.json
@@ -0,0 +1,13 @@
+{
+ "plugins": [
+ [
+ "../../../../src",
+ {
+ "generateScopedName": "[name]__[local]",
+ "attributeNames": {
+ "activeStyleName": "activeClassName"
+ }
+ }
+ ]
+ ]
+}
diff --git a/test/fixtures/react-css-modules/handle spread attributes/output.js b/test/fixtures/react-css-modules/handle spread attributes/output.js
new file mode 100644
index 0000000..49609e0
--- /dev/null
+++ b/test/fixtures/react-css-modules/handle spread attributes/output.js
@@ -0,0 +1,16 @@
+"use strict";
+
+require("./foo.css");
+
+const rest = {};
+;
+;
+;
+; // Should be okay if rest is put on last
+
+;
+const rest2 = {};
+; // Should not do anything
+
+;
+;
From 4a47f35e2e887bb935d0602cf1425fbc87719ae1 Mon Sep 17 00:00:00 2001
From: Albert Lucianto
Date: Fri, 22 Mar 2019 15:38:27 +0800
Subject: [PATCH 03/13] fix: spread should not traverse children elements
(#245)
---
src/createSpreadMapper.js | 68 ++++++++++---------
.../handle spread attributes/input.js | 4 ++
.../handle spread attributes/output.js | 3 +
3 files changed, 42 insertions(+), 33 deletions(-)
diff --git a/src/createSpreadMapper.js b/src/createSpreadMapper.js
index 7b99cf5..81d3cb6 100644
--- a/src/createSpreadMapper.js
+++ b/src/createSpreadMapper.js
@@ -6,7 +6,8 @@ import {
binaryExpression,
stringLiteral,
logicalExpression,
- identifier
+ identifier,
+ isJSXSpreadAttribute
} from '@babel/types';
import optionsDefaults from './schemas/optionsDefaults';
@@ -29,43 +30,44 @@ const createSpreadMapper = (path: *, stats: *): { [destinationName: string]: Exp
return pair[0];
});
- path.traverse({
- JSXSpreadAttribute (spreadPath: *) {
- const spread = spreadPath.node;
+ const spreadAttributes = path.node.openingElement.attributes
+ .filter((attr) => {
+ return isJSXSpreadAttribute(attr);
+ });
- for (const attributeKey of attributeKeys) {
- const destinationName = attributeNames[attributeKey];
+ for (const spread of spreadAttributes) {
+ for (const attributeKey of attributeKeys) {
+ const destinationName = attributeNames[attributeKey];
- if (result[destinationName]) {
- result[destinationName] = binaryExpression(
+ if (result[destinationName]) {
+ result[destinationName] = binaryExpression(
+ '+',
+ result[destinationName],
+ binaryExpression(
'+',
- result[destinationName],
- binaryExpression(
- '+',
- stringLiteral(' '),
- logicalExpression(
- '||',
- memberExpression(
- spread.argument,
- identifier(destinationName),
- ),
- stringLiteral('')
- )
- ),
- );
- } else {
- result[destinationName] = logicalExpression(
- '||',
- memberExpression(
- spread.argument,
- identifier(destinationName),
- ),
- stringLiteral('')
- );
- }
+ stringLiteral(' '),
+ logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ )
+ ),
+ );
+ } else {
+ result[destinationName] = logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ );
}
}
- });
+ }
return result;
};
diff --git a/test/fixtures/react-css-modules/handle spread attributes/input.js b/test/fixtures/react-css-modules/handle spread attributes/input.js
index efb4b6d..8e09b6d 100644
--- a/test/fixtures/react-css-modules/handle spread attributes/input.js
+++ b/test/fixtures/react-css-modules/handle spread attributes/input.js
@@ -20,3 +20,7 @@ const rest2 = {};
// Should not do anything
;
;
+
+
diff --git a/test/fixtures/react-css-modules/handle spread attributes/output.js b/test/fixtures/react-css-modules/handle spread attributes/output.js
index 49609e0..59ec5c2 100644
--- a/test/fixtures/react-css-modules/handle spread attributes/output.js
+++ b/test/fixtures/react-css-modules/handle spread attributes/output.js
@@ -14,3 +14,6 @@ const rest2 = {};
;
;
+;
From f11d423ae43f2eb57f603bd13cef7f58f0216a07 Mon Sep 17 00:00:00 2001
From: George Pittarelli
Date: Fri, 29 Mar 2019 18:31:27 -0400
Subject: [PATCH 04/13] fix: don't break when spreading falsy value (#249)
---
src/createSpreadMapper.js | 43 +++++++++++--------
.../output.js | 2 +-
.../handle spread attributes/output.js | 14 +++---
3 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/src/createSpreadMapper.js b/src/createSpreadMapper.js
index 81d3cb6..176fb0a 100644
--- a/src/createSpreadMapper.js
+++ b/src/createSpreadMapper.js
@@ -4,6 +4,7 @@ import {
Expression,
memberExpression,
binaryExpression,
+ conditionalExpression,
stringLiteral,
logicalExpression,
identifier,
@@ -43,25 +44,33 @@ const createSpreadMapper = (path: *, stats: *): { [destinationName: string]: Exp
result[destinationName] = binaryExpression(
'+',
result[destinationName],
- binaryExpression(
- '+',
- stringLiteral(' '),
- logicalExpression(
- '||',
- memberExpression(
- spread.argument,
- identifier(destinationName),
- ),
- stringLiteral('')
- )
- ),
+ conditionalExpression(
+ spread.argument,
+ binaryExpression(
+ '+',
+ stringLiteral(' '),
+ logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ )
+ ),
+ stringLiteral('')
+ )
);
} else {
- result[destinationName] = logicalExpression(
- '||',
- memberExpression(
- spread.argument,
- identifier(destinationName),
+ result[destinationName] = conditionalExpression(
+ spread.argument,
+ logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
),
stringLiteral('')
);
diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
index c2084e1..a325415 100644
--- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
+++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
@@ -5,4 +5,4 @@ require("./bar.css");
const props = {
foo: 'bar'
};
-;
+;
diff --git a/test/fixtures/react-css-modules/handle spread attributes/output.js b/test/fixtures/react-css-modules/handle spread attributes/output.js
index 59ec5c2..421a3f8 100644
--- a/test/fixtures/react-css-modules/handle spread attributes/output.js
+++ b/test/fixtures/react-css-modules/handle spread attributes/output.js
@@ -3,17 +3,17 @@
require("./foo.css");
const rest = {};
-;
-;
-;
-; // Should be okay if rest is put on last
+;
+;
+;
+; // Should be okay if rest is put on last
-;
+;
const rest2 = {};
-; // Should not do anything
+; // Should not do anything
;
;
;
From ff21df5e6cfdac94e5d3f82f4083ec257a3e9dea Mon Sep 17 00:00:00 2001
From: Gajus Kuizinas
Date: Thu, 9 May 2019 17:54:03 +0100
Subject: [PATCH 05/13] docs: add GitSpo mentions badge
---
README.md | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 543bbb9..df2123f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
# babel-plugin-react-css-modules
+](https://gitspo.com/badges/gajus/babel-plugin-react-css-modules?style=flat-square)
[](https://travis-ci.org/gajus/babel-plugin-react-css-modules)
[](https://www.npmjs.org/package/babel-plugin-react-css-modules)
[](https://github.com/gajus/canonical)
@@ -260,9 +261,9 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two
}
}
```
-
+
Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config
-
+
```json
"plugins": [
["postcss-import-sync2", {
@@ -270,9 +271,9 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two
}],
"postcss-nested"
]
- ```
-
-
+ ```
+
+
### Custom Attribute Mapping
You can set your own attribute mapping rules using the `attributeNames` option.
From 31c5626c8df718c101d65b2b60630116bd13323d Mon Sep 17 00:00:00 2001
From: Gajus Kuizinas
Date: Thu, 9 May 2019 17:59:33 +0100
Subject: [PATCH 06/13] fix: correct GitSpo badge markdown
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index df2123f..0fda1ce 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# babel-plugin-react-css-modules
-](https://gitspo.com/badges/gajus/babel-plugin-react-css-modules?style=flat-square)
+[](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules)
[](https://travis-ci.org/gajus/babel-plugin-react-css-modules)
[](https://www.npmjs.org/package/babel-plugin-react-css-modules)
[](https://github.com/gajus/canonical)
From d6fdc38b2f6a5855407fd25232f171b5085e1236 Mon Sep 17 00:00:00 2001
From: Gajus Kuizinas
Date: Sat, 11 May 2019 09:26:19 +0100
Subject: [PATCH 07/13] fix: update GitSpo badge URL
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0fda1ce..30a303c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# babel-plugin-react-css-modules
-[](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules)
+[](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules)
[](https://travis-ci.org/gajus/babel-plugin-react-css-modules)
[](https://www.npmjs.org/package/babel-plugin-react-css-modules)
[](https://github.com/gajus/canonical)
From 59e05a2150876276f6318ce9b8f59a36d610f250 Mon Sep 17 00:00:00 2001
From: Gajus Kuizinas
Date: Wed, 19 Jun 2019 10:12:38 +0200
Subject: [PATCH 08/13] Create FUNDING.yml
---
.github/FUNDING.yml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 .github/FUNDING.yml
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..2f093a7
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: gajus
+patreon: gajus
From e3636b39d6811aca7701d44f19cdf777a9260d71 Mon Sep 17 00:00:00 2001
From: Ben Ilegbodu
Date: Fri, 10 Jan 2020 18:54:12 -0800
Subject: [PATCH 09/13] Add error FAQs (#283)
---
README.md | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 30a303c..748a3fe 100644
--- a/README.md
+++ b/README.md
@@ -163,7 +163,7 @@ NODE_ENV=production ./test
## How does it work?
1. Builds index of all stylesheet imports per file (imports of files with `.css` or `.scss` extension).
-1. Uses [postcss](https://github.com/postcss/postcss) to parse the matching CSS files.
+1. Uses [postcss](https://github.com/postcss/postcss) to parse the matching CSS files into a lookup of CSS module references.
1. Iterates through all [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html) element declarations.
1. Parses the `styleName` attribute value into anonymous and named CSS module references.
1. Finds the CSS class name matching the CSS module reference:
@@ -239,7 +239,7 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two
npm install postcss-scss --save-dev
```
-2. Add a filetype syntax mapping to the Babel plugin configuration
+2. Add a `filetypes` syntax mapping to the Babel plugin configuration. For example for SCSS:
```json
"filetypes": {
@@ -249,7 +249,7 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two
}
```
- And optionaly specify extra plugins
+ And optionally specify extra plugins:
```json
"filetypes": {
@@ -262,7 +262,9 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two
}
```
- Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config
+ > NOTE: [`postcss-nested`](https://github.com/postcss/postcss-nested) is added as an extra plugin for demonstration purposes only. It's not needed with [`postcss-scss`](https://github.com/postcss/postcss-scss) because SCSS already supports nesting.
+
+ Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config:
```json
"plugins": [
@@ -490,3 +492,32 @@ To enable live reloading of the CSS:
> Note:
>
> This is a [webpack](https://webpack.github.io/) specific option. If you are using `babel-plugin-react-css-modules` in a different setup and require CSS live reloading, raise an issue describing your setup.
+
+### I get a "Cannot use styleName attribute for style name '`[X]`' without importing at least one stylesheet." error
+
+First, ensure that you are correctly importing the CSS file following the [conventions](#conventions).
+
+If you are correctly importing but using different CSS (such as SCSS), this is likely happening because your CSS file wasn't able to be successfully parsed. You need to [configure a syntax loader](#configurate-syntax-loaders).
+
+### I get a "Could not resolve the styleName '`[X]`' error but the class exists in the CSS included in the browser.
+
+First, verify that the CSS is being included in the browser. Remove from `styleName` the reference to the CSS class that's failing and view the page. Search through the `` tags that have been added to the `` and find the one related to your CSS module. Copy the code into your editor and search for the class name.
+
+Once you've verified that the class is being rendered in CSS, the likely cause is that the `babel-plugin-react-css-modules` is unable to find your CSS class in the parsed code. If you're using different CSS (such as SCSS), verify that you have [configured a syntax loader](#configurate-syntax-loaders).
+
+However, if you're using a syntaxes such as [`postcss-scss`](https://github.com/postcss/postcss-scss) or [`postcss-less`](https://github.com/webschik/postcss-less), they do not compile down to CSS. So if you are programmatically building a class name (see below), webpack will be able to generate the rendered CSS from SCSS/LESS, but `babel-plugin-react-css-modules` will not be able to parse the SCSS/LESS.
+
+A SCSS example:
+
+```scss
+$scales: 10, 20, 30, 40, 50;
+
+@each $scale in $scales {
+ .icon-#{$scale} {
+ width: $scale;
+ height: $scale;
+ }
+ }
+```
+
+`babel-plugin-react-css-modules` will not receive `icon-10` or `icon-50`, but `icon-#{$scale}`. That is why you receive the error that `styleName` `"icon-10"` cannot be found.
\ No newline at end of file
From 91c8e9b9b272e1d16c756f7e865fdbf94dec2075 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BE=90=E7=AB=9F=E4=B8=89?=
Date: Fri, 18 Sep 2020 00:11:30 +0800
Subject: [PATCH 10/13] Feat/add regexp support for filetype (#240)
* feat: use RegExp as including condition in filetype config
* test: add corresponding test cases.
* fix: do not use extension-style filrtype as RegExp pattern
* feat: modify the priority between RegExp pattern filetype and extension style filetype
* style: no continue
* style: for comment #2
Co-authored-by: super-cattle
---
src/conditionalClassMerge.js | 1 +
src/findMatchedFiletype.js | 25 +++++++++++++++++++
src/getClassName.js | 1 +
src/index.js | 12 ++++++---
src/requireCssModule.js | 6 ++---
src/resolveStringLiteral.js | 1 -
.../bar.less | 3 +++
.../bar.md.less | 3 +++
.../input.js | 3 +++
.../options.json | 15 +++++++++++
.../output.js | 5 ++++
.../bar.md.css | 1 +
.../foo.css | 1 +
.../input.js | 4 +++
.../options.json | 16 ++++++++++++
.../output.js | 9 +++++++
.../styles/base.css | 1 +
17 files changed, 99 insertions(+), 8 deletions(-)
create mode 100644 src/findMatchedFiletype.js
create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less
create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less
create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js
create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json
create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js
create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css
create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css
create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js
create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json
create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js
create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css
diff --git a/src/conditionalClassMerge.js b/src/conditionalClassMerge.js
index 617599c..cb7bbf5 100644
--- a/src/conditionalClassMerge.js
+++ b/src/conditionalClassMerge.js
@@ -12,6 +12,7 @@ export default (
classNameExpression: any,
styleNameExpression: any,
): any => {
+ // classNameExpression ? (classNameExpression + ' ') : '' + styleNameExpression
return binaryExpression(
'+',
conditionalExpression(
diff --git a/src/findMatchedFiletype.js b/src/findMatchedFiletype.js
new file mode 100644
index 0000000..b74a0b2
--- /dev/null
+++ b/src/findMatchedFiletype.js
@@ -0,0 +1,25 @@
+// @flow
+
+export default (sourceFilePath: string, filetypes: $ReadOnlyArray): ?string => {
+ // Try to match as the RegExp pattern
+ for (const pattern of filetypes) {
+ if (!pattern.match(/^\.[a-z0-9A-Z]+?$/)) {
+ if (sourceFilePath.match(new RegExp(pattern))) {
+ return pattern;
+ }
+ }
+ }
+
+ const extensionDotIndex = sourceFilePath.lastIndexOf('.');
+
+ if (extensionDotIndex > -1) {
+ const extension = sourceFilePath.substr(extensionDotIndex);
+ const index = filetypes.indexOf(extension);
+
+ if (index > -1) {
+ return filetypes[index];
+ }
+ }
+
+ return null;
+};
diff --git a/src/getClassName.js b/src/getClassName.js
index 1bf05fb..823ce16 100644
--- a/src/getClassName.js
+++ b/src/getClassName.js
@@ -120,6 +120,7 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM
return getClassNameFromMultipleImports(styleName, styleModuleImportMap, handleMissingStyleName);
}
+ // There is only one imported CSS module file.
const styleModuleMap: StyleModuleMapType = styleModuleImportMap[styleModuleImportMapKeys[0]];
if (!styleModuleMap[styleName]) {
diff --git a/src/index.js b/src/index.js
index 305d941..477026b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,6 +15,7 @@ import requireCssModule from './requireCssModule';
import resolveStringLiteral from './resolveStringLiteral';
import replaceJsxExpressionContainer from './replaceJsxExpressionContainer';
import attributeNameExists from './attributeNameExists';
+import findMatchedFiletype from './findMatchedFiletype';
import createSpreadMapper from './createSpreadMapper';
import handleSpreadClassName from './handleSpreadClassName';
@@ -130,12 +131,12 @@ export default ({
return filename.match(new RegExp(exclude));
};
+ // decide whether the import statement should be processed as CSS module
const notForPlugin = (path: *, stats: *) => {
stats.opts.filetypes = stats.opts.filetypes || {};
- const extension = path.node.source.value.lastIndexOf('.') > -1 ? path.node.source.value.substr(path.node.source.value.lastIndexOf('.')) : null;
-
- if (extension !== '.css' && Object.keys(stats.opts.filetypes).indexOf(extension) < 0) {
+ // @HACK
+ if (path.node.source.value.indexOf('babel-plugin-react-css-modules') === 0) {
return true;
}
@@ -145,7 +146,10 @@ export default ({
return true;
}
- return false;
+ const filetypeKeys = Object.keys(stats.opts.filetypes);
+ filetypeKeys.push('.css');
+
+ return !findMatchedFiletype(filename, filetypeKeys);
};
return {
diff --git a/src/requireCssModule.js b/src/requireCssModule.js
index 0268a43..d77c25a 100644
--- a/src/requireCssModule.js
+++ b/src/requireCssModule.js
@@ -18,6 +18,7 @@ import type {
GenerateScopedNameConfigurationType,
StyleModuleMapType
} from './types';
+import findMatchedFiletype from './findMatchedFiletype';
import optionsDefaults from './schemas/optionsDefaults';
type FiletypeOptionsType = {|
@@ -36,10 +37,9 @@ type OptionsType = {|
|};
const getFiletypeOptions = (cssSourceFilePath: string, filetypes: FiletypesConfigurationType): ?FiletypeOptionsType => {
- const extension = cssSourceFilePath.substr(cssSourceFilePath.lastIndexOf('.'));
- const filetype = filetypes ? filetypes[extension] : null;
+ const matchedKey = findMatchedFiletype(cssSourceFilePath, Object.keys(filetypes));
- return filetype;
+ return matchedKey ? filetypes && filetypes[matchedKey] : null;
};
// eslint-disable-next-line flowtype/no-weak-types
diff --git a/src/resolveStringLiteral.js b/src/resolveStringLiteral.js
index b1d4f32..f62e42a 100644
--- a/src/resolveStringLiteral.js
+++ b/src/resolveStringLiteral.js
@@ -41,7 +41,6 @@ export default (
} else {
throw new Error('Unexpected attribute value:' + destinationAttribute.value);
}
-
path.node.openingElement.attributes.splice(path.node.openingElement.attributes.indexOf(sourceAttribute), 1);
} else {
sourceAttribute.name.name = destinationName;
diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less
new file mode 100644
index 0000000..6586489
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less
@@ -0,0 +1,3 @@
+@color: #f00;
+
+.a {background-color: @color;}
diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less
new file mode 100644
index 0000000..6586489
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less
@@ -0,0 +1,3 @@
+@color: #f00;
+
+.a {background-color: @color;}
diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js
new file mode 100644
index 0000000..25d6c7d
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js
@@ -0,0 +1,3 @@
+import './bar.md.less';
+
+;
diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json
new file mode 100644
index 0000000..0e3777a
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json
@@ -0,0 +1,15 @@
+{
+ "plugins": [
+ [
+ "../../../../src",
+ {
+ "generateScopedName": "[name]__[local]",
+ "filetypes": {
+ "\\.md\\.less$": {
+ "syntax": "postcss-less"
+ }
+ }
+ }
+ ]
+ ]
+}
diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js
new file mode 100644
index 0000000..e77b991
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js
@@ -0,0 +1,5 @@
+"use strict";
+
+require("./bar.md.less");
+
+;
diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css
new file mode 100644
index 0000000..07a8534
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css
@@ -0,0 +1 @@
+.a {background-color: #f00;}
diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css
new file mode 100644
index 0000000..07a8534
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css
@@ -0,0 +1 @@
+.a {background-color: #f00;}
diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js
new file mode 100644
index 0000000..d00c4be
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js
@@ -0,0 +1,4 @@
+import barMd from './bar.md.css';
+import base from './styles/base.css';
+
+;
diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json
new file mode 100644
index 0000000..5adefe5
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json
@@ -0,0 +1,16 @@
+{
+ "plugins": [
+ [
+ "../../../../src",
+ {
+ "generateScopedName": "[name]__[local]",
+ "filetypes": {
+ "\\.md\\.less$": {
+ "syntax": "postcss-less"
+ },
+ "styles/.*?\\.css$": {}
+ }
+ }
+ ]
+ ]
+}
diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js
new file mode 100644
index 0000000..882cb0a
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js
@@ -0,0 +1,9 @@
+"use strict";
+
+var _barMd = _interopRequireDefault(require("./bar.md.css"));
+
+var _base = _interopRequireDefault(require("./styles/base.css"));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+;
diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css
new file mode 100644
index 0000000..f454509
--- /dev/null
+++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css
@@ -0,0 +1 @@
+.b {background-color: #0f0;}
\ No newline at end of file
From 6a2a894df6f08fa2ba968735aeedb07a70302a01 Mon Sep 17 00:00:00 2001
From: Anton A
Date: Tue, 20 Apr 2021 07:34:54 +0930
Subject: [PATCH 11/13] docs: link to webpack's localIdentName documentation in
the description of generateScopedName.
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 748a3fe..1af05a7 100644
--- a/README.md
+++ b/README.md
@@ -194,7 +194,7 @@ Configure the options for the plugin within your `.babelrc` as follows:
|`context`|`string`|Must match webpack [`context`](https://webpack.js.org/configuration/entry-context/#context) configuration. [`css-loader`](https://github.com/webpack/css-loader) inherits `context` values from webpack. Other CSS module implementations might use different context resolution logic.|`process.cwd()`|
|`exclude`|`string`|A RegExp that will exclude otherwise included files e.g., to exclude all styles from node_modules `exclude: 'node_modules'`|
|`filetypes`|`?FiletypesConfigurationType`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugarss, LESS and SCSS and extra plugins for them. ||
-|`generateScopedName`|`?GenerateScopedNameConfigurationType`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names). If you use this option, make sure it matches the value of `localIdentName` in webpack config. See this [issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/108#issuecomment-334351241) |`[path]___[name]__[local]___[hash:base64:5]`|
+|`generateScopedName`|`?GenerateScopedNameConfigurationType`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names). If you use this option, make sure it matches the value of `localIdentName` [in webpack config](https://webpack.js.org/loaders/css-loader/#localidentname). See this [issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/108#issuecomment-334351241) |`[path]___[name]__[local]___[hash:base64:5]`|
|`removeImport`|`boolean`|Remove the matching style import. This option is used to enable server-side rendering.|`false`|
|`webpackHotModuleReloading`|`boolean`|Enables hot reloading of CSS in webpack|`false`|
|`handleMissingStyleName`|`"throw"`, `"warn"`, `"ignore"`|Determines what should be done for undefined CSS modules (using a `styleName` for which there is no CSS module defined). Setting this option to `"ignore"` is equivalent to setting `errorWhenNotFound: false` in [react-css-modules](https://github.com/gajus/react-css-modules#errorwhennotfound). |`"throw"`|
@@ -520,4 +520,4 @@ $scales: 10, 20, 30, 40, 50;
}
```
-`babel-plugin-react-css-modules` will not receive `icon-10` or `icon-50`, but `icon-#{$scale}`. That is why you receive the error that `styleName` `"icon-10"` cannot be found.
\ No newline at end of file
+`babel-plugin-react-css-modules` will not receive `icon-10` or `icon-50`, but `icon-#{$scale}`. That is why you receive the error that `styleName` `"icon-10"` cannot be found.
From aef71c779bb79de4bbec9cb70e18016a65e8c865 Mon Sep 17 00:00:00 2001
From: Gajus Kuizinas
Date: Fri, 23 Apr 2021 14:27:10 -0500
Subject: [PATCH 12/13] docs: add a call for maintainers
---
README.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1af05a7..d46a6d0 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,12 @@
[](https://gitter.im/babel-plugin-react-css-modules/Lobby)
[](https://twitter.com/kuizinas)
+> # Looking for maintainers
+>
+> This project is not actively maintained by the original author. However, I am happy to nominate new maintainers.
+> If you wish to contribute to `babel-plugin-react-css-modules`, please begin by raising PRs that fix existing issues.
+> PRs must pass CI/CD tests, include tests (if they change behavior or fix a bug), and include documentation.
+
Transforms `styleName` to `className` using compile time [CSS module](#css-modules) resolution.
@@ -264,7 +270,7 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two
> NOTE: [`postcss-nested`](https://github.com/postcss/postcss-nested) is added as an extra plugin for demonstration purposes only. It's not needed with [`postcss-scss`](https://github.com/postcss/postcss-scss) because SCSS already supports nesting.
- Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config:
+ Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config:
```json
"plugins": [
From eb008aaa7c8efc61c266f15b03c101cbb111a53e Mon Sep 17 00:00:00 2001
From: Gajus Kuizinas
Date: Fri, 23 Apr 2021 14:27:35 -0500
Subject: [PATCH 13/13] docs: remove gitspo link
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index d46a6d0..44b349b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
# babel-plugin-react-css-modules
-[](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules)
[](https://travis-ci.org/gajus/babel-plugin-react-css-modules)
[](https://www.npmjs.org/package/babel-plugin-react-css-modules)
[](https://github.com/gajus/canonical)