Skip to content

Commit cd4b658

Browse files
bjohansebasclaude
andcommitted
feat(client): bring the error overlay to parity with webpack-dev-server (#2353)
* feat(client): bring the error overlay to parity with webpack-dev-server - Render inside an about:blank iframe and style exclusively through the CSSOM so the overlay works under a strict style-src CSP; inline styles from ansi-html are re-applied via style.cssText. - Support Trusted Types: innerHTML writes go through a policy (configurable via overlayTrustedTypesPolicyName). - Capture uncaught runtime errors and unhandled rejections in the overlay (overlayRuntimeErrors, default true), with the same React error boundary heuristic as dev-server. - Inline the HTML entity encoder and drop the html-entities dependency. - Expose the overlay as a standalone subpath export (webpack-dev-middleware/client/overlay) so webpack-dev-server can reuse it. Ref webpack/webpack-hot-middleware#457 * feat(client): support opening file references in the editor When `overlayOpenEditorEndpoint` is set, file chips in the overlay become clickable and issue GET <endpoint>?fileName=<file:line:column> — the same contract as webpack-dev-server's open-editor route. The endpoint implementation is left to the server integration, so no launch-editor dependency is added. * feat(client): bring the error overlay to parity with webpack-dev-server - Render inside an about:blank iframe and style exclusively through the CSSOM so the overlay works under a strict style-src CSP; inline styles from ansi-html are re-applied via style.cssText. - Support Trusted Types: innerHTML writes go through a policy (configurable via the overlay's trustedTypesPolicyName). - Capture uncaught runtime errors and unhandled rejections in the overlay, with the same React error boundary heuristic as dev-server. - Adopt dev-server's client.overlay option shape: a boolean or a JSON object with errors/warnings/runtimeErrors (booleans or filter functions) and trustedTypesPolicyName, so dev-server configs migrate as-is. Warnings are shown by default and no longer block updates, matching dev-server. - Support opening file references in the editor: when overlayOpenEditorEndpoint is set, file chips issue GET <endpoint>?fileName=<file:line:column> (same contract as dev-server's open-editor route); the endpoint implementation is left to the server integration. - Inline the HTML entity encoder and drop the html-entities dependency. - Expose the overlay as a standalone subpath export (webpack-dev-middleware/client/overlay) so webpack-dev-server can reuse it. Ref webpack/webpack-hot-middleware#457 Ref webpack/webpack-hot-middleware#184 * fix(client): track overlay problems per compilation With a MultiCompiler the client receives one event per bundle, and a successful build from one bundle used to wipe another bundle's still-valid errors from the overlay. Keep the live problems keyed by compilation name, render the union, and only clear the overlay when every compilation is clean. The console de-duplication cache is also keyed per bundle so interleaved payloads do not defeat it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(examples): add a MultiCompiler hot example Keep examples/hot as the minimal single-compiler setup (now with runtime-error buttons and an opt-in DEMO_WARNING build warning), and add examples/hot-multi-compiler: two compilers ("app" and "admin") sharing one middleware instance and a single SSE connection, with per-bundle `?name=` client scoping and recipes for the overlay's per-compilation error tracking. Each multi config sets a distinct output.uniqueName (and prefixed hot-update filenames): with both bundles on one page, a shared webpackHotUpdate global would make each bundle's updates land in the wrong runtime. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(client): nest overlay extensions inside the overlay option Move styles, ansiColors and openEditorEndpoint into the overlay object as webpack-dev-middleware extensions of dev-server's client.overlay shape, replacing the flat overlayStyles/ansiColors/ overlayOpenEditorEndpoint options. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 5de4c98 commit cd4b658

21 files changed

Lines changed: 1073 additions & 167 deletions

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"finalhandler",
2525
"hono",
2626
"rspack",
27+
"apos",
2728
"malformed"
2829
],
2930
"ignorePaths": [

README.md

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -375,19 +375,16 @@ entry: [
375375

376376
### Client options
377377

378-
| Name | Type | Default | Description |
379-
| :-----------------: | :-------: | :--------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
380-
| `path` | `string` | `/__webpack_hmr` | Path the SSE endpoint is served at. Must match the server `hot.path`. |
381-
| `timeout` | `number` | `20000` | Reconnection / heartbeat watchdog timeout in milliseconds. |
382-
| `overlay` | `boolean` | `true` | Show compile-time errors in an in-page overlay. |
383-
| `overlayWarnings` | `boolean` | `false` | Also show compile-time warnings in the overlay. |
384-
| `overlayStyles` | `Object` | `{}` | JSON object of CSS overrides for the overlay container. Pass JSON-encoded value via query string. |
385-
| `ansiColors` | `Object` | `{}` | JSON object overriding the ANSI → HTML color map used by the overlay. |
386-
| `reload` | `boolean` | `true` | Fall back to a full page reload when an update cannot be applied through HMR (e.g. recovering from a broken build). Set to `false` to keep HMR-only. |
387-
| `logging` | `string` | `"info"` | Logger level — one of `"none"`, `"error"`, `"warn"`, `"info"`, `"log"`, `"verbose"`. Uses webpack's runtime logger. |
388-
| `name` | `string` | `""` | Restrict updates to a specific compilation name (useful with multi-compiler). |
389-
| `autoConnect` | `boolean` | `true` | Connect on load; set to `false` and call `setOptionsAndConnect()` manually. |
390-
| `dynamicPublicPath` | `boolean` | `false` | Prefix `path` with `__webpack_public_path__` at runtime. |
378+
| Name | Type | Default | Description |
379+
| :-----------------: | :---------------: | :--------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
380+
| `path` | `string` | `/__webpack_hmr` | Path the SSE endpoint is served at. Must match the server `hot.path`. |
381+
| `timeout` | `number` | `20000` | Reconnection / heartbeat watchdog timeout in milliseconds. |
382+
| `overlay` | `boolean\|Object` | `true` | In-page overlay for problems. Same value shape as webpack-dev-server's [`client.overlay`](https://webpack.js.org/configuration/dev-server/#overlay): a boolean, or a JSON object with `errors`, `warnings`, `runtimeErrors` (booleans or filter functions) and `trustedTypesPolicyName`. Partial objects are filled with `true`. Also accepts the webpack-dev-middleware extensions `styles` (CSS overrides for the overlay card), `ansiColors` (ANSI → HTML color map) and `openEditorEndpoint` (when set, file references become clickable and issue `GET <endpoint>?fileName=<file:line:column>`; the endpoint is provided by your server, e.g. a route calling [launch-editor](https://github.com/yyx990803/launch-editor)). |
383+
| `reload` | `boolean` | `true` | Fall back to a full page reload when an update cannot be applied through HMR (e.g. recovering from a broken build). Set to `false` to keep HMR-only. |
384+
| `logging` | `string` | `"info"` | Logger level — one of `"none"`, `"error"`, `"warn"`, `"info"`, `"log"`, `"verbose"`. Uses webpack's runtime logger. |
385+
| `name` | `string` | `""` | Restrict updates to a specific compilation name (useful with multi-compiler). |
386+
| `autoConnect` | `boolean` | `true` | Connect on load; set to `false` and call `setOptionsAndConnect()` manually. |
387+
| `dynamicPublicPath` | `boolean` | `false` | Prefix `path` with `__webpack_public_path__` at runtime. |
391388

392389
### Programmatic API
393390

@@ -426,6 +423,24 @@ hotClient.setOptionsAndConnect({ path: "/__hmr" });
426423
hotClient.disconnect();
427424
```
428425

426+
The error overlay is also exposed as a standalone module so other tooling
427+
(e.g. `webpack-dev-server`) can reuse it without the SSE client:
428+
429+
```js
430+
import configureOverlay, {
431+
clear,
432+
showProblems,
433+
} from "webpack-dev-middleware/client/overlay";
434+
435+
const overlay = configureOverlay({
436+
// ansiColors, overlayStyles, trustedTypesPolicyName, catchRuntimeError,
437+
// openEditorEndpoint
438+
});
439+
440+
overlay.showProblems("errors", ["Something broke"]);
441+
overlay.clear();
442+
```
443+
429444
## API
430445

431446
`webpack-dev-middleware` also provides convenience methods that can be use to

client-src/globals.d.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface ClientReporter {
1414
type: "errors" | "warnings",
1515
obj: { errors: string[]; warnings: string[]; name?: string },
1616
): boolean;
17-
success(): void;
17+
success(obj?: { name?: string }): void;
1818
useCustomOverlay(customOverlay: unknown): void;
1919
}
2020

@@ -23,7 +23,17 @@ interface EventSourceWrapper {
2323
close(): void;
2424
}
2525

26+
interface OverlayTrustedTypesPolicy {
27+
createHTML(value: string): string;
28+
}
29+
2630
interface Window {
2731
__wdmEventSourceWrapper?: Record<string, EventSourceWrapper>;
2832
__webpack_dev_middleware_hot_reporter__?: ClientReporter;
33+
trustedTypes?: {
34+
createPolicy(
35+
name: string,
36+
rules: { createHTML(value: string): string },
37+
): OverlayTrustedTypesPolicy;
38+
};
2939
}

0 commit comments

Comments
 (0)