Skip to content

Commit 31efe85

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

File tree

12 files changed

+120
-5
lines changed

12 files changed

+120
-5
lines changed

src/index.js

Lines changed: 43 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;
@@ -127,6 +163,8 @@ export default ({
127163
filenameMap[filename] = {
128164
styleModuleImportMap: {}
129165
};
166+
167+
cursors[filename] = null;
130168
}
131169
}
132170
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import './bar.css';
2+
3+
<div styleName='a'></div>;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.a {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import './bar.css';
2+
3+
if (module.hot) {
4+
module.hot.accept('./bar.css', function () {
5+
require('./bar.css');
6+
});
7+
}
8+
9+
<div className="bar__a"></div>;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"plugins": [
3+
[
4+
"../../../../src",
5+
{
6+
"generateScopedName": "[name]__[local]"
7+
}
8+
]
9+
]
10+
}

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)