Skip to content

Commit 2dfe0ea

Browse files
committed
docs: add hot module replacement example with Express server and client setup
1 parent 0f7859b commit 2dfe0ea

9 files changed

Lines changed: 120 additions & 3 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ npm-debug.log*
77
.eslintcache
88
.cspellcache
99
/client
10-
/dist
10+
dist
1111
/local
1212
/reports
1313
/test/outputs

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { defineConfig, globalIgnores } from "eslint/config";
22
import configs from "eslint-config-webpack/configs.js";
33

44
export default defineConfig([
5-
globalIgnores(["client/**/*"]),
5+
globalIgnores(["client/**/*", "examples/**/*"]),
66
{
77
extends: [configs["recommended-dirty"]],
88
ignores: ["client-src/**/*"],

examples/hot/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Hot module replacement example
2+
3+
A minimal [Express](https://expressjs.com/) server that uses
4+
`webpack-dev-middleware` with the `hot` option to enable hot module replacement
5+
over [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events).
6+
7+
## What it shows
8+
9+
- Enabling HMR with a single `{ hot: true }` option.
10+
- Wiring the browser runtime shipped as `webpack-dev-middleware/client` as a
11+
webpack entry, together with `HotModuleReplacementPlugin`.
12+
- Accepting updates with `module.hot.accept` so edits apply without a full
13+
page reload.
14+
15+
## Files
16+
17+
| File | Purpose |
18+
| ------------------- | --------------------------------------------------------------- |
19+
| `server.js` | Express server mounting the middleware with `hot: true`. |
20+
| `webpack.config.js` | Adds the client runtime entry and `HotModuleReplacementPlugin`. |
21+
| `src/index.js` | App entry that accepts updates via `module.hot`. |
22+
| `src/render.js` | The module you edit to see HMR in action. |
23+
| `public/index.html` | Demo page that loads the bundle. |
24+
25+
## Running
26+
27+
From the repository root, build the package first so `dist/` and `client/`
28+
exist (the example imports `webpack-dev-middleware` and
29+
`webpack-dev-middleware/client` by name):
30+
31+
```bash
32+
npm run build
33+
node examples/hot/server.js
34+
```
35+
36+
Then open <http://localhost:3000> and edit `examples/hot/src/render.js`. The
37+
page updates in place — no reload.
38+
39+
Open your browser's console to see the client runtime log the HMR lifecycle
40+
(`[webpack-dev-middleware] connected`, `App is up to date.`, …). Server-side
41+
logs (`Client connected`, build status) are printed through webpack's
42+
[infrastructure logger](https://webpack.js.org/configuration/other-options/#infrastructurelogging);
43+
set `infrastructureLogging: { level: "log" }` in the webpack config to see them.

examples/hot/public/index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>webpack-dev-middleware — hot example</title>
7+
</head>
8+
<body>
9+
<main id="root"></main>
10+
<!-- Served from memory by webpack-dev-middleware at output.publicPath. -->
11+
<script src="/main.js"></script>
12+
</body>
13+
</html>

examples/hot/server.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const path = require("path");
2+
const express = require("express");
3+
const webpack = require("webpack");
4+
const middleware = require("webpack-dev-middleware");
5+
const config = require("./webpack.config.js");
6+
7+
const compiler = webpack(config);
8+
const app = express();
9+
10+
// `hot: true` serves a Server-Sent Events endpoint (at `/__webpack_hmr` by
11+
// default) that the browser runtime subscribes to. The bundled files are still
12+
// served from memory at `output.publicPath`.
13+
app.use(middleware(compiler, { hot: true }));
14+
15+
// Serve the demo page for any non-asset request.
16+
app.get("/", (req, res) => {
17+
res.sendFile(path.join(__dirname, "public", "index.html"));
18+
});
19+
20+
const port = process.env.PORT || 3000;
21+
22+
app.listen(port, () => {
23+
// eslint-disable-next-line no-console
24+
console.log(`Example app listening on http://localhost:${port}`);
25+
});

examples/hot/src/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { render } from "./render.js";
2+
3+
render();
4+
5+
// Accept updates to `render.js` and re-run it so the DOM reflects the change
6+
// without reloading the page.
7+
if (module.hot) {
8+
module.hot.accept("./render.js", () => {
9+
render();
10+
});
11+
}

examples/hot/src/render.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function render() {
2+
const root = document.getElementById("root");
3+
4+
// Edit this string (or anything below) and save — the page updates in place,
5+
// without a full reload, thanks to hot module replacement.
6+
root.textContent =
7+
"Hello from webpack-dev-middleware hot module replacement!";
8+
}

examples/hot/webpack.config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const path = require("path");
2+
const webpack = require("webpack");
3+
4+
module.exports = {
5+
mode: "development",
6+
// `webpack-dev-middleware/client` is the small runtime that subscribes to the
7+
// SSE endpoint served by the `hot` option and applies the updates. Add it as
8+
// the first entry next to your application code.
9+
entry: ["webpack-dev-middleware/client", "./src/index.js"],
10+
context: __dirname,
11+
output: {
12+
path: path.resolve(__dirname, "dist"),
13+
publicPath: "/",
14+
filename: "main.js",
15+
},
16+
plugins: [new webpack.HotModuleReplacementPlugin()],
17+
};

lint-staged.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ module.exports = {
33
"prettier --cache --write --ignore-unknown",
44
"cspell --cache --no-must-find-files --config cspell.config.json",
55
],
6-
"*.js": ["eslint --cache --fix"],
6+
"*.js": ["eslint --cache --fix --no-warn-ignored"],
77
};

0 commit comments

Comments
 (0)