Skip to content

Commit 00dc4b3

Browse files
clessggajus
authored andcommitted
feat: add hot reloading (gajus#24)
* Use single-quotes in test cases so Babel copies us * Automatically allow hot-reloading of imported CSS * Add webpackHotModuleReloading option * Document webpack hot module reloading * docs: add instructions for enabling live CSS reloading
1 parent d2a2398 commit 00dc4b3

File tree

6 files changed

+87
-2
lines changed

6 files changed

+87
-2
lines changed

README.md

+22-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ In contrast to [`react-css-modules`](https://github.com/gajus/react-css-modules)
3131
* [Have a question or want to suggest an improvement?](#have-a-question-or-want-to-suggest-an-improvement)
3232
* [FAQ](#faq)
3333
* [How to reference multiple CSS modules?](#how-to-reference-multiple-css-modules)
34+
* [How to live reload the CSS?](#hot-to-live-reload-the-css)
3435

3536
## CSS Modules
3637

@@ -173,6 +174,7 @@ NODE_ENV=production ./test
173174
|---|---|---|
174175
|`context`|Must match webpack [`context`](https://webpack.github.io/docs/configuration.html#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()`|
175176
|`filetypes`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugerss, LESS and SCSS. ||
177+
|`webpackHotModuleReloading`|Enables hot reloading of CSS in webpack|`false`|
176178
|`generateScopedName`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names)|`[path]___[name]__[local]___[hash:base64:5]`|
177179

178180
Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/new?title=New%20configuration:).
@@ -185,13 +187,13 @@ Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin-
185187
To add support for different CSS syntaxes (e.g. SCSS), perform the following two steps:
186188

187189
1. Add the [postcss syntax loader](https://github.com/postcss/postcss#syntaxes) as a development dependency:
188-
190+
189191
```bash
190192
npm install postcss-scss --save-dev
191193
```
192194

193195
2. Add a filetype syntax mapping to the Babel plugin configuration
194-
196+
195197
```json
196198
"filetypes": {
197199
".scss": "postcss-scss"
@@ -358,3 +360,21 @@ const _styleModuleImportMap = {
358360
```
359361

360362
This behaviour is enabled by default in `babel-plugin-react-css-modules`.
363+
364+
## How to live reload the CSS?
365+
366+
`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.
367+
368+
To enable live reloading of the CSS:
369+
370+
* Enable [`webpackHotModuleReloading`](#configuration) `babel-plugin-react-css-modules` configuration.
371+
* Configure `webpack` to use HMR. Use [`--hot`](https://webpack.github.io/docs/webpack-dev-server.html) option if you are using `webpack-dev-server`.
372+
* Use [`style-loader`](https://github.com/webpack/style-loader) to load the style sheets.
373+
374+
> Note:
375+
>
376+
> 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.
377+
378+
> Note:
379+
>
380+
> 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.

src/index.js

+41
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,43 @@ export default ({
5757
// console.log('setting up', filename, util.inspect(filenameMap,{depth: 5}))
5858
};
5959

60+
const addWebpackHotModuleAccept = (path) => {
61+
const test = t.memberExpression(t.identifier('module'), t.identifier('hot'));
62+
const consequent = t.blockStatement([
63+
t.expressionStatement(
64+
t.callExpression(
65+
t.memberExpression(
66+
t.memberExpression(t.identifier('module'), t.identifier('hot')),
67+
t.identifier('accept')
68+
),
69+
[
70+
t.stringLiteral(path.node.source.value),
71+
t.functionExpression(null, [], t.blockStatement([
72+
t.expressionStatement(
73+
t.callExpression(
74+
t.identifier('require'),
75+
[t.stringLiteral(path.node.source.value)]
76+
)
77+
)
78+
]))
79+
]
80+
)
81+
)
82+
]);
83+
84+
const programPath = path.findParent((parentPath) => {
85+
return parentPath.isProgram();
86+
});
87+
88+
const firstNonImportDeclarationNode = programPath.get('body').find((node) => {
89+
return !t.isImportDeclaration(node);
90+
});
91+
92+
const hotAcceptStatement = t.ifStatement(test, consequent);
93+
94+
firstNonImportDeclarationNode.insertBefore(hotAcceptStatement);
95+
};
96+
6097
return {
6198
inherits: babelPluginJsxSyntax,
6299
visitor: {
@@ -93,6 +130,10 @@ export default ({
93130
filetypes: stats.opts.filetypes || {},
94131
generateScopedName: stats.opts.generateScopedName
95132
});
133+
134+
if (stats.opts.webpackHotModuleReloading) {
135+
addWebpackHotModuleAccept(path);
136+
}
96137
},
97138
JSXElement (path: Object, stats: Object): void {
98139
const filename = stats.file.opts.filename;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import './bar.css';
2+
3+
<div styleName='a'></div>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.a {}
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>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"plugins": [
3+
[
4+
"../../../../src",
5+
{
6+
"generateScopedName": "[name]__[local]",
7+
"webpackHotModuleReloading": true
8+
}
9+
]
10+
]
11+
}

0 commit comments

Comments
 (0)