Skip to content

Commit 6509a3f

Browse files
authoredAug 16, 2024··
feat: http2 support for connect and connect compatibility frameworks which support HTTP2 (#5267)
1 parent 1b3d124 commit 6509a3f

File tree

7 files changed

+320
-228
lines changed

7 files changed

+320
-228
lines changed
 

‎lib/Server.js

+165-145
Large diffs are not rendered by default.

‎lib/options.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -526,10 +526,10 @@
526526
"description": "Allows to set server and options (by default 'http')."
527527
},
528528
"ServerType": {
529-
"enum": ["http", "https", "spdy"]
529+
"enum": ["http", "https", "spdy", "http2"]
530530
},
531531
"ServerEnum": {
532-
"enum": ["http", "https", "spdy"],
532+
"enum": ["http", "https", "spdy", "http2"],
533533
"cli": {
534534
"exclude": true
535535
}

‎test/__snapshots__/validate-options.test.js.snap.webpack5

+4-4
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ exports[`options validate should throw an error on the "server" option with '{"t
533533
exports[`options validate should throw an error on the "server" option with '{"type":"https","options":{"ca":true}}' value 1`] = `
534534
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
535535
- options.server should be one of these:
536-
"http" | "https" | "spdy" | non-empty string | object { type?, options? }
536+
"http" | "https" | "spdy" | "http2" | non-empty string | object { type?, options? }
537537
-> Allows to set server and options (by default 'http').
538538
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverserver
539539
Details:
@@ -550,7 +550,7 @@ exports[`options validate should throw an error on the "server" option with '{"t
550550
exports[`options validate should throw an error on the "server" option with '{"type":"https","options":{"cert":true}}' value 1`] = `
551551
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
552552
- options.server should be one of these:
553-
"http" | "https" | "spdy" | non-empty string | object { type?, options? }
553+
"http" | "https" | "spdy" | "http2" | non-empty string | object { type?, options? }
554554
-> Allows to set server and options (by default 'http').
555555
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverserver
556556
Details:
@@ -567,7 +567,7 @@ exports[`options validate should throw an error on the "server" option with '{"t
567567
exports[`options validate should throw an error on the "server" option with '{"type":"https","options":{"key":10}}' value 1`] = `
568568
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
569569
- options.server should be one of these:
570-
"http" | "https" | "spdy" | non-empty string | object { type?, options? }
570+
"http" | "https" | "spdy" | "http2" | non-empty string | object { type?, options? }
571571
-> Allows to set server and options (by default 'http').
572572
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverserver
573573
Details:
@@ -590,7 +590,7 @@ exports[`options validate should throw an error on the "server" option with '{"t
590590
exports[`options validate should throw an error on the "server" option with '{"type":"https","options":{"pfx":10}}' value 1`] = `
591591
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
592592
- options.server should be one of these:
593-
"http" | "https" | "spdy" | non-empty string | object { type?, options? }
593+
"http" | "https" | "spdy" | "http2" | non-empty string | object { type?, options? }
594594
-> Allows to set server and options (by default 'http').
595595
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverserver
596596
Details:

‎test/e2e/__snapshots__/app.test.js.snap.webpack5

+56
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,34 @@ exports[`app option should work using "connect (async)" application and "http" s
2828
"
2929
`;
3030

31+
exports[`app option should work using "connect (async)" application and "http2" server should handle GET request to index route (/): console messages 1`] = `
32+
[
33+
"[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
34+
"[HMR] Waiting for update signal from WDS...",
35+
"Hey.",
36+
]
37+
`;
38+
39+
exports[`app option should work using "connect (async)" application and "http2" server should handle GET request to index route (/): page errors 1`] = `[]`;
40+
41+
exports[`app option should work using "connect (async)" application and "http2" server should handle GET request to index route (/): response status 1`] = `200`;
42+
43+
exports[`app option should work using "connect (async)" application and "http2" server should handle GET request to index route (/): response text 1`] = `
44+
"
45+
<!DOCTYPE html>
46+
<html>
47+
<head>
48+
<meta charset='UTF-8'>
49+
<title>webpack-dev-server</title>
50+
</head>
51+
<body>
52+
<h1>webpack-dev-server is running...</h1>
53+
<script type="text/javascript" charset="utf-8" src="/main.js"></script>
54+
</body>
55+
</html>
56+
"
57+
`;
58+
3159
exports[`app option should work using "connect (async)" application and "https" server should handle GET request to index route (/): console messages 1`] = `
3260
[
3361
"[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
@@ -112,6 +140,34 @@ exports[`app option should work using "connect" application and "http" server sh
112140
"
113141
`;
114142

143+
exports[`app option should work using "connect" application and "http2" server should handle GET request to index route (/): console messages 1`] = `
144+
[
145+
"[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
146+
"[HMR] Waiting for update signal from WDS...",
147+
"Hey.",
148+
]
149+
`;
150+
151+
exports[`app option should work using "connect" application and "http2" server should handle GET request to index route (/): page errors 1`] = `[]`;
152+
153+
exports[`app option should work using "connect" application and "http2" server should handle GET request to index route (/): response status 1`] = `200`;
154+
155+
exports[`app option should work using "connect" application and "http2" server should handle GET request to index route (/): response text 1`] = `
156+
"
157+
<!DOCTYPE html>
158+
<html>
159+
<head>
160+
<meta charset='UTF-8'>
161+
<title>webpack-dev-server</title>
162+
</head>
163+
<body>
164+
<h1>webpack-dev-server is running...</h1>
165+
<script type="text/javascript" charset="utf-8" src="/main.js"></script>
166+
</body>
167+
</html>
168+
"
169+
`;
170+
115171
exports[`app option should work using "connect" application and "https" server should handle GET request to index route (/): console messages 1`] = `
116172
[
117173
"[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",

‎test/e2e/app.test.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@ const staticDirectory = path.resolve(
1515
const apps = [
1616
["express", () => require("express")()],
1717
["connect", () => require("connect")()],
18-
["connect (async)", async () => require("express")()],
18+
["connect (async)", () => require("connect")()],
1919
];
2020

21-
const servers = ["http", "https", "spdy"];
21+
const servers = ["http", "https", "spdy", "http2"];
2222

2323
describe("app option", () => {
2424
for (const [appName, app] of apps) {
2525
for (const server of servers) {
26+
if (appName === "express" && server === "http2") {
27+
// eslint-disable-next-line no-continue
28+
continue;
29+
}
30+
2631
let compiler;
2732
let devServer;
2833
let page;
@@ -82,9 +87,7 @@ describe("app option", () => {
8287
() => performance.getEntries()[0].nextHopProtocol,
8388
);
8489

85-
const isSpdy = server === "spdy";
86-
87-
if (isSpdy) {
90+
if (server === "spdy" || server === "http2") {
8891
expect(HTTPVersion).toEqual("h2");
8992
} else {
9093
expect(HTTPVersion).toEqual("http/1.1");

‎test/fixtures/watch-files-config/webpack.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
44

55
module.exports = {
66
mode: "development",
7+
devtool: false,
78
context: __dirname,
89
stats: "none",
910
entry: "./foo.js",

‎types/lib/Server.d.ts

+84-72
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ export = Server;
44
* @property {typeof useFn} use
55
*/
66
/**
7-
* @template {BasicApplication} [T=ExpressApplication]
7+
* @template {BasicApplication} [A=ExpressApplication]
8+
* @template {BasicServer} [S=HTTPServer]
89
*/
910
declare class Server<
10-
T extends BasicApplication = import("express").Application,
11+
A extends BasicApplication = import("express").Application,
12+
S extends BasicServer = import("http").Server<
13+
typeof import("http").IncomingMessage,
14+
typeof import("http").ServerResponse
15+
>,
1116
> {
1217
static get schema(): {
1318
title: string;
@@ -1160,19 +1165,19 @@ declare class Server<
11601165
*/
11611166
private static isWebTarget;
11621167
/**
1163-
* @param {Configuration<T>} options
1168+
* @param {Configuration<A, S>} options
11641169
* @param {Compiler | MultiCompiler} compiler
11651170
*/
11661171
constructor(
1167-
options: Configuration<T> | undefined,
1172+
options: Configuration<A, S> | undefined,
11681173
compiler: Compiler | MultiCompiler,
11691174
);
11701175
compiler: import("webpack").Compiler | import("webpack").MultiCompiler;
11711176
/**
11721177
* @type {ReturnType<Compiler["getInfrastructureLogger"]>}
11731178
* */
11741179
logger: ReturnType<Compiler["getInfrastructureLogger"]>;
1175-
options: Configuration<T>;
1180+
options: Configuration<A, S>;
11761181
/**
11771182
* @type {FSWatcher[]}
11781183
*/
@@ -1217,8 +1222,9 @@ declare class Server<
12171222
*/
12181223
private getClientTransport;
12191224
/**
1225+
* @template T
12201226
* @private
1221-
* @returns {string}
1227+
* @returns {T}
12221228
*/
12231229
private getServerTransport;
12241230
/**
@@ -1236,8 +1242,8 @@ declare class Server<
12361242
* @returns {Promise<void>}
12371243
*/
12381244
private setupApp;
1239-
/** @type {T | undefined}*/
1240-
app: T | undefined;
1245+
/** @type {A | undefined}*/
1246+
app: A | undefined;
12411247
/**
12421248
* @private
12431249
* @param {Stats | MultiStats} statsObj
@@ -1302,8 +1308,8 @@ declare class Server<
13021308
* @returns {void}
13031309
*/
13041310
private createServer;
1305-
/** @type {import("http").Server | undefined | null} */
1306-
server: import("http").Server | undefined | null;
1311+
/** @type {S | null | undefined}*/
1312+
server: S | null | undefined;
13071313
/**
13081314
* @private
13091315
* @returns {void}
@@ -1426,6 +1432,7 @@ declare namespace Server {
14261432
IPv4,
14271433
IPv6,
14281434
Socket,
1435+
HTTPServer,
14291436
IncomingMessage,
14301437
ServerResponse,
14311438
OpenOptions,
@@ -1449,6 +1456,7 @@ declare namespace Server {
14491456
WatchFiles,
14501457
Static,
14511458
NormalizedStatic,
1459+
ServerType,
14521460
ServerConfiguration,
14531461
WebSocketServerConfiguration,
14541462
ClientConnection,
@@ -1466,6 +1474,7 @@ declare namespace Server {
14661474
Headers,
14671475
MiddlewareHandler,
14681476
Middleware,
1477+
BasicServer,
14691478
Configuration,
14701479
BasicApplication,
14711480
};
@@ -1496,6 +1505,7 @@ type ServeStaticOptions = import("serve-static").ServeStaticOptions;
14961505
type IPv4 = import("ipaddr.js").IPv4;
14971506
type IPv6 = import("ipaddr.js").IPv6;
14981507
type Socket = import("net").Socket;
1508+
type HTTPServer = import("http").Server;
14991509
type IncomingMessage = import("http").IncomingMessage;
15001510
type ServerResponse = import("http").ServerResponse;
15011511
type OpenOptions = import("open").Options;
@@ -1579,6 +1589,7 @@ type NormalizedStatic = {
15791589
staticOptions: ServeStaticOptions;
15801590
watch: false | WatchOptions;
15811591
};
1592+
type ServerType = "http" | "https" | "spdy" | "http2" | string;
15821593
type ServerConfiguration = {
15831594
type?: string | undefined;
15841595
options?: ServerOptions | undefined;
@@ -1679,68 +1690,69 @@ type Middleware =
16791690
middleware: MiddlewareHandler;
16801691
}
16811692
| MiddlewareHandler;
1682-
type Configuration<T extends BasicApplication = import("express").Application> =
1683-
{
1684-
ipc?: string | boolean | undefined;
1685-
host?: string | undefined;
1686-
port?: Port | undefined;
1687-
hot?: boolean | "only" | undefined;
1688-
liveReload?: boolean | undefined;
1689-
devMiddleware?:
1690-
| DevMiddlewareOptions<
1691-
import("express").Request<
1692-
import("express-serve-static-core").ParamsDictionary,
1693-
any,
1694-
any,
1695-
qs.ParsedQs,
1696-
Record<string, any>
1697-
>,
1698-
import("express").Response<any, Record<string, any>>
1699-
>
1700-
| undefined;
1701-
compress?: boolean | undefined;
1702-
allowedHosts?: string | string[] | undefined;
1703-
historyApiFallback?:
1704-
| boolean
1705-
| import("connect-history-api-fallback").Options
1706-
| undefined;
1707-
bonjour?:
1708-
| boolean
1709-
| Record<string, never>
1710-
| import("bonjour-service").Service
1711-
| undefined;
1712-
watchFiles?:
1713-
| string
1714-
| string[]
1715-
| WatchFiles
1716-
| (string | WatchFiles)[]
1717-
| undefined;
1718-
static?: string | boolean | Static | (string | Static)[] | undefined;
1719-
https?: boolean | ServerOptions | undefined;
1720-
server?: string | ServerConfiguration | undefined;
1721-
app?: (() => Promise<T>) | undefined;
1722-
webSocketServer?:
1723-
| string
1724-
| boolean
1725-
| WebSocketServerConfiguration
1726-
| undefined;
1727-
proxy?: ProxyConfigArray | undefined;
1728-
open?: string | boolean | Open | (string | Open)[] | undefined;
1729-
setupExitSignals?: boolean | undefined;
1730-
client?: boolean | ClientConfiguration | undefined;
1731-
headers?:
1732-
| Headers
1733-
| ((
1734-
req: Request,
1735-
res: Response,
1736-
context: DevMiddlewareContext<Request, Response>,
1737-
) => Headers)
1738-
| undefined;
1739-
onListening?: ((devServer: Server<T>) => void) | undefined;
1740-
setupMiddlewares?:
1741-
| ((middlewares: Middleware[], devServer: Server<T>) => Middleware[])
1742-
| undefined;
1743-
};
1693+
type BasicServer = import("net").Server;
1694+
type Configuration<
1695+
A extends BasicApplication = import("express").Application,
1696+
S extends BasicServer = import("http").Server<
1697+
typeof import("http").IncomingMessage,
1698+
typeof import("http").ServerResponse
1699+
>,
1700+
> = {
1701+
ipc?: string | boolean | undefined;
1702+
host?: string | undefined;
1703+
port?: Port | undefined;
1704+
hot?: boolean | "only" | undefined;
1705+
liveReload?: boolean | undefined;
1706+
devMiddleware?:
1707+
| DevMiddlewareOptions<
1708+
import("express").Request<
1709+
import("express-serve-static-core").ParamsDictionary,
1710+
any,
1711+
any,
1712+
qs.ParsedQs,
1713+
Record<string, any>
1714+
>,
1715+
import("express").Response<any, Record<string, any>>
1716+
>
1717+
| undefined;
1718+
compress?: boolean | undefined;
1719+
allowedHosts?: string | string[] | undefined;
1720+
historyApiFallback?:
1721+
| boolean
1722+
| import("connect-history-api-fallback").Options
1723+
| undefined;
1724+
bonjour?:
1725+
| boolean
1726+
| Record<string, never>
1727+
| import("bonjour-service").Service
1728+
| undefined;
1729+
watchFiles?:
1730+
| string
1731+
| string[]
1732+
| WatchFiles
1733+
| (string | WatchFiles)[]
1734+
| undefined;
1735+
static?: string | boolean | Static | (string | Static)[] | undefined;
1736+
server?: string | ServerConfiguration | undefined;
1737+
app?: (() => Promise<A>) | undefined;
1738+
webSocketServer?: string | boolean | WebSocketServerConfiguration | undefined;
1739+
proxy?: ProxyConfigArray | undefined;
1740+
open?: string | boolean | Open | (string | Open)[] | undefined;
1741+
setupExitSignals?: boolean | undefined;
1742+
client?: boolean | ClientConfiguration | undefined;
1743+
headers?:
1744+
| Headers
1745+
| ((
1746+
req: Request,
1747+
res: Response,
1748+
context: DevMiddlewareContext<Request, Response>,
1749+
) => Headers)
1750+
| undefined;
1751+
onListening?: ((devServer: Server<A, S>) => void) | undefined;
1752+
setupMiddlewares?:
1753+
| ((middlewares: Middleware[], devServer: Server<A, S>) => Middleware[])
1754+
| undefined;
1755+
};
17441756
type BasicApplication = {
17451757
use: typeof useFn;
17461758
};

0 commit comments

Comments
 (0)
Please sign in to comment.