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: 1 addition & 1 deletion .changeset/use-compiler-platform-target.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"webpack-dev-server": minor
---

Use `compiler.platform` to determine the target environment instead of inspecting the resolved `target` string.
Use `compiler.platform` to determine the target environment instead of inspecting the resolved `target` string. Universal targets (`"universal"` or `["web", "node"]`, where `compiler.platform.universal` is `true` since webpack `5.108.0`) are treated as web targets so the client runtime is injected.
46 changes: 44 additions & 2 deletions lib/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -574,10 +574,20 @@ class Server {
/**
* @private
* @param {Compiler} compiler compiler
* @returns {boolean} true when target is `web`, otherwise false
* @returns {boolean} true when target is `web` or `universal`, otherwise false
*/
static isWebTarget(compiler) {
return compiler.platform.web || false;
const { platform } = compiler;

// A `web` or universal target (`web` and `node` both `null`) injects the
// client. `target: false` is `null` everywhere, so it is excluded.
return Boolean(
platform.web ||
platform?.universal ||
(compiler.options.target !== false &&
platform.web === null &&
platform.node === null),
);
}

/**
Expand Down Expand Up @@ -1683,6 +1693,38 @@ class Server {
__webpack_dev_server_client__: this.getClientTransport(),
}).apply(compiler);

// For universal targets `webpack/hot/emitter` uses Node's `events`,
// which breaks in the browser. Swap it for webpack's `EventTarget`
// emitter when available.
if (
compiler.options.output.module &&
compiler.platform.web === null &&
compiler.platform.node === null
) {
let emitter;

try {
emitter = cjsRequire.resolve("webpack/hot/emitter-event-target.js");
} catch {
// older webpack versions do not ship the `EventTarget` emitter
}

if (emitter) {
new webpack.NormalModuleReplacementPlugin(
/emitter(\.js)?$/,
(result) => {
if (
/webpack[/\\]hot|webpack-dev-server[/\\]client/.test(
result.context,
)
) {
result.request = emitter;
}
},
).apply(compiler);
}
}
Comment on lines +1696 to +1726

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same thing needs to be done on the v5 branch, but I'd prefer that we ship v6 first. After that, I can backport the patch to v5 to avoid having to do another rebase on next.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll probably be a bit more involved for the v5 branch, but that's something to figure out when I put together that patch.


if (this.options.hot) {
const HMRPluginExists = compiler.options.plugins.find(
(plugin) =>
Expand Down
Loading
Loading