diff --git a/package.json b/package.json index 3c54f8776..73b577eef 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "eslint-plugin-jest": "25.0.5", "eslint-plugin-local-rules": "1.1.0", "eslint-plugin-prettier": "4.0.0", + "http-proxy-middleware": "^2.0.1", "jest": "27.2.5", "prettier": "2.4.1", "source-map-support": "0.5.20", diff --git a/src/main.ts b/src/main.ts index 1a9048bb6..1fcc74a35 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,6 +14,7 @@ import { AuthConfig } from './config/auth.config'; import { MediaConfig } from './config/media.config'; import { ConsoleLoggerService } from './logger/console-logger.service'; import { BackendType } from './media/backends/backend-type.enum'; +import { setupFrontendProxy } from './utils/frontend-integration'; import { setupSessionMiddleware } from './utils/session'; import { setupValidationPipe } from './utils/setup-pipes'; import { setupPrivateApiDocs, setupPublicApiDocs } from './utils/swagger'; @@ -47,6 +48,7 @@ async function bootstrap(): Promise { `Serving OpenAPI docs for private api under '/private/apidoc'`, 'AppBootstrap', ); + setupFrontendProxy(app, logger); } setupSessionMiddleware(app, authConfig); diff --git a/src/utils/frontend-integration.ts b/src/utils/frontend-integration.ts new file mode 100644 index 000000000..55d109436 --- /dev/null +++ b/src/utils/frontend-integration.ts @@ -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)); +} diff --git a/src/utils/use-unless.ts b/src/utils/use-unless.ts new file mode 100644 index 000000000..ddf35a21f --- /dev/null +++ b/src/utils/use-unless.ts @@ -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); + }; +} diff --git a/yarn.lock b/yarn.lock index 17bbb5b46..85da90bbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1582,6 +1582,15 @@ __metadata: languageName: node 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": version: 2.0.3 resolution: "@types/istanbul-lib-coverage@npm:2.0.3" @@ -4172,6 +4181,13 @@ __metadata: languageName: node 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": version: 3.3.0 resolution: "events@npm:3.3.0" @@ -4502,7 +4518,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.4": +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.4": version: 1.14.4 resolution: "follow-redirects@npm:1.14.4" peerDependenciesMeta: @@ -4985,6 +5001,7 @@ __metadata: eslint-plugin-prettier: 4.0.0 express-session: 1.17.2 file-type: 16.5.3 + http-proxy-middleware: ^2.0.1 jest: 27.2.5 joi: 17.4.2 minio: 7.0.19 @@ -5077,6 +5094,30 @@ __metadata: languageName: node 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": version: 1.2.0 resolution: "http-signature@npm:1.2.0" @@ -5491,6 +5532,13 @@ __metadata: languageName: node 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": version: 1.0.1 resolution: "is-potential-custom-element-name@npm:1.0.1" @@ -6641,7 +6689,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.4": +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4": version: 4.0.4 resolution: "micromatch@npm:4.0.4" dependencies: @@ -8017,6 +8065,13 @@ __metadata: languageName: node 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": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0"