From 265dbb598948d3f8e48c617544c1933ddde42f31 Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Wed, 17 Apr 2024 20:09:51 +0300 Subject: [PATCH] feat: added the `app` option to allow to use custom application --- lib/Server.js | 17 +- lib/options.json | 8 + .../validate-options.test.js.snap.webpack5 | 14 + test/e2e/app.test.js | 0 test/validate-options.test.js | 10 + types/lib/Server.d.ts | 766 +++++++++++++++--- 6 files changed, 714 insertions(+), 101 deletions(-) create mode 100644 test/e2e/app.test.js diff --git a/lib/Server.js b/lib/Server.js index fe139297df..03379fde99 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -194,6 +194,7 @@ const schema = require("./options.json"); * @property {boolean | ServerOptions} [https] * @property {boolean} [http2] * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] * @property {ProxyConfigArray} [proxy] * @property {boolean | string | Open | Array} [open] @@ -1713,7 +1714,7 @@ class Server { } this.setupHooks(); - this.setupApp(); + await this.setupApp(); this.setupHostHeaderCheck(); this.setupDevMiddleware(); // Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response @@ -1772,16 +1773,14 @@ class Server { /** * @private - * @returns {void} + * @returns {Promise} */ - setupApp() { - // eslint-disable-next-line import/no-extraneous-dependencies - const connect = require("connect"); - const app = connect(); - + async setupApp() { /** @type {T | undefined}*/ - this.app = /** @type {any} */ (app); - // this.app = new /** @type {any} */ (getExpress())(); + this.app = + typeof this.options.app === "function" + ? await this.options.app() + : getExpress()(); } /** diff --git a/lib/options.json b/lib/options.json index 567245ce4c..0951aefbcf 100644 --- a/lib/options.json +++ b/lib/options.json @@ -2,6 +2,11 @@ "title": "Dev Server options", "type": "object", "definitions": { + "App": { + "instanceof": "Function", + "description": "Allows to use custom applications (i.e. 'connect', 'fastify' and etc).", + "link": " https://webpack.js.org/configuration/dev-server/#devserverapp" + }, "AllowedHosts": { "anyOf": [ { @@ -997,6 +1002,9 @@ "server": { "$ref": "#/definitions/Server" }, + "app": { + "$ref": "#/definitions/App" + }, "setupExitSignals": { "$ref": "#/definitions/SetupExitSignals" }, diff --git a/test/__snapshots__/validate-options.test.js.snap.webpack5 b/test/__snapshots__/validate-options.test.js.snap.webpack5 index 03cf17040e..60fa07786f 100644 --- a/test/__snapshots__/validate-options.test.js.snap.webpack5 +++ b/test/__snapshots__/validate-options.test.js.snap.webpack5 @@ -52,6 +52,20 @@ exports[`options validate should throw an error on the "allowedHosts" option wit * options.allowedHosts should be a non-empty string." `; +exports[`options validate should throw an error on the "app" option with 'false' value 1`] = ` +"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. + - options.app should be an instance of function. + -> Allows to use custom applications (i.e. 'connect', 'fastify' and etc). + -> Read more at https://webpack.js.org/configuration/dev-server/#devserverapp" +`; + +exports[`options validate should throw an error on the "app" option with 'test' value 1`] = ` +"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. + - options.app should be an instance of function. + -> Allows to use custom applications (i.e. 'connect', 'fastify' and etc). + -> Read more at https://webpack.js.org/configuration/dev-server/#devserverapp" +`; + exports[`options validate should throw an error on the "bonjour" option with '' value 1`] = ` "ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. - options.bonjour should be one of these: diff --git a/test/e2e/app.test.js b/test/e2e/app.test.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/validate-options.test.js b/test/validate-options.test.js index 72bf4c933e..bc170f3dc3 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -437,6 +437,16 @@ const tests = { }, ], }, + app: { + success: [ + () => require("connect")(), + async () => + new Promise((resolve) => { + resolve(require("connect")()); + }), + ], + failure: ["test", false], + }, static: { success: [ "path", diff --git a/types/lib/Server.d.ts b/types/lib/Server.d.ts index 2ac793f67e..0755079ec0 100644 --- a/types/lib/Server.d.ts +++ b/types/lib/Server.d.ts @@ -14,12 +14,183 @@ declare class Server< title: string; type: string; definitions: { + App: { + instanceof: string; + description: string; + link: string; + }; AllowedHosts: { anyOf: ( | { type: string; minItems: number; items: { + /** @typedef {import("webpack").Configuration} WebpackConfiguration */ + /** @typedef {import("webpack").StatsOptions} StatsOptions */ + /** @typedef {import("webpack").StatsCompilation} StatsCompilation */ + /** @typedef {import("webpack").Stats} Stats */ + /** @typedef {import("webpack").MultiStats} MultiStats */ + /** @typedef {import("os").NetworkInterfaceInfo} NetworkInterfaceInfo */ + /** @typedef {import("express").NextFunction} NextFunction */ + /** @typedef {import("express").RequestHandler} ExpressRequestHandler */ + /** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */ + /** @typedef {import("chokidar").WatchOptions} WatchOptions */ + /** @typedef {import("chokidar").FSWatcher} FSWatcher */ + /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */ + /** @typedef {import("bonjour-service").Bonjour} Bonjour */ + /** @typedef {import("bonjour-service").Service} BonjourOptions */ + /** @typedef {import("http-proxy-middleware").RequestHandler} RequestHandler */ + /** @typedef {import("http-proxy-middleware").Options} HttpProxyMiddlewareOptions */ + /** @typedef {import("http-proxy-middleware").Filter} HttpProxyMiddlewareOptionsFilter */ + /** @typedef {import("serve-index").Options} ServeIndexOptions */ + /** @typedef {import("serve-static").ServeStaticOptions} ServeStaticOptions */ + /** @typedef {import("ipaddr.js").IPv4} IPv4 */ + /** @typedef {import("ipaddr.js").IPv6} IPv6 */ + /** @typedef {import("net").Socket} Socket */ + /** @typedef {import("http").IncomingMessage} IncomingMessage */ + /** @typedef {import("http").ServerResponse} ServerResponse */ + /** @typedef {import("open").Options} OpenOptions */ + /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */ + /** @typedef {import("express").Request} Request */ + /** @typedef {import("express").Response} Response */ + /** + * @template {Request} T + * @template {Response} U + * @typedef {import("webpack-dev-middleware").Options} DevMiddlewareOptions + */ + /** + * @template {Request} T + * @template {Response} U + * @typedef {import("webpack-dev-middleware").Context} DevMiddlewareContext + */ + /** + * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host + */ + /** + * @typedef {number | string | "auto"} Port + */ + /** + * @typedef {Object} WatchFiles + * @property {string | string[]} paths + * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options] + */ + /** + * @typedef {Object} Static + * @property {string} [directory] + * @property {string | string[]} [publicPath] + * @property {boolean | ServeIndexOptions} [serveIndex] + * @property {ServeStaticOptions} [staticOptions] + * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch] + */ + /** + * @typedef {Object} NormalizedStatic + * @property {string} directory + * @property {string[]} publicPath + * @property {false | ServeIndexOptions} serveIndex + * @property {ServeStaticOptions} staticOptions + * @property {false | WatchOptions} watch + */ + /** + * @typedef {Object} ServerConfiguration + * @property {"http" | "https" | "spdy" | string} [type] + * @property {ServerOptions} [options] + */ + /** + * @typedef {Object} WebSocketServerConfiguration + * @property {"sockjs" | "ws" | string | Function} [type] + * @property {Record} [options] + */ + /** + * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection + */ + /** + * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer + */ + /** + * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation + */ + /** + * @callback ByPass + * @param {Request} req + * @param {Response} res + * @param {ProxyConfigArrayItem} proxyConfig + */ + /** + * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem + */ + /** + * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray + */ + /** + * @typedef {Object} OpenApp + * @property {string} [name] + * @property {string[]} [arguments] + */ + /** + * @typedef {Object} Open + * @property {string | string[] | OpenApp} [app] + * @property {string | string[]} [target] + */ + /** + * @typedef {Object} NormalizedOpen + * @property {string} target + * @property {import("open").Options} options + */ + /** + * @typedef {Object} WebSocketURL + * @property {string} [hostname] + * @property {string} [password] + * @property {string} [pathname] + * @property {number | string} [port] + * @property {string} [protocol] + * @property {string} [username] + */ + /** + * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions + */ + /** + * @typedef {Object} ClientConfiguration + * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging] + * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay] + * @property {boolean} [progress] + * @property {boolean | number} [reconnect] + * @property {"ws" | "sockjs" | string} [webSocketTransport] + * @property {string | WebSocketURL} [webSocketURL] + */ + /** + * @typedef {Array<{ key: string; value: string }> | Record} Headers + */ + /** + * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware + */ + /** + * @template {BasicApplication} [T=import("express").Application] + * @typedef {Object} Configuration + * @property {boolean | string} [ipc] + * @property {Host} [host] + * @property {Port} [port] + * @property {boolean | "only"} [hot] + * @property {boolean} [liveReload] + * @property {DevMiddlewareOptions} [devMiddleware] + * @property {boolean} [compress] + * @property {"auto" | "all" | string | string[]} [allowedHosts] + * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback] + * @property {boolean | Record | BonjourOptions} [bonjour] + * @property {string | string[] | WatchFiles | Array} [watchFiles] + * @property {boolean | string | Static | Array} [static] + * @property {boolean | ServerOptions} [https] + * @property {boolean} [http2] + * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] + * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] + * @property {ProxyConfigArray} [proxy] + * @property {boolean | string | Open | Array} [open] + * @property {boolean} [setupExitSignals] + * @property {boolean | ClientConfiguration} [client] + * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext) => Headers)} [headers] + * @property {(devServer: Server) => void} [onListening] + * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] + */ $ref: string; }; enum?: undefined; @@ -58,18 +229,165 @@ declare class Server< link?: undefined; } | { - type: string /** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */; + type: string; description: string; link: string; cli?: undefined; } - )[]; + )[] /** @typedef {import("bonjour-service").Service} BonjourOptions */; description: string; link: string; }; Client: { description: string; link: string; + /** @typedef {import("ipaddr.js").IPv4} IPv4 */ + /** @typedef {import("ipaddr.js").IPv6} IPv6 */ + /** @typedef {import("net").Socket} Socket */ + /** @typedef {import("http").IncomingMessage} IncomingMessage */ + /** @typedef {import("http").ServerResponse} ServerResponse */ + /** @typedef {import("open").Options} OpenOptions */ + /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */ + /** @typedef {import("express").Request} Request */ + /** @typedef {import("express").Response} Response */ + /** + * @template {Request} T + * @template {Response} U + * @typedef {import("webpack-dev-middleware").Options} DevMiddlewareOptions + */ + /** + * @template {Request} T + * @template {Response} U + * @typedef {import("webpack-dev-middleware").Context} DevMiddlewareContext + */ + /** + * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host + */ + /** + * @typedef {number | string | "auto"} Port + */ + /** + * @typedef {Object} WatchFiles + * @property {string | string[]} paths + * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options] + */ + /** + * @typedef {Object} Static + * @property {string} [directory] + * @property {string | string[]} [publicPath] + * @property {boolean | ServeIndexOptions} [serveIndex] + * @property {ServeStaticOptions} [staticOptions] + * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch] + */ + /** + * @typedef {Object} NormalizedStatic + * @property {string} directory + * @property {string[]} publicPath + * @property {false | ServeIndexOptions} serveIndex + * @property {ServeStaticOptions} staticOptions + * @property {false | WatchOptions} watch + */ + /** + * @typedef {Object} ServerConfiguration + * @property {"http" | "https" | "spdy" | string} [type] + * @property {ServerOptions} [options] + */ + /** + * @typedef {Object} WebSocketServerConfiguration + * @property {"sockjs" | "ws" | string | Function} [type] + * @property {Record} [options] + */ + /** + * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection + */ + /** + * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer + */ + /** + * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation + */ + /** + * @callback ByPass + * @param {Request} req + * @param {Response} res + * @param {ProxyConfigArrayItem} proxyConfig + */ + /** + * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem + */ + /** + * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray + */ + /** + * @typedef {Object} OpenApp + * @property {string} [name] + * @property {string[]} [arguments] + */ + /** + * @typedef {Object} Open + * @property {string | string[] | OpenApp} [app] + * @property {string | string[]} [target] + */ + /** + * @typedef {Object} NormalizedOpen + * @property {string} target + * @property {import("open").Options} options + */ + /** + * @typedef {Object} WebSocketURL + * @property {string} [hostname] + * @property {string} [password] + * @property {string} [pathname] + * @property {number | string} [port] + * @property {string} [protocol] + * @property {string} [username] + */ + /** + * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions + */ + /** + * @typedef {Object} ClientConfiguration + * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging] + * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay] + * @property {boolean} [progress] + * @property {boolean | number} [reconnect] + * @property {"ws" | "sockjs" | string} [webSocketTransport] + * @property {string | WebSocketURL} [webSocketURL] + */ + /** + * @typedef {Array<{ key: string; value: string }> | Record} Headers + */ + /** + * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware + */ + /** + * @template {BasicApplication} [T=import("express").Application] + * @typedef {Object} Configuration + * @property {boolean | string} [ipc] + * @property {Host} [host] + * @property {Port} [port] + * @property {boolean | "only"} [hot] + * @property {boolean} [liveReload] + * @property {DevMiddlewareOptions} [devMiddleware] + * @property {boolean} [compress] + * @property {"auto" | "all" | string | string[]} [allowedHosts] + * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback] + * @property {boolean | Record | BonjourOptions} [bonjour] + * @property {string | string[] | WatchFiles | Array} [watchFiles] + * @property {boolean | string | Static | Array} [static] + * @property {boolean | ServerOptions} [https] + * @property {boolean} [http2] + * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] + * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] + * @property {ProxyConfigArray} [proxy] + * @property {boolean | string | Open | Array} [open] + * @property {boolean} [setupExitSignals] + * @property {boolean | ClientConfiguration} [client] + * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext) => Headers)} [headers] + * @property {(devServer: Server) => void} [onListening] + * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] + */ anyOf: ( | { enum: boolean[]; @@ -85,20 +403,162 @@ declare class Server< additionalProperties: boolean; properties: { logging: { + /** @typedef {import("open").Options} OpenOptions */ + /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */ + /** @typedef {import("express").Request} Request */ + /** @typedef {import("express").Response} Response */ + /** + * @template {Request} T + * @template {Response} U + * @typedef {import("webpack-dev-middleware").Options} DevMiddlewareOptions + */ + /** + * @template {Request} T + * @template {Response} U + * @typedef {import("webpack-dev-middleware").Context} DevMiddlewareContext + */ + /** + * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host + */ + /** + * @typedef {number | string | "auto"} Port + */ + /** + * @typedef {Object} WatchFiles + * @property {string | string[]} paths + * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options] + */ + /** + * @typedef {Object} Static + * @property {string} [directory] + * @property {string | string[]} [publicPath] + * @property {boolean | ServeIndexOptions} [serveIndex] + * @property {ServeStaticOptions} [staticOptions] + * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch] + */ + /** + * @typedef {Object} NormalizedStatic + * @property {string} directory + * @property {string[]} publicPath + * @property {false | ServeIndexOptions} serveIndex + * @property {ServeStaticOptions} staticOptions + * @property {false | WatchOptions} watch + */ + /** + * @typedef {Object} ServerConfiguration + * @property {"http" | "https" | "spdy" | string} [type] + * @property {ServerOptions} [options] + */ + /** + * @typedef {Object} WebSocketServerConfiguration + * @property {"sockjs" | "ws" | string | Function} [type] + * @property {Record} [options] + */ + /** + * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection + */ + /** + * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer + */ + /** + * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation + */ + /** + * @callback ByPass + * @param {Request} req + * @param {Response} res + * @param {ProxyConfigArrayItem} proxyConfig + */ + /** + * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem + */ + /** + * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray + */ + /** + * @typedef {Object} OpenApp + * @property {string} [name] + * @property {string[]} [arguments] + */ + /** + * @typedef {Object} Open + * @property {string | string[] | OpenApp} [app] + * @property {string | string[]} [target] + */ + /** + * @typedef {Object} NormalizedOpen + * @property {string} target + * @property {import("open").Options} options + */ + /** + * @typedef {Object} WebSocketURL + * @property {string} [hostname] + * @property {string} [password] + * @property {string} [pathname] + * @property {number | string} [port] + * @property {string} [protocol] + * @property {string} [username] + */ + /** + * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions + */ + /** + * @typedef {Object} ClientConfiguration + * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging] + * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay] + * @property {boolean} [progress] + * @property {boolean | number} [reconnect] + * @property {"ws" | "sockjs" | string} [webSocketTransport] + * @property {string | WebSocketURL} [webSocketURL] + */ + /** + * @typedef {Array<{ key: string; value: string }> | Record} Headers + */ + /** + * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware + */ + /** + * @template {BasicApplication} [T=import("express").Application] + * @typedef {Object} Configuration + * @property {boolean | string} [ipc] + * @property {Host} [host] + * @property {Port} [port] + * @property {boolean | "only"} [hot] + * @property {boolean} [liveReload] + * @property {DevMiddlewareOptions} [devMiddleware] + * @property {boolean} [compress] + * @property {"auto" | "all" | string | string[]} [allowedHosts] + * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback] + * @property {boolean | Record | BonjourOptions} [bonjour] + * @property {string | string[] | WatchFiles | Array} [watchFiles] + * @property {boolean | string | Static | Array} [static] + * @property {boolean | ServerOptions} [https] + * @property {boolean} [http2] + * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] + * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] + * @property {ProxyConfigArray} [proxy] + * @property {boolean | string | Open | Array} [open] + * @property {boolean} [setupExitSignals] + * @property {boolean | ClientConfiguration} [client] + * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext) => Headers)} [headers] + * @property {(devServer: Server) => void} [onListening] + * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] + */ + $ref: string; + }; + overlay: { + $ref: string; + }; + progress: { + $ref: string; + }; + reconnect: { + $ref: string; + }; + webSocketTransport: { $ref: string; }; - /** @typedef {import("net").Socket} Socket */ - /** @typedef {import("http").IncomingMessage} IncomingMessage */ - /** @typedef {import("http").ServerResponse} ServerResponse */ - /** @typedef {import("open").Options} OpenOptions */ - /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */ - /** @typedef {import("express").Request} Request */ - /** @typedef {import("express").Response} Response */ - /** - * @template {Request} T - * @template {Response} U - * @typedef {import("webpack-dev-middleware").Options} DevMiddlewareOptions - */ /** * @template {Request} T * @template {Response} U @@ -222,6 +682,7 @@ declare class Server< * @property {boolean | ServerOptions} [https] * @property {boolean} [http2] * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] * @property {ProxyConfigArray} [proxy] * @property {boolean | string | Open | Array} [open] @@ -231,18 +692,6 @@ declare class Server< * @property {(devServer: Server) => void} [onListening] * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] */ - overlay: { - $ref: string; - }; - progress: { - $ref: string; - }; - reconnect: { - $ref: string; - }; - webSocketTransport: { - $ref: string; - }; webSocketURL: { $ref: string; }; @@ -291,20 +740,191 @@ declare class Server< } )[]; }; + /** + * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer + */ + /** + * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation + */ + /** + * @callback ByPass + * @param {Request} req + * @param {Response} res + * @param {ProxyConfigArrayItem} proxyConfig + */ + /** + * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem + */ + /** + * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray + */ + /** + * @typedef {Object} OpenApp + * @property {string} [name] + * @property {string[]} [arguments] + */ + /** + * @typedef {Object} Open + * @property {string | string[] | OpenApp} [app] + * @property {string | string[]} [target] + */ + /** + * @typedef {Object} NormalizedOpen + * @property {string} target + * @property {import("open").Options} options + */ + /** + * @typedef {Object} WebSocketURL + * @property {string} [hostname] + * @property {string} [password] + * @property {string} [pathname] + * @property {number | string} [port] + * @property {string} [protocol] + * @property {string} [username] + */ + /** + * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions + */ + /** + * @typedef {Object} ClientConfiguration + * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging] + * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay] + * @property {boolean} [progress] + * @property {boolean | number} [reconnect] + * @property {"ws" | "sockjs" | string} [webSocketTransport] + * @property {string | WebSocketURL} [webSocketURL] + */ + /** + * @typedef {Array<{ key: string; value: string }> | Record} Headers + */ + /** + * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware + */ + /** + * @template {BasicApplication} [T=import("express").Application] + * @typedef {Object} Configuration + * @property {boolean | string} [ipc] + * @property {Host} [host] + * @property {Port} [port] + * @property {boolean | "only"} [hot] + * @property {boolean} [liveReload] + * @property {DevMiddlewareOptions} [devMiddleware] + * @property {boolean} [compress] + * @property {"auto" | "all" | string | string[]} [allowedHosts] + * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback] + * @property {boolean | Record | BonjourOptions} [bonjour] + * @property {string | string[] | WatchFiles | Array} [watchFiles] + * @property {boolean | string | Static | Array} [static] + * @property {boolean | ServerOptions} [https] + * @property {boolean} [http2] + * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] + * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] + * @property {ProxyConfigArray} [proxy] + * @property {boolean | string | Open | Array} [open] + * @property {boolean} [setupExitSignals] + * @property {boolean | ClientConfiguration} [client] + * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext) => Headers)} [headers] + * @property {(devServer: Server) => void} [onListening] + * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] + */ warnings: { anyOf: ( | { description: string; type: string; cli: { + /** + * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation + */ + /** + * @callback ByPass + * @param {Request} req + * @param {Response} res + * @param {ProxyConfigArrayItem} proxyConfig + */ + /** + * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem + */ + /** + * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray + */ + /** + * @typedef {Object} OpenApp + * @property {string} [name] + * @property {string[]} [arguments] + */ + /** + * @typedef {Object} Open + * @property {string | string[] | OpenApp} [app] + * @property {string | string[]} [target] + */ + /** + * @typedef {Object} NormalizedOpen + * @property {string} target + * @property {import("open").Options} options + */ + /** + * @typedef {Object} WebSocketURL + * @property {string} [hostname] + * @property {string} [password] + * @property {string} [pathname] + * @property {number | string} [port] + * @property {string} [protocol] + * @property {string} [username] + */ + /** + * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions + */ + /** + * @typedef {Object} ClientConfiguration + * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging] + * @property {boolean | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay] + * @property {boolean} [progress] + * @property {boolean | number} [reconnect] + * @property {"ws" | "sockjs" | string} [webSocketTransport] + * @property {string | WebSocketURL} [webSocketURL] + */ + /** + * @typedef {Array<{ key: string; value: string }> | Record} Headers + */ + /** + * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware + */ + /** + * @template {BasicApplication} [T=import("express").Application] + * @typedef {Object} Configuration + * @property {boolean | string} [ipc] + * @property {Host} [host] + * @property {Port} [port] + * @property {boolean | "only"} [hot] + * @property {boolean} [liveReload] + * @property {DevMiddlewareOptions} [devMiddleware] + * @property {boolean} [compress] + * @property {"auto" | "all" | string | string[]} [allowedHosts] + * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback] + * @property {boolean | Record | BonjourOptions} [bonjour] + * @property {string | string[] | WatchFiles | Array} [watchFiles] + * @property {boolean | string | Static | Array} [static] + * @property {boolean | ServerOptions} [https] + * @property {boolean} [http2] + * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] + * @property {() => Promise} [app] + * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] + * @property {ProxyConfigArray} [proxy] + * @property {boolean | string | Open | Array} [open] + * @property {boolean} [setupExitSignals] + * @property {boolean | ClientConfiguration} [client] + * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext) => Headers)} [headers] + * @property {(devServer: Server) => void} [onListening] + * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] + */ negatedDescription: string; }; instanceof?: undefined; } | { - instanceof: string /** - * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer - */; + instanceof: string; description: string; type?: undefined; cli?: undefined; @@ -367,36 +987,6 @@ declare class Server< )[]; }; ClientWebSocketTransport: { - /** - * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware - */ - /** - * @template {BasicApplication} [T=import("express").Application] - * @typedef {Object} Configuration - * @property {boolean | string} [ipc] - * @property {Host} [host] - * @property {Port} [port] - * @property {boolean | "only"} [hot] - * @property {boolean} [liveReload] - * @property {DevMiddlewareOptions} [devMiddleware] - * @property {boolean} [compress] - * @property {"auto" | "all" | string | string[]} [allowedHosts] - * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback] - * @property {boolean | Record | BonjourOptions} [bonjour] - * @property {string | string[] | WatchFiles | Array} [watchFiles] - * @property {boolean | string | Static | Array} [static] - * @property {boolean | ServerOptions} [https] - * @property {boolean} [http2] - * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server] - * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer] - * @property {ProxyConfigArray} [proxy] - * @property {boolean | string | Open | Array} [open] - * @property {boolean} [setupExitSignals] - * @property {boolean | ClientConfiguration} [client] - * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext) => Headers)} [headers] - * @property {(devServer: Server) => void} [onListening] - * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares] - */ anyOf: { $ref: string; }[]; @@ -477,7 +1067,7 @@ declare class Server< Compress: { type: string; description: string; - link: string /** @typedef {(req: IncomingMessage, res: import("http").ServerResponse, next: NextFunction) => void} NextHandleFunction */; + link: string; cli: { negatedDescription: string; }; @@ -561,11 +1151,7 @@ declare class Server< minLength?: undefined; } | { - type: string /** - * @private - * @returns {StatsOptions} - * @constructor - */; + type: string; minLength: number; enum?: undefined; } @@ -588,7 +1174,10 @@ declare class Server< )[]; description: string; link: string; - }; + } /** + * @param {string} gateway + * @returns {string | undefined} + */; IPC: { anyOf: ( | { @@ -601,10 +1190,7 @@ declare class Server< enum: boolean[]; minLength?: undefined; } - )[] /** - * @param {string} gateway - * @returns {string | undefined} - */; + )[]; description: string; link: string; }; @@ -686,9 +1272,6 @@ declare class Server< | { type: string; minLength: number; - /** - * @type {string | undefined} - */ items?: undefined; minItems?: undefined; } @@ -776,8 +1359,9 @@ declare class Server< description: string; }; ServerType: { - enum: string[]; + enum: string[] /** @type {WebSocketURL} */; }; + /** @type {WebSocketURL} */ ServerEnum: { enum: string[]; cli: { @@ -787,12 +1371,11 @@ declare class Server< ServerString: { type: string; minLength: number; - /** @type {WebSocketURL} */ + /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable }} */ cli: { exclude: boolean; }; }; - /** @type {ClientConfiguration} */ ServerObject: { type: string; properties: { @@ -803,7 +1386,7 @@ declare class Server< }; options: { $ref: string; - } /** @type {string} */; + }; }; additionalProperties: boolean; }; @@ -815,7 +1398,6 @@ declare class Server< type: string; description: string; }; - /** @type {ServerConfiguration} */ requestCert: { type: string; description: string; @@ -966,7 +1548,6 @@ declare class Server< additionalProperties?: undefined; } | { - /** @type {string} */ instanceof: string; type?: undefined; additionalProperties?: undefined; @@ -1068,9 +1649,10 @@ declare class Server< minItems?: undefined; } )[]; - description: string; + /** @type {MultiCompiler} */ description: string; link: string; }; + /** @type {MultiCompiler} */ serveIndex: { anyOf: ( | { @@ -1131,10 +1713,7 @@ declare class Server< type?: undefined; items?: undefined; } - )[] /** - * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions - * @returns {WatchOptions} - */; + )[]; description: string; link: string; }; @@ -1178,14 +1757,13 @@ declare class Server< WebSocketServer: { anyOf: { $ref: string; - }[]; + }[] /** + * @param {string | Static | undefined} [optionsForStatic] + * @returns {NormalizedStatic} + */; description: string; link: string; }; - /** - * @param {string | Static | undefined} [optionsForStatic] - * @returns {NormalizedStatic} - */ WebSocketServerType: { enum: string[]; }; @@ -1195,14 +1773,14 @@ declare class Server< enum: boolean[]; cli: { negatedDescription: string; - exclude?: undefined; + /** @type {NormalizedStatic} */ exclude?: undefined; }; } | { enum: string[]; cli: { exclude: boolean; - negatedDescription?: undefined; + negatedDescription?: undefined /** @type {NormalizedStatic} */; }; } )[]; @@ -1286,6 +1864,9 @@ declare class Server< server: { $ref: string; }; + app: { + $ref: string; + }; setupExitSignals: { $ref: string; }; @@ -1418,7 +1999,7 @@ declare class Server< private initialize; /** * @private - * @returns {void} + * @returns {Promise} */ private setupApp; /** @type {T | undefined}*/ @@ -1906,6 +2487,7 @@ type Configuration = https?: boolean | ServerOptions | undefined; http2?: boolean | undefined; server?: string | ServerConfiguration | undefined; + app?: (() => Promise) | undefined; webSocketServer?: | string | boolean