Skip to content

Commit 08205b4

Browse files
committed
Automatically allow hot-reloading of imported CSS
1 parent 7626eb5 commit 08205b4

File tree

8 files changed

+95
-5
lines changed
  • src
  • test/fixtures/react-css-modules
    • does not throw error if attribute has no name property
    • merges the resolved styleName with the existing className values
    • resolves namespaced styleName
    • resolves non-namespaced styleName (anonymous import)
    • resolves non-namespaced styleName (named import)
    • uses getClassName to resolve non-literal styleName (with already existing className)
    • uses getClassName to resolve non-literal styleName

8 files changed

+95
-5
lines changed

src/index.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default ({
1717
types: BabelTypes
1818
}) => {
1919
const filenameMap = {};
20+
const cursors = {};
2021

2122
const setupFileForRuntimeResolution = (path, filename) => {
2223
const programPath = path.findParent((parentPath) => {
@@ -38,11 +39,7 @@ export default ({
3839
)
3940
);
4041

41-
const firstNonImportDeclarationNode = programPath.get('body').find((node) => {
42-
return !t.isImportDeclaration(node);
43-
});
44-
45-
firstNonImportDeclarationNode.insertBefore(
42+
cursors[filename].insertAfter(
4643
t.variableDeclaration(
4744
'const',
4845
[
@@ -86,6 +83,45 @@ export default ({
8683
filenameMap[filename].styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, {
8784
generateScopedName: stats.opts.generateScopedName
8885
});
86+
87+
const test = t.memberExpression(t.identifier('module'), t.identifier('hot'));
88+
const consequent = t.blockStatement([
89+
t.expressionStatement(
90+
t.callExpression(
91+
t.memberExpression(
92+
t.memberExpression(t.identifier('module'), t.identifier('hot')),
93+
t.identifier('accept')
94+
),
95+
[
96+
t.stringLiteral(path.node.source.value),
97+
t.functionExpression(null, [], t.blockStatement([
98+
t.expressionStatement(
99+
t.callExpression(
100+
t.identifier('require'),
101+
[t.stringLiteral(path.node.source.value)]
102+
)
103+
)
104+
]))
105+
]
106+
)
107+
)
108+
]);
109+
110+
const hotAcceptStatement = t.ifStatement(test, consequent);
111+
112+
if (cursors[filename]) {
113+
cursors[filename] = cursors[filename].insertAfter(hotAcceptStatement)[0];
114+
} else {
115+
const programPath = path.findParent((parentPath) => {
116+
return parentPath.isProgram();
117+
});
118+
119+
const firstNonImportDeclarationNode = programPath.get('body').find((node) => {
120+
return !t.isImportDeclaration(node);
121+
});
122+
123+
cursors[filename] = firstNonImportDeclarationNode.insertBefore(hotAcceptStatement)[0];
124+
}
89125
},
90126
JSXElement (path: Object, stats: Object): void {
91127
const filename = stats.file.opts.filename;

test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import './bar.css';
22

3+
if (module.hot) {
4+
module.hot.accept('./bar.css', function () {
5+
require('./bar.css');
6+
});
7+
}
8+
39
const props = {
410
foo: 'bar'
511
};
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
import './bar.css';
22

3+
if (module.hot) {
4+
module.hot.accept('./bar.css', function () {
5+
require('./bar.css');
6+
});
7+
}
8+
39
<div className="apple banana bar__a"></div>;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
import foo from './bar.css';
22

3+
if (module.hot) {
4+
module.hot.accept('./bar.css', function () {
5+
require('./bar.css');
6+
});
7+
}
8+
39
<div className="bar__a"></div>;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
import './bar.css';
22

3+
if (module.hot) {
4+
module.hot.accept('./bar.css', function () {
5+
require('./bar.css');
6+
});
7+
}
8+
39
<div className="bar__a"></div>;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
import foo from './bar.css';
22

3+
if (module.hot) {
4+
module.hot.accept('./bar.css', function () {
5+
require('./bar.css');
6+
});
7+
}
8+
39
<div className="bar__a"></div>;

test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@ import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassN
22
import bar from './bar.css';
33
import './foo.css';
44

5+
if (module.hot) {
6+
module.hot.accept('./bar.css', function () {
7+
require('./bar.css');
8+
});
9+
}
10+
11+
if (module.hot) {
12+
module.hot.accept('./foo.css', function () {
13+
require('./foo.css');
14+
});
15+
}
16+
517
const _styleModuleImportMap = {
618
'bar': {
719
'a-b': 'bar__a-b'

test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@ import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassN
22
import bar from './bar.css';
33
import './foo.css';
44

5+
if (module.hot) {
6+
module.hot.accept('./bar.css', function () {
7+
require('./bar.css');
8+
});
9+
}
10+
11+
if (module.hot) {
12+
module.hot.accept('./foo.css', function () {
13+
require('./foo.css');
14+
});
15+
}
16+
517
const _styleModuleImportMap = {
618
'bar': {
719
'a-b': 'bar__a-b'

0 commit comments

Comments
 (0)