Add dev-proxy to frontend dev server

This adds a reverse proxy to the backend, that automatically
redirects requests that are not handled by the backend to the React
dev server running on port 3001.

The reverse proxy is only enabled when NODE_ENV is set to
'development'.

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2021-09-23 22:36:13 +02:00
parent e5750b0084
commit a4749d60f7
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
5 changed files with 113 additions and 2 deletions

View file

@ -83,6 +83,7 @@
"eslint-plugin-jest": "25.0.5", "eslint-plugin-jest": "25.0.5",
"eslint-plugin-local-rules": "1.1.0", "eslint-plugin-local-rules": "1.1.0",
"eslint-plugin-prettier": "4.0.0", "eslint-plugin-prettier": "4.0.0",
"http-proxy-middleware": "^2.0.1",
"jest": "27.2.5", "jest": "27.2.5",
"prettier": "2.4.1", "prettier": "2.4.1",
"source-map-support": "0.5.20", "source-map-support": "0.5.20",

View file

@ -14,6 +14,7 @@ import { AuthConfig } from './config/auth.config';
import { MediaConfig } from './config/media.config'; import { MediaConfig } from './config/media.config';
import { ConsoleLoggerService } from './logger/console-logger.service'; import { ConsoleLoggerService } from './logger/console-logger.service';
import { BackendType } from './media/backends/backend-type.enum'; import { BackendType } from './media/backends/backend-type.enum';
import { setupFrontendProxy } from './utils/frontend-integration';
import { setupSessionMiddleware } from './utils/session'; import { setupSessionMiddleware } from './utils/session';
import { setupValidationPipe } from './utils/setup-pipes'; import { setupValidationPipe } from './utils/setup-pipes';
import { setupPrivateApiDocs, setupPublicApiDocs } from './utils/swagger'; import { setupPrivateApiDocs, setupPublicApiDocs } from './utils/swagger';
@ -47,6 +48,7 @@ async function bootstrap(): Promise<void> {
`Serving OpenAPI docs for private api under '/private/apidoc'`, `Serving OpenAPI docs for private api under '/private/apidoc'`,
'AppBootstrap', 'AppBootstrap',
); );
setupFrontendProxy(app, logger);
} }
setupSessionMiddleware(app, authConfig); setupSessionMiddleware(app, authConfig);

View file

@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { NestExpressApplication } from '@nestjs/platform-express';
import { createProxyMiddleware } from 'http-proxy-middleware';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { useUnless } from './use-unless';
export function setupFrontendProxy(
app: NestExpressApplication,
logger: ConsoleLoggerService,
): void {
logger.log(
`Setting up proxy to frontend dev server on port 3001`,
'setupFrontendProxy',
);
const frontendProxy = createProxyMiddleware({
logProvider: () => {
return {
log: (msg) => logger.log(msg, 'FrontendProxy'),
debug: (msg) => logger.debug(msg, 'FrontendProxy'),
info: (msg) => logger.log(msg, 'FrontendProxy'),
warn: (msg) => logger.warn(msg, 'FrontendProxy'),
error: (msg) => logger.error(msg, 'FrontendProxy'),
};
},
target: 'http://localhost:3001',
changeOrigin: true,
ws: true,
});
app.use(useUnless(['/api', '/public'], frontendProxy));
}

18
src/utils/use-unless.ts Normal file
View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { NextFunction, Request, Response } from 'express';
export function useUnless(
paths: string[],
middleware: (req: Request, res: Response, next: NextFunction) => unknown,
) {
return function (req: Request, res: Response, next: NextFunction): unknown {
if (paths.some((path) => req.path.startsWith(path))) {
return next();
}
return middleware(req, res, next);
};
}

View file

