Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: migrate entry injection to hooks #3424

Closed
wants to merge 4 commits into from
Closed
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 .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
run: npm run lint

- name: Security audit
run: npm audit
run: npm audit --production

- name: Check commit message
uses: wagoid/commitlint-github-action@v1
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ coverage
node_modules
.vscode
yarn.lock
yarn-error.log

.eslintcache

Expand Down
207 changes: 108 additions & 99 deletions README.md

Large diffs are not rendered by default.

222 changes: 129 additions & 93 deletions bin/cli-flags.js

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions client-src/clients/BaseClient.js

This file was deleted.

10 changes: 1 addition & 9 deletions client-src/clients/SockJSClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

const SockJS = require('../modules/sockjs-client');
const { log } = require('../utils/log');
const BaseClient = require('./BaseClient');

module.exports = class SockJSClient extends BaseClient {
module.exports = class SockJSClient {
constructor(url) {
super();

// SockJS requires `http` and `https` protocols
this.sock = new SockJS(
url.replace(/^ws:/i, 'http:').replace(/^wss:/i, 'https:')
Expand All @@ -17,11 +14,6 @@ module.exports = class SockJSClient extends BaseClient {
};
}

// eslint-disable-next-line no-unused-vars
static getClientPath(options) {
return require.resolve('./SockJSClient');
}

onOpen(f) {
this.sock.onopen = f;
}
Expand Down
10 changes: 1 addition & 9 deletions client-src/clients/WebsocketClient.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
'use strict';

const { log } = require('../utils/log');
const BaseClient = require('./BaseClient');

module.exports = class WebsocketClient extends BaseClient {
module.exports = class WebsocketClient {
constructor(url) {
super();

this.client = new WebSocket(url);
this.client.onerror = (error) => {
log.error(error);
};
}

// eslint-disable-next-line no-unused-vars
static getClientPath(options) {
return require.resolve('./WebsocketClient');
}

onOpen(f) {
this.client.onopen = f;
}
Expand Down
14 changes: 8 additions & 6 deletions client-src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ const socketURL = createSocketURL(parsedResourceQuery);

function setAllLogLevel(level) {
// This is needed because the HMR logger operate separately from dev server logger
webpackHotLog.setLogLevel(level);
webpackHotLog.setLogLevel(
level === 'verbose' || level === 'log' ? 'info' : level
);
setLogLevel(level);
}

Expand Down Expand Up @@ -85,7 +87,7 @@ const onSocketMessage = {

// Fixes #1042. overlay doesn't clear if errors are fixed but warnings remain.
if (options.overlay) {
overlay.clear();
overlay.hide();
}

sendMessage('Invalid');
Expand Down Expand Up @@ -119,7 +121,7 @@ const onSocketMessage = {
log.info('Nothing changed.');

if (options.overlay) {
overlay.clear();
overlay.hide();
}

sendMessage('StillOk');
Expand All @@ -128,7 +130,7 @@ const onSocketMessage = {
sendMessage('Ok');

if (options.overlay) {
overlay.clear();
overlay.hide();
}

if (options.initial) {
Expand Down Expand Up @@ -175,7 +177,7 @@ const onSocketMessage = {
: options.overlay && options.overlay.warnings;

if (needShowOverlay) {
overlay.showMessage(warnings);
overlay.show(warnings, 'warnings');
}

if (options.initial) {
Expand Down Expand Up @@ -203,7 +205,7 @@ const onSocketMessage = {
: options.overlay && options.overlay.errors;

if (needShowOverlay) {
overlay.showMessage(errors);
overlay.show(errors, 'errors');
}

options.initial = false;
Expand Down
192 changes: 109 additions & 83 deletions client-src/overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,113 +19,139 @@ const colors = {
darkgrey: '6D7891',
};

let overlayIframe = null;
let overlayDiv = null;
let lastOnOverlayDivReady = null;
let iframeContainerElement;
let containerElement;
let onLoadQueue = [];

ansiHTML.setColors(colors);

function createOverlayIframe(onIframeLoad) {
const iframe = document.createElement('iframe');

iframe.id = 'webpack-dev-server-client-overlay';
iframe.src = 'about:blank';
iframe.style.position = 'fixed';
iframe.style.left = 0;
iframe.style.top = 0;
iframe.style.right = 0;
iframe.style.bottom = 0;
iframe.style.width = '100vw';
iframe.style.height = '100vh';
iframe.style.border = 'none';
iframe.style.zIndex = 9999999999;
iframe.onload = onIframeLoad;

return iframe;
function createContainer() {
iframeContainerElement = document.createElement('iframe');
iframeContainerElement.id = 'webpack-dev-server-client-overlay';
iframeContainerElement.src = 'about:blank';
iframeContainerElement.style.position = 'fixed';
iframeContainerElement.style.left = 0;
iframeContainerElement.style.top = 0;
iframeContainerElement.style.right = 0;
iframeContainerElement.style.bottom = 0;
iframeContainerElement.style.width = '100vw';
iframeContainerElement.style.height = '100vh';
iframeContainerElement.style.border = 'none';
iframeContainerElement.style.zIndex = 9999999999;
iframeContainerElement.onload = () => {
containerElement =
iframeContainerElement.contentDocument.createElement('div');
containerElement.id = 'webpack-dev-server-client-overlay-div';
containerElement.style.position = 'fixed';
containerElement.style.boxSizing = 'border-box';
containerElement.style.left = 0;
containerElement.style.top = 0;
containerElement.style.right = 0;
containerElement.style.bottom = 0;
containerElement.style.width = '100vw';
containerElement.style.height = '100vh';
containerElement.style.backgroundColor = 'rgba(0, 0, 0, 0.85)';
containerElement.style.color = '#E8E8E8';
containerElement.style.fontFamily = 'Menlo, Consolas, monospace';
containerElement.style.fontSize = 'large';
containerElement.style.padding = '2rem';
containerElement.style.lineHeight = '1.2';
containerElement.style.whiteSpace = 'pre-wrap';
containerElement.style.overflow = 'auto';

const headerElement = document.createElement('span');

headerElement.innerText = 'Compiled with problems:';

const closeButtonElement = document.createElement('button');

closeButtonElement.innerText = 'X';
closeButtonElement.style.background = 'transparent';
closeButtonElement.style.border = 'none';
closeButtonElement.style.fontSize = '20px';
closeButtonElement.style.fontWeight = 'bold';
closeButtonElement.style.color = 'white';
closeButtonElement.style.cursor = 'pointer';
closeButtonElement.style.cssFloat = 'right';
closeButtonElement.style.styleFloat = 'right';
closeButtonElement.addEventListener('click', () => {
hide();
});

containerElement.appendChild(headerElement);
containerElement.appendChild(closeButtonElement);
containerElement.appendChild(document.createElement('br'));
containerElement.appendChild(document.createElement('br'));

iframeContainerElement.contentDocument.body.appendChild(containerElement);

onLoadQueue.forEach((onLoad) => {
onLoad(containerElement);
});
onLoadQueue = [];

iframeContainerElement.onload = null;
};

document.body.appendChild(iframeContainerElement);
}

function addOverlayDivTo(iframe) {
const div = iframe.contentDocument.createElement('div');

div.id = 'webpack-dev-server-client-overlay-div';
div.style.position = 'fixed';
div.style.boxSizing = 'border-box';
div.style.left = 0;
div.style.top = 0;
div.style.right = 0;
div.style.bottom = 0;
div.style.width = '100vw';
div.style.height = '100vh';
div.style.backgroundColor = 'rgba(0, 0, 0, 0.85)';
div.style.color = '#E8E8E8';
div.style.fontFamily = 'Menlo, Consolas, monospace';
div.style.fontSize = 'large';
div.style.padding = '2rem';
div.style.lineHeight = '1.2';
div.style.whiteSpace = 'pre-wrap';
div.style.overflow = 'auto';

iframe.contentDocument.body.appendChild(div);

return div;
}

function ensureOverlayDivExists(onOverlayDivReady) {
if (overlayDiv) {
function ensureOverlayExists(callback) {
if (containerElement) {
// Everything is ready, call the callback right away.
onOverlayDivReady(overlayDiv);
callback(containerElement);

return;
}

// Creating an iframe may be asynchronous so we'll schedule the callback.
// In case of multiple calls, last callback wins.
lastOnOverlayDivReady = onOverlayDivReady;
onLoadQueue.push(callback);

if (overlayIframe) {
// We've already created it.
if (iframeContainerElement) {
return;
}

// Create iframe and, when it is ready, a div inside it.
overlayIframe = createOverlayIframe(() => {
overlayDiv = addOverlayDivTo(overlayIframe);
// Now we can talk!
lastOnOverlayDivReady(overlayDiv);
});

// Zalgo alert: onIframeLoad() will be called either synchronously
// or asynchronously depending on the browser.
// We delay adding it so `overlayIframe` is set when `onIframeLoad` fires.
document.body.appendChild(overlayIframe);
createContainer();
}

// Successful compilation.
function clear() {
if (!overlayDiv) {
// It is not there in the first place.
function hide() {
if (!iframeContainerElement) {
return;
}

// Clean up and reset internal state.
document.body.removeChild(overlayIframe);
document.body.removeChild(iframeContainerElement);

overlayDiv = null;
overlayIframe = null;
lastOnOverlayDivReady = null;
iframeContainerElement = null;
containerElement = null;
}

// Compilation with errors (e.g. syntax error or missing modules).
function showMessage(messages) {
ensureOverlayDivExists((div) => {
// Make it look similar to our terminal.
const errorMessage = messages[0].message || messages[0];
const text = ansiHTML(encode(errorMessage));

div.innerHTML = `<span style="color: #${colors.red}">Failed to compile.</span><br><br>${text}`;
function show(messages, type) {
ensureOverlayExists(() => {
messages.forEach((message) => {
const entryElement = document.createElement('div');
const typeElement = document.createElement('span');

typeElement.innerText = type === 'warnings' ? 'Warning:' : 'Error:';
typeElement.style.color = `#${colors.red}`;

// Make it look similar to our terminal.
const errorMessage = message.message || messages[0];
const text = ansiHTML(encode(errorMessage));
const messageTextNode = document.createTextNode(text);

entryElement.appendChild(typeElement);
entryElement.appendChild(document.createElement('br'));
entryElement.appendChild(document.createElement('br'));
entryElement.appendChild(messageTextNode);
entryElement.appendChild(document.createElement('br'));
entryElement.appendChild(document.createElement('br'));
entryElement.appendChild(document.createElement('br'));

containerElement.appendChild(entryElement);
});
});
}

module.exports = {
clear,
showMessage,
};
module.exports = { show, hide };
6 changes: 3 additions & 3 deletions examples/cli/web-socket-url-cli/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# CLI: Web Socket URL

```console
npx webpack serve --open-target --host 0.0.0.0 --web-socket-url <insert-host>:8080
npx webpack serve --open-target --host 0.0.0.0 --client-web-socket-url ws://<insert-host>:8080
```

_NOTE: replace `<insert local ip>` with your local IP Address._
_NOTE: replace `<insert-host>` with your local IP Address._

In order to make the server publicly accessible the client needs to know with
what host to connect to the server. If `--host 0.0.0.0` is given, the client
would try to connect to `0.0.0.0`. With the `--web-socket-url` options it is possible to
would try to connect to `0.0.0.0`. With the `--client-web-socket-url` options it is possible to
override this.

## What Should Happen
Expand Down
4 changes: 1 addition & 3 deletions examples/cli/web-socket-url/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
npx webpack serve
```

_NOTE: replace `<insert local ip>` with your local IP Address._

You're now able to explicitly define the protocol used with the `client.webSocketURL` option
(have a look to the config provided in `webpack.config.js`).
(have a look at the config provided in `webpack.config.js`).

## What Should Happen

Expand Down
4 changes: 3 additions & 1 deletion globalSetupTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ async function validatePorts() {

arr.forEach((port) => {
const check = tcpPortUsed.check(port, 'localhost').then((inUse) => {
if (inUse) throw new Error(`${port} has already used. [${key}]`);
if (inUse) {
throw new Error(`${port} has already used. [${key}]`);
}
});

samples.push(check);
Expand Down
Loading