Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ on:
branches:
- main
- next
- hot-middleware
pull_request:
branches:
- main
- next
- hot-middleware

permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ logs
npm-debug.log*
.eslintcache
.cspellcache
/client
/dist
/local
/reports
Expand Down
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,77 @@ middleware(compiler, {
});
```

## Hot Module Replacement client

When the server is configured to serve the hot module replacement endpoint, the bundled application needs a small runtime that subscribes to that stream and applies the updates. `webpack-dev-middleware` ships that runtime under the `./client` subpath. Add it as a webpack entry next to your application code and enable `HotModuleReplacementPlugin`:

```js
const webpack = require("webpack");

module.exports = {
entry: ["webpack-dev-middleware/client", "./src/app.js"],
plugins: [new webpack.HotModuleReplacementPlugin()],
};
```

The runtime connects to `/__webpack_hmr` by default. Any of the options below can be set by adding a query string to the entry path:

```js
entry: [
"webpack-dev-middleware/client?reload=true&overlay=false",
"./src/app.js",
];
```

### Client options

| Name | Type | Default | Description |
| :-----------------: | :-------: | :--------------: | :------------------------------------------------------------------------------------------------------------------ |
| `path` | `string` | `/__webpack_hmr` | Path the SSE endpoint is served at. Must match the server `hot.path`. |
| `timeout` | `number` | `20000` | Reconnection / heartbeat watchdog timeout in milliseconds. |
| `overlay` | `boolean` | `true` | Show compile-time errors in an in-page overlay. |
| `overlayWarnings` | `boolean` | `false` | Also show compile-time warnings in the overlay. |
| `overlayStyles` | `Object` | `{}` | JSON object of CSS overrides for the overlay container. Pass JSON-encoded value via query string. |
| `ansiColors` | `Object` | `{}` | JSON object overriding the ANSI → HTML color map used by the overlay. |
| `reload` | `boolean` | `false` | Reload the page when an update cannot be applied through HMR. |
| `logging` | `string` | `"info"` | Logger level — one of `"none"`, `"error"`, `"warn"`, `"info"`, `"log"`, `"verbose"`. Uses webpack's runtime logger. |
| `name` | `string` | `""` | Restrict updates to a specific compilation name (useful with multi-compiler). |
| `autoConnect` | `boolean` | `true` | Connect on load; set to `false` and call `setOptionsAndConnect()` manually. |
| `dynamicPublicPath` | `boolean` | `false` | Prefix `path` with `__webpack_public_path__` at runtime. |

### Programmatic API

`webpack-dev-middleware/client` also exports a few functions for advanced cases:

```js
const hotClient = require("webpack-dev-middleware/client");

// Receive every HMR payload (building / built / sync / custom).
hotClient.subscribeAll((payload) => {
console.log("hot event", payload);
});

// Receive payloads whose `action` is not recognised by the client (i.e. custom
// payloads published via the server's `instance.context.hot.publish(...)`).
hotClient.subscribe((payload) => {
// do something
});

// Replace the default error overlay with your own implementation.
hotClient.useCustomOverlay({
showProblems(type, lines) {
/* ... */
},
clear() {
/* ... */
},
});

// Connect manually when `autoConnect=false`. Accepts the same option keys as
// the query-string API above.
hotClient.setOptionsAndConnect({ path: "/__hmr" });
```

## API

`webpack-dev-middleware` also provides convenience methods that can be use to
Expand Down
22 changes: 18 additions & 4 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
const MIN_BABEL_VERSION = 7;

module.exports = (api) => {
api.assertVersion(MIN_BABEL_VERSION);
api.cache(true);

return {
presets: [
[
"@babel/preset-env",
{
modules: false,
targets: {
node: "20.9.0",
esmodules: true,
node: "0.12",
},
},
],
],
env: {
test: {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "18.12.0",
},
},
],
],
plugins: ["@babel/plugin-transform-runtime"],
},
},
};
};
28 changes: 28 additions & 0 deletions client-src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-disable */

declare module "ansi-html-community" {
function ansiHtmlCommunity(str: string): string;
namespace ansiHtmlCommunity {
function setColors(colors: Record<string, string | string[]>): void;
}
export = ansiHtmlCommunity;
}

interface ClientReporter {
cleanProblemsCache(): void;
problems(
type: "errors" | "warnings",
obj: { errors: string[]; warnings: string[]; name?: string },
): boolean;
success(): void;
useCustomOverlay(customOverlay: unknown): void;
}

interface EventSourceWrapper {
addMessageListener(fn: (event: { data: string }) => void): void;
}

interface Window {
__wdmEventSourceWrapper?: Record<string, EventSourceWrapper>;
__webpack_dev_middleware_hot_reporter__?: ClientReporter;
}
Loading
Loading