@ -1582,6 +1582,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/http-proxy@npm:^1.17.5":
version: 1.17.7
resolution: "@types/http-proxy@npm:1.17.7"
dependencies:
"@types/node": "*"
checksum: 88f9c75ca65378d0287d8d0b1dbeed372c8267f4841fe2f6f2d759522494382d3943bc6cc774bef7dd125464a266bafeda813d3658b17a2d1e74acc4efb6e21c
languageName: node
linkType: hard
"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1":
version: 2.0.3 version: 2.0.3
resolution: "@types/istanbul-lib-coverage@npm:2.0.3" resolution: "@types/istanbul-lib-coverage@npm:2.0.3"
@ -4172,6 +4181,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eventemitter3@npm:^4.0.0":
version: 4.0.7
resolution: "eventemitter3@npm:4.0.7"
checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374
languageName: node
linkType: hard
"events@npm:^3.0.0, events@npm:^3.2.0": "events@npm:^3.0.0, events@npm:^3.2.0":
version: 3.3.0 version: 3.3.0
resolution: "events@npm:3.3.0" resolution: "events@npm:3.3.0"
@ -4502,7 +4518,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"follow-redirects@npm:^1.14.4": "follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.4":
version: 1.14.4 version: 1.14.4
resolution: "follow-redirects@npm:1.14.4" resolution: "follow-redirects@npm:1.14.4"
peerDependenciesMeta: peerDependenciesMeta:
@ -4985,6 +5001,7 @@ __metadata:
eslint-plugin-prettier: 4.0.0 eslint-plugin-prettier: 4.0.0
express-session: 1.17.2 express-session: 1.17.2
file-type: 16.5.3 file-type: 16.5.3
http-proxy-middleware: ^2.0.1
jest: 27.2.5 jest: 27.2.5
joi: 17.4.2 joi: 17.4.2
minio: 7.0.19 minio: 7.0.19
@ -5077,6 +5094,30 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"http-proxy-middleware@npm:^2.0.1":
version: 2.0.1
resolution: "http-proxy-middleware@npm:2.0.1"
dependencies:
"@types/http-proxy": ^1.17.5
http-proxy: ^1.18.1
is-glob: ^4.0.1
is-plain-obj: ^3.0.0
micromatch: ^4.0.2
checksum: 0de65bc6644b6efae5d26cd3bec071ceaeb92f26856ffee5ecdde9c702ea1435936e7dfb09da2ac0883eada80fdc993e9925902fc10bf6625565d6365f8cb30f
languageName: node
linkType: hard
"http-proxy@npm:^1.18.1":
version: 1.18.1
resolution: "http-proxy@npm:1.18.1"
dependencies:
eventemitter3: ^4.0.0
follow-redirects: ^1.0.0
requires-port: ^1.0.0
checksum: f5bd96bf83e0b1e4226633dbb51f8b056c3e6321917df402deacec31dd7fe433914fc7a2c1831cf7ae21e69c90b3a669b8f434723e9e8b71fd68afe30737b6a5
languageName: node
linkType: hard
"http-signature@npm:~1.2.0": "http-signature@npm:~1.2.0":
version: 1.2.0 version: 1.2.0
resolution: "http-signature@npm:1.2.0" resolution: "http-signature@npm:1.2.0"
@ -5491,6 +5532,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"is-plain-obj@npm:^3.0.0":
version: 3.0.0
resolution: "is-plain-obj@npm:3.0.0"
checksum: a6ebdf8e12ab73f33530641972a72a4b8aed6df04f762070d823808303e4f76d87d5ea5bd76f96a7bbe83d93f04ac7764429c29413bd9049853a69cb630fb21c
languageName: node
linkType: hard
"is-potential-custom-element-name@npm:^1.0.1": "is-potential-custom-element-name@npm:^1.0.1":
version: 1.0.1 version: 1.0.1
resolution: "is-potential-custom-element-name@npm:1.0.1" resolution: "is-potential-custom-element-name@npm:1.0.1"
@ -6641,7 +6689,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"micromatch@npm:^4.0.4": "micromatch@npm:^4.0.2, micromatch@npm:^4.0.4":
version: 4.0.4 version: 4.0.4
resolution: "micromatch@npm:4.0.4" resolution: "micromatch@npm:4.0.4"
dependencies: dependencies:
@ -8017,6 +8065,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"requires-port@npm:^1.0.0":
version: 1.0.0
resolution: "requires-port@npm:1.0.0"
checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff
languageName: node
linkType: hard
"resolve-cwd@npm:^3.0.0": "resolve-cwd@npm:^3.0.0":
version: 3.0.0 version: 3.0.0
resolution: "resolve-cwd@npm:3.0.0" resolution: "resolve-cwd@npm:3.0.0"