From bbe5c536bfe53c38e49118c5b7b7b7e294af2872 Mon Sep 17 00:00:00 2001 From: chimurai <655241+chimurai@users.noreply.github.com> Date: Fri, 15 Apr 2022 17:12:20 +0200 Subject: [PATCH] feat(ejectPlugins): skip loading default plugins --- README.md | 25 ++++++++++ src/get-plugins.ts | 15 ++++++ src/http-proxy-middleware.ts | 17 ++----- src/types.ts | 7 +++ test/unit/get-plugins.spec.ts | 88 +++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 src/get-plugins.ts create mode 100644 test/unit/get-plugins.spec.ts diff --git a/README.md b/README.md index 3c466d4f..f53d24f0 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option - [`pathRewrite` (object/function)](#pathrewrite-objectfunction) - [`router` (object/function)](#router-objectfunction) - [`plugins` (Array)](#plugins-array) + - [`ejectPlugins` (boolean) default: `false`](#ejectplugins-boolean-default-false) - [`logger` (Object)](#logger-object) - [`http-proxy` events](#http-proxy-events) - [`http-proxy` options](#http-proxy-options) @@ -286,6 +287,30 @@ const config = { }; ``` +### `ejectPlugins` (boolean) default: `false` + +Eject pre-configured plugins. + +NOTE: register your own error handlers to prevent server from crashing. + +```js +// eject default plugins and manually add them back + +const { + debugProxyErrorsPlugin, + loggerPlugin, + errorResponsePlugin, + proxyEventsPlugin, +} = require('http-proxy-middleware/plugins/default'); + +createProxyMiddleware({ + target: `http://example.org`, + changeOrigin: true, + ejectPlugins: true, + plugins: [debugProxyErrorsPlugin, loggerPlugin, errorResponsePlugin, proxyEventsPlugin], +}); +``` + ### `logger` (Object) Configure a logger to output information from http-proxy-middleware: ie. `console`, `winston`, `pino`, `bunyan`, `log4js`, etc... diff --git a/src/get-plugins.ts b/src/get-plugins.ts new file mode 100644 index 00000000..4eeffa82 --- /dev/null +++ b/src/get-plugins.ts @@ -0,0 +1,15 @@ +import type { Options, Plugin } from './types'; +import { + debugProxyErrorsPlugin, + loggerPlugin, + errorResponsePlugin, + proxyEventsPlugin, +} from './plugins/default'; + +export function getPlugins(options: Options): Plugin[] { + const defaultPlugins: Plugin[] = !!options.ejectPlugins + ? [] // no default plugins when ejecting + : [debugProxyErrorsPlugin, proxyEventsPlugin, loggerPlugin, errorResponsePlugin]; + const userPlugins: Plugin[] = options.plugins ?? []; + return [...defaultPlugins, ...userPlugins]; +} diff --git a/src/http-proxy-middleware.ts b/src/http-proxy-middleware.ts index bea6c99d..6454436d 100644 --- a/src/http-proxy-middleware.ts +++ b/src/http-proxy-middleware.ts @@ -2,16 +2,11 @@ import type * as https from 'https'; import type { Request, RequestHandler, Options, Filter, Logger } from './types'; import * as httpProxy from 'http-proxy'; import { verifyConfig } from './configuration'; +import { getPlugins } from './get-plugins'; import { matchPathFilter } from './path-filter'; import { getLogger } from './logger'; import * as PathRewriter from './path-rewriter'; import * as Router from './router'; -import { - debugProxyErrorsPlugin, - loggerPlugin, - errorResponsePlugin, - proxyEventsPlugin, -} from './plugins/default'; export class HttpProxyMiddleware { private logger: Logger; @@ -81,14 +76,8 @@ export class HttpProxyMiddleware { }; private registerPlugins(proxy: httpProxy, options: Options) { - const defaultPlugins = [ - debugProxyErrorsPlugin, - proxyEventsPlugin, - loggerPlugin, - errorResponsePlugin, - ]; - const plugins = options.plugins ?? []; - [...defaultPlugins, ...plugins].forEach((plugin) => plugin(proxy, options)); + const plugins = getPlugins(options); + plugins.forEach((plugin) => plugin(proxy, options)); } private catchUpgradeRequest = (server: https.Server) => { diff --git a/src/types.ts b/src/types.ts index 63441e03..e75421f3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -62,6 +62,13 @@ export interface Options extends httpProxy.ServerOptions { * ``` */ plugins?: Plugin[]; + /** + * Eject pre-configured plugins. + * NOTE: register your own error handlers to prevent server from crashing. + * + * @since v3.0.0 + */ + ejectPlugins?: boolean; /** * Listen to http-proxy events * @see {@link OnProxyEvent} for available events diff --git a/test/unit/get-plugins.spec.ts b/test/unit/get-plugins.spec.ts new file mode 100644 index 00000000..2292c297 --- /dev/null +++ b/test/unit/get-plugins.spec.ts @@ -0,0 +1,88 @@ +import { Plugin } from '../../src/types'; +import { getPlugins } from '../../src/get-plugins'; +import { + debugProxyErrorsPlugin, + loggerPlugin, + errorResponsePlugin, + proxyEventsPlugin, +} from '../../src/plugins/default'; + +describe('getPlugins', () => { + let plugins: Plugin[]; + + it('should return default plugins when no user plugins are provided', () => { + plugins = getPlugins({}); + + expect(plugins).toHaveLength(4); + expect(plugins.map((plugin) => plugin.name)).toMatchInlineSnapshot(` + Array [ + "debugProxyErrorsPlugin", + "proxyEventsPlugin", + "loggerPlugin", + "errorResponsePlugin", + ] + `); + }); + + it('should return no plugins when ejectPlugins is configured in option', () => { + plugins = getPlugins({ + ejectPlugins: true, + }); + + expect(plugins).toHaveLength(0); + }); + + it('should return user plugins with default plugins when user plugins are provided', () => { + const myPlugin: Plugin = () => { + /* noop */ + }; + plugins = getPlugins({ + plugins: [myPlugin], + }); + + expect(plugins).toHaveLength(5); + expect(plugins.map((plugin) => plugin.name)).toMatchInlineSnapshot(` + Array [ + "debugProxyErrorsPlugin", + "proxyEventsPlugin", + "loggerPlugin", + "errorResponsePlugin", + "myPlugin", + ] + `); + }); + + it('should only return user plugins when user plugins are provided with ejectPlugins option', () => { + const myPlugin: Plugin = () => { + /* noop */ + }; + plugins = getPlugins({ + ejectPlugins: true, + plugins: [myPlugin], + }); + + expect(plugins).toHaveLength(1); + expect(plugins.map((plugin) => plugin.name)).toMatchInlineSnapshot(` + Array [ + "myPlugin", + ] + `); + }); + + it('should return manually added default plugins in different order after using ejectPlugins', () => { + plugins = getPlugins({ + ejectPlugins: true, + plugins: [debugProxyErrorsPlugin, errorResponsePlugin, loggerPlugin, proxyEventsPlugin], // alphabetical order + }); + + expect(plugins).toHaveLength(4); + expect(plugins.map((plugin) => plugin.name)).toMatchInlineSnapshot(` + Array [ + "debugProxyErrorsPlugin", + "errorResponsePlugin", + "loggerPlugin", + "proxyEventsPlugin", + ] + `); + }); +});