You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/guides/hot-module-replacement.md
+215-79
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,7 @@ contributors:
10
10
- joshsantos
11
11
- drpicox
12
12
- skipjack
13
+
- sbaidon
13
14
- gdi2290
14
15
related:
15
16
- title: Concepts - Hot Module Replacement
@@ -18,128 +19,220 @@ related:
18
19
url: /api/hot-module-replacement
19
20
---
20
21
22
+
T> This guide extends on code examples found in the [Development](/guides/development) guide.
23
+
21
24
Hot Module Replacement (or HMR) is one of the most useful features offered by webpack. It allows all kinds of modules to be updated at runtime without the need for a full refresh. This page focuses on __implementation__ while the [concepts page](/concepts/hot-module-replacement) gives more details on how it works and why it's useful.
22
25
23
26
W> __HMR__ is not intended for use in production, meaning it should only be used in development. See the [building for production guide](/guides/production) for more information.
24
27
25
28
26
29
## Enabling HMR
27
30
28
-
This feature is great for productivity. Let's take a look at how to set it up with [webpack-dev-server](https://github.com/webpack/webpack-dev-server)...
29
-
30
-
```js
31
-
constpath=require('path');
32
-
constwebpack=require('webpack');
31
+
This feature is great for productivity. All we need to do is update our [webpack-dev-server](https://github.com/webpack/webpack-dev-server) configuration, and use webpack's built in HMR plugin.
You can also use the CLI to modify the [webpack-dev-server](https://github.com/webpack/webpack-dev-server) configuration with the following command: `webpack-dev-server --hotOnly`.
46
64
47
-
devServer: {
48
-
hot:true, // Tell the dev-server we're using HMR
49
-
contentBase:path.resolve(__dirname, 'dist'),
50
-
publicPath:'/'
51
-
}
52
-
};
53
-
```
65
+
To get it up and running let's run `npm start` from the command line.
54
66
55
-
Not too bad, huh? Let's test it out using `module.hot.accept`...
67
+
Now let's update the `index.js` file so that when a change inside `print.js` is detected we tell webpack to accept the updated module.
56
68
57
69
__index.js__
58
70
59
-
```js
60
-
importLibraryfrom'./library';
71
+
```diff
72
+
import _ from 'lodash';
73
+
import printMe from './print.js';
61
74
62
-
if (module.hot) {
63
-
module.hot.accept('./library', function() {
64
-
console.log('Accepting the updated library module!');
65
-
Library.log();
66
-
})
67
-
}
75
+
+ if (module.hot) {
76
+
+ module.hot.accept('./print.js', function() {
77
+
+ console.log('Accepting the updated printMe module!');
btn.innerHTML = 'Click me and check the console!';
89
+
btn.onclick = printMe;
90
+
91
+
element.appendChild(btn);
92
+
93
+
return element;
94
+
}
95
+
96
+
document.body.appendChild(component());
68
97
```
69
98
70
-
__library.js__
99
+
Start changing the `console.log` statement in `print.js`, and you should see the following output in the browser console.
71
100
72
-
```js
73
-
exportdefault {
74
-
log() {
75
-
// Change this after the server is started to test
76
-
console.log('Initial log...')
101
+
__print.js__
102
+
103
+
```diff
104
+
export default function printMe() {
105
+
- console.log('I get called from print.js!');
106
+
+ console.log('Updating print.js...')
77
107
}
78
-
}
79
108
```
80
109
81
-
Start changing the `console.log` statement in `library.js`, to `'Second log...'` for example, and you should see the following output in the browser console...
110
+
__console__
82
111
83
112
```diff
84
113
[HMR] Waiting for update signal from WDS...
85
-
main.js:9998 Initial log...
86
-
main.js:9468 [WDS] Hot Module Replacement enabled.
87
-
+ 2main.js:9468 [WDS] App updated. Recompiling...
88
-
+ main.js:9468 [WDS] App hot update...
89
-
+ main.js:9912 [HMR] Checking for updates on the server...
90
-
+ main.js:9982 Accepting the updated library module!
91
-
+ 0.1bafc70….hot-update.js:11 Second log...
92
-
+ main.js:9955 [HMR] Updated modules:
93
-
+ main.js:9957 [HMR] - ./src/library.js
94
-
+ main.js:9894 [HMR] App is up to date.
114
+
main.js:4395 [WDS] Hot Module Replacement enabled.
115
+
+ 2main.js:4395 [WDS] App updated. Recompiling...
116
+
+ main.js:4395 [WDS] App hot update...
117
+
+ main.js:4330 [HMR] Checking for updates on the server...
118
+
+ main.js:10024 Accepting the updated printMe module!
+ main.js:4330 [HMR] Consider using the NamedModulesPlugin for module names.
95
123
```
96
124
97
125
98
126
## Gotchas
99
127
100
-
Hot Module Replacement can be tricky. For example, let's say I have the following class:
128
+
Hot Module Replacement can be tricky. To show this, let's go back to our working example. If you go ahead and click the button on the example page, you will realize the console is printing the old `printMe` function.
129
+
130
+
This is happening because the button's `onclick` event handler is still bound to the original `printMe` function.
101
131
102
-
```js
103
-
classLogger {
104
-
log(text) {
105
-
console.log('Logging some text: ', text)
132
+
To make this work with HMR we need to update that binding to the new `printMe` function using `module.hot.accept`:
133
+
134
+
__print.js__
135
+
136
+
```diff
137
+
import _ from 'lodash';
138
+
import printMe from './print.js';
139
+
140
+
if (module.hot) {
141
+
module.hot.accept('./print.js', function() {
142
+
console.log('Accepting the updated printMe module!');
143
+
- printMe();
144
+
+ document.body.removeChild(element);
145
+
+ element = component(); // Re-render the "component" to update the click handler
146
+
+ document.body.appendChild(element);
147
+
})
106
148
}
107
-
}
108
-
```
109
149
110
-
Even if the underlying module containing this class is patched with new code, any existing instances of the class still have the old `log` method. Meaning if we changed what that method does, it wouldn't be reflected in those old instances unless we re-instantiate them somehow using `module.hot.accept`.
btn.innerHTML = 'Click me and check the console!';
159
+
btn.onclick = printMe; // onclick event is bind to the original printMe function
160
+
161
+
element.appendChild(btn);
162
+
163
+
return element;
164
+
}
165
+
166
+
document.body.appendChild(element);
167
+
```
111
168
112
-
This is just one example, but there are many others that can easily trip people up. Luckily, there are a lot of loaders out there, some mentioned below, that will make using this process much easier.
169
+
This is just one example, but there are many others that can easily trip people up. Luckily, there are a lot of loaders out there (some of which are mentioned below) that will make hot module replacement much easier.
113
170
114
171
115
172
## HMR with Stylesheets
116
173
117
-
We can use the `style-loader` to achieve Hot Module Replacement with CSS. This loader uses `module.hot.accept` behind the scenes to patch `<style>` tags when CSS dependencies are updated. So, with the following webpack configuration...
118
-
119
-
```js
120
-
module.exports= {
121
-
// ...
122
-
module: {
123
-
rules: [
124
-
{
125
-
test:/\.css$/,
126
-
use: [ 'style-loader', 'css-loader' ]
127
-
}
128
-
]
129
-
},
130
-
// ...
131
-
}
174
+
Hot Module Replacement with CSS is actually fairly straightforward with the help of the `style-loader`. This loader uses `module.hot.accept` behind the scenes to patch `<style>` tags when CSS dependencies are updated.
175
+
176
+
First let's install both loaders with the following command:
177
+
178
+
```bash
179
+
npm install --save-dev style-loader css-loader
132
180
```
133
181
134
-
hot loading stylesheets is a breeze...
182
+
Now let's update the configuration file to make use of the loader.
0 commit comments