Skip to content
Merged
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
64 changes: 43 additions & 21 deletions lib/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Server {

this.options = options;
this.staticWatchers = [];
this.listeners = [];
// Keep track of websocket proxies for external websocket upgrade.
this.webSocketProxies = [];
this.sockets = [];
Expand Down Expand Up @@ -1168,15 +1169,11 @@ class Server {

let needForceShutdown = false;

const exitProcess = () => {
// eslint-disable-next-line no-process-exit
process.exit();
};

signals.forEach((signal) => {
process.on(signal, () => {
const listener = () => {
if (needForceShutdown) {
exitProcess();
// eslint-disable-next-line no-process-exit
process.exit();
}

this.logger.info(
Expand All @@ -1187,12 +1184,20 @@ class Server {

this.stopCallback(() => {
if (typeof this.compiler.close === "function") {
this.compiler.close(exitProcess);
this.compiler.close(() => {
// eslint-disable-next-line no-process-exit
process.exit();
});
} else {
exitProcess();
// eslint-disable-next-line no-process-exit
process.exit();
}
});
});
};

this.listeners.push({ name: signal, listener });

process.on(signal, listener);
});
}

Expand Down Expand Up @@ -1712,22 +1717,25 @@ class Server {
);
}

runBonjour() {
const bonjour = require("bonjour")();
stopBonjour(callback = () => {}) {
this.bonjour.unpublishAll(() => {
this.bonjour.destroy();

if (callback) {
callback();
}
});
}

bonjour.publish({
runBonjour() {
this.bonjour = require("bonjour")();
this.bonjour.publish({
name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`,
port: this.options.port,
type: this.options.server.type === "http" ? "http" : "https",
subtypes: ["webpack"],
...this.options.bonjour,
});

process.on("exit", () => {
bonjour.unpublishAll(() => {
bonjour.destroy();
});
});
}

logStatus() {
Expand Down Expand Up @@ -2198,13 +2206,21 @@ class Server {
}
}

startCallback(callback) {
startCallback(callback = () => {}) {
this.start()
.then(() => callback(null), callback)
.catch(callback);
}

async stop() {
if (this.bonjour) {
await new Promise((resolve) => {
this.stopBonjour(() => {
resolve();
});
});
}

this.webSocketProxies = [];

await Promise.all(this.staticWatchers.map((watcher) => watcher.close()));
Expand Down Expand Up @@ -2258,9 +2274,15 @@ class Server {
this.middleware = null;
}
}

// We add listeners to signals when creating a new Server instance
// So ensure they are removed to prevent EventEmitter memory leak warnings
for (const item of this.listeners) {
process.removeListener(item.name, item.listener);
}
}

stopCallback(callback) {
stopCallback(callback = () => {}) {
this.stop()
.then(() => callback(null), callback)
.catch(callback);
Expand Down
40 changes: 37 additions & 3 deletions test/e2e/bonjour.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,17 @@ const runBrowser = require("../helpers/run-browser");
const port = require("../ports-map").bonjour;

describe("bonjour option", () => {
const mockPublish = jest.fn();
const mockUnpublishAll = jest.fn();
let mockPublish;
let mockUnpublishAll;
let mockDestroy;

beforeEach(() => {
mockPublish = jest.fn();
mockUnpublishAll = jest.fn((callback) => {
callback();
});
mockDestroy = jest.fn();
});

describe("as true", () => {
let compiler;
Expand All @@ -24,6 +33,7 @@ describe("bonjour option", () => {
return {
publish: mockPublish,
unpublishAll: mockUnpublishAll,
destroy: mockDestroy,
};
});

Expand All @@ -42,8 +52,10 @@ describe("bonjour option", () => {
afterEach(async () => {
await browser.close();
await server.stop();

mockPublish.mockReset();
mockUnpublishAll.mockReset();
mockDestroy.mockReset();
});

it("should call bonjour with correct params", async () => {
Expand All @@ -69,6 +81,7 @@ describe("bonjour option", () => {
});

expect(mockUnpublishAll).toHaveBeenCalledTimes(0);
expect(mockDestroy).toHaveBeenCalledTimes(0);

expect(response.status()).toMatchSnapshot("response status");

Expand All @@ -93,6 +106,7 @@ describe("bonjour option", () => {
return {
publish: mockPublish,
unpublishAll: mockUnpublishAll,
destroy: mockDestroy,
};
});

Expand All @@ -111,8 +125,10 @@ describe("bonjour option", () => {
afterEach(async () => {
await browser.close();
await server.stop();

mockPublish.mockReset();
mockUnpublishAll.mockReset();
mockDestroy.mockReset();
});

it("should call bonjour with 'https' type", async () => {
Expand All @@ -138,6 +154,7 @@ describe("bonjour option", () => {
});

expect(mockUnpublishAll).toHaveBeenCalledTimes(0);
expect(mockDestroy).toHaveBeenCalledTimes(0);

expect(response.status()).toMatchSnapshot("response status");

Expand All @@ -162,6 +179,7 @@ describe("bonjour option", () => {
return {
publish: mockPublish,
unpublishAll: mockUnpublishAll,
destroy: mockDestroy,
};
});

Expand All @@ -180,8 +198,10 @@ describe("bonjour option", () => {
afterEach(async () => {
await browser.close();
await server.stop();

mockPublish.mockReset();
mockUnpublishAll.mockReset();
mockDestroy.mockReset();
});

it("should call bonjour with 'https' type", async () => {
Expand All @@ -207,6 +227,7 @@ describe("bonjour option", () => {
});

expect(mockUnpublishAll).toHaveBeenCalledTimes(0);
expect(mockDestroy).toHaveBeenCalledTimes(0);

expect(response.status()).toMatchSnapshot("response status");

Expand All @@ -231,6 +252,7 @@ describe("bonjour option", () => {
return {
publish: mockPublish,
unpublishAll: mockUnpublishAll,
destroy: mockDestroy,
};
});

Expand Down Expand Up @@ -258,8 +280,10 @@ describe("bonjour option", () => {
afterEach(async () => {
await browser.close();
await server.stop();

mockPublish.mockReset();
mockUnpublishAll.mockReset();
mockDestroy.mockReset();
});

it("should apply bonjour options", async () => {
Expand All @@ -286,6 +310,7 @@ describe("bonjour option", () => {
});

expect(mockUnpublishAll).toHaveBeenCalledTimes(0);
expect(mockDestroy).toHaveBeenCalledTimes(0);

expect(response.status()).toMatchSnapshot("response status");

Expand All @@ -310,6 +335,7 @@ describe("bonjour option", () => {
return {
publish: mockPublish,
unpublishAll: mockUnpublishAll,
destroy: mockDestroy,
};
});

Expand Down Expand Up @@ -338,8 +364,10 @@ describe("bonjour option", () => {
afterEach(async () => {
await browser.close();
await server.stop();

mockPublish.mockReset();
mockUnpublishAll.mockReset();
mockDestroy.mockReset();
});

it("should apply bonjour options", async () => {
Expand All @@ -366,6 +394,7 @@ describe("bonjour option", () => {
});

expect(mockUnpublishAll).toHaveBeenCalledTimes(0);
expect(mockDestroy).toHaveBeenCalledTimes(0);

expect(response.status()).toMatchSnapshot("response status");

Expand All @@ -390,6 +419,7 @@ describe("bonjour option", () => {
return {
publish: mockPublish,
unpublishAll: mockUnpublishAll,
destroy: mockDestroy,
};
});

Expand All @@ -402,7 +432,9 @@ describe("bonjour option", () => {
type: "http",
protocol: "udp",
},
server: "https",
server: {
type: "https",
},
},
compiler
);
Expand All @@ -418,6 +450,7 @@ describe("bonjour option", () => {
afterEach(async () => {
await browser.close();
await server.stop();

mockPublish.mockReset();
mockUnpublishAll.mockReset();
});
Expand Down Expand Up @@ -446,6 +479,7 @@ describe("bonjour option", () => {
});

expect(mockUnpublishAll).toHaveBeenCalledTimes(0);
expect(mockDestroy).toHaveBeenCalledTimes(0);

expect(response.status()).toMatchSnapshot("response status");

Expand Down