Skip to content

Commit

Permalink
Update types and improve docs for server.enhanceMiddleware
Browse files Browse the repository at this point in the history
Summary:
Resolves #739.

Usage example / types fix is inspired by use in `react-native-community/cli-plugin-metro`:
https://github.com/react-native-community/cli/blob/main/packages/cli-plugin-metro/src/commands/start/runServer.ts#L87-L97

Changelog: **[Types]** Update config and `Server` types to use broader types from `connect` package

Reviewed By: motiz88

Differential Revision: D46228146

fbshipit-source-id: 63718ae44bed12735bd798a9c819b128aeb5a9d6
  • Loading branch information
huntie authored and facebook-github-bot committed Jun 2, 2023
1 parent 06682f8 commit d20d7c8
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 25 deletions.
18 changes: 16 additions & 2 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,9 +607,23 @@ Whether we should enable CMD+R hotkey for refreshing the bundle.
#### `enhanceMiddleware`
Type: `(Middleware, Server) => Middleware`
Type: `(Middleware, MetroServer) => Middleware`
The possibility to add custom middleware to the server response chain.
A function that allows attaching custom [`connect`](https://www.npmjs.com/package/connect) middleware to Metro. For example:
:::tip
You can use [`connect()`](https://www.npmjs.com/package/connect#mount-middleware) as a util to extend the base `metroMiddleware` and to mount additional middleware handlers.
:::
```ts
enhanceMiddleware: (metroMiddleware: Middleware, metroServer: MetroServer) => {
return connect()
.use(metroMiddleware)
.use('/custom-endpoint', customEndpointMiddleware());
},
```
The `Middleware` type is an alias for [`connect.HandleFunction`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/876b9ec96ba02d0c84b1e49af5890c8f5aa2dfe3/types/connect/index.d.ts#L29).
#### `rewriteRequestUrl`
Expand Down
2 changes: 1 addition & 1 deletion flow-typed/Promise.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
Expand Down
2 changes: 1 addition & 1 deletion flow-typed/npm/chalk_v4.x.x.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
Expand Down
51 changes: 51 additions & 0 deletions flow-typed/npm/connect_v3.x.x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
* @oncall react_native
*/

declare module 'connect' {
import type http from 'http';

declare export type ServerHandle = HandleFunction | http.Server;

declare type NextFunction = (err?: mixed) => void;

declare export type NextHandleFunction = (
req: IncomingMessage,
res: http.ServerResponse,
next: NextFunction,
) => void | Promise<void>;
declare export type HandleFunction =
| NextHandleFunction;

declare export interface IncomingMessage extends http.IncomingMessage {
originalUrl?: http.IncomingMessage['url'];
}

declare export interface Server extends events$EventEmitter {
(req: IncomingMessage, res: http.ServerResponse): void;

use(fn: HandleFunction): Server;
use(route: string, fn: HandleFunction): Server;

listen(
port: number,
hostname?: string,
backlog?: number,
callback?: Function,
): http.Server;
listen(port: number, hostname?: string, callback?: Function): http.Server;
listen(path: string, callback?: Function): http.Server;
listen(handle: any, listeningListener?: Function): http.Server;
}

declare type createServer = () => Server;

declare module.exports: createServer;
}
2 changes: 2 additions & 0 deletions packages/metro-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"license": "MIT",
"dependencies": {
"connect": "^3.6.5",
"cosmiconfig": "^5.0.5",
"jest-validate": "^29.2.1",
"metro": "0.76.5",
Expand All @@ -21,6 +22,7 @@
"metro-runtime": "0.76.5"
},
"devDependencies": {
"@types/connect": "^3.4.35",
"pretty-format": "^26.5.2",
"strip-ansi": "^6.0.0"
},
Expand Down
12 changes: 4 additions & 8 deletions packages/metro-config/src/configTypes.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@

'use strict';

import type {IncomingMessage, ServerResponse} from 'http';
import type {HandleFunction, Server} from 'connect';
import type {CacheStore} from 'metro-cache';
import typeof MetroCache from 'metro-cache';
import type {CacheManagerFactory} from 'metro-file-map';
import type {CustomResolver} from 'metro-resolver';
import type {JsTransformerConfig} from 'metro-transform-worker';
import type {TransformResult} from 'metro/src/DeltaBundler';
import type MetroServer from 'metro/src/Server';

import type {
DeltaResult,
Expand All @@ -25,7 +26,6 @@ import type {
SerializerOptions,
} from 'metro/src/DeltaBundler/types.flow.js';
import type {Reporter} from 'metro/src/lib/reporting';
import type Server from 'metro/src/Server';
import type {IntermediateStackFrame} from '../../metro/src/Server/symbolicate';

export type ExtraTransformOptions = {
Expand All @@ -52,11 +52,7 @@ export type GetTransformOptions = (
getDependenciesOf: (string) => Promise<Array<string>>,
) => Promise<Partial<ExtraTransformOptions>>;

export type Middleware = (
IncomingMessage,
ServerResponse,
((e: ?Error) => mixed),
) => mixed;
export type Middleware = HandleFunction;

type PerfAnnotations = Partial<{
string: {[key: string]: string},
Expand Down Expand Up @@ -168,7 +164,7 @@ type MetalConfigT = {
};

type ServerConfigT = {
enhanceMiddleware: (Middleware, Server) => Middleware,
enhanceMiddleware: (Middleware, MetroServer) => Middleware | Server,
port: number,
rewriteRequestUrl: string => string,
runInspectorProxy: boolean,
Expand Down
2 changes: 1 addition & 1 deletion packages/metro-config/src/defaults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const getDefaultValues = (projectRoot: ?string): ConfigT => ({
},

server: {
enhanceMiddleware: middleware => middleware,
enhanceMiddleware: (middleware, _) => middleware,
port: 8080,
rewriteRequestUrl: url => url,
runInspectorProxy: true,
Expand Down
15 changes: 7 additions & 8 deletions packages/metro-config/types/configTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @oncall react_native
*/

import type {IncomingMessage, ServerResponse} from 'http';
import type {HandleFunction, Server} from 'connect';
import type {CacheStore, MetroCache} from 'metro-cache';
import type {CustomResolver} from 'metro-resolver';
import type {JsTransformerConfig} from 'metro-transform-worker';
Expand All @@ -20,7 +20,7 @@ import type {
TransformResult,
} from 'metro/src/DeltaBundler/types';
import type {Reporter} from 'metro/src/lib/reporting';
import type Server from 'metro/src/Server';
import type MetroServer from 'metro/src/Server';

export interface ExtraTransformOptions {
readonly preloadedModules: {[path: string]: true} | false;
Expand All @@ -45,11 +45,7 @@ export type GetTransformOptions = (
getDependenciesOf: (filePath: string) => Promise<string[]>,
) => Promise<Partial<ExtraTransformOptions>>;

export type Middleware = (
incomingMessage: IncomingMessage,
serverResponse: ServerResponse,
error: (e?: Error) => unknown,
) => unknown;
export type Middleware = HandleFunction;

export type PerfAnnotations = Partial<{
string: {[key: string]: string};
Expand Down Expand Up @@ -163,7 +159,10 @@ export interface MetalConfigT {
}

export interface ServerConfigT {
enhanceMiddleware: (middleware: Middleware, server: Server) => Middleware;
enhanceMiddleware: (
metroMiddleware: Middleware,
metroServer: MetroServer,
) => Middleware | Server;
port: number;
rewriteRequestUrl: (url: string) => string;
runInspectorProxy: boolean;
Expand Down
9 changes: 5 additions & 4 deletions packages/metro/src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import type {
ResolverInputOptions,
SplitBundleOptions,
} from './shared/types.flow';
import type {IncomingMessage, ServerResponse} from 'http';
import type {IncomingMessage} from 'connect';
import type {ServerResponse} from 'http';
import type {CacheStore} from 'metro-cache';
import type {ConfigT, RootPerfLogger} from 'metro-config/src/configTypes.flow';
import type {
Expand Down Expand Up @@ -478,11 +479,11 @@ class Server {
processRequest: (
IncomingMessage,
ServerResponse,
((e: ?Error) => mixed),
((e: ?Error) => void),
) => void = (
req: IncomingMessage,
res: ServerResponse,
next: (?Error) => mixed,
next: (?Error) => void,
) => {
this._processRequest(req, res, next).catch(next);
};
Expand All @@ -500,7 +501,7 @@ class Server {
async _processRequest(
req: IncomingMessage,
res: ServerResponse,
next: (?Error) => mixed,
next: (?Error) => void,
) {
const originalUrl = req.url;
req.url = this._rewriteAndNormalizeUrl(req.url);
Expand Down
1 change: 1 addition & 0 deletions packages/metro/src/index.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ exports.runServer = async (
...secureServerOptions,
};
}
// $FlowFixMe[incompatible-call] 'http' and 'https' Flow types do not match
httpServer = https.createServer(options, serverApp);
} else {
httpServer = http.createServer(serverApp);
Expand Down
Loading

0 comments on commit d20d7c8

Please sign in to comment.