mirror of
https://github.com/wassname/talk.git
synced 2026-07-08 05:39:25 +08:00
feat: allow explicitly disabling client routes (#2311)
This commit is contained in:
+8
-1
@@ -110,6 +110,13 @@ const config: Config = {
|
||||
ignore: ["core/client/**/*"],
|
||||
executor: new LongRunningExecutor("npm run --silent start:development"),
|
||||
},
|
||||
runServerWithoutClientRoutes: {
|
||||
paths: ["locales/**/*.ftl"],
|
||||
ignore: ["core/client/**/*"],
|
||||
executor: new LongRunningExecutor(
|
||||
"DISABLE_CLIENT_ROUTES=true npm run --silent start:development"
|
||||
),
|
||||
},
|
||||
runServerLint: {
|
||||
paths: ["core/**/*.ts"],
|
||||
ignore: ["core/client/**/*"],
|
||||
@@ -140,7 +147,7 @@ const config: Config = {
|
||||
"runServerSyntaxCheck",
|
||||
],
|
||||
client: [
|
||||
"runServer",
|
||||
"runServerWithoutClientRoutes",
|
||||
"runServerLint",
|
||||
"runServerSyntaxCheck",
|
||||
"runWebpackDevServer",
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface AppOptions {
|
||||
signingConfig: JWTSigningConfig;
|
||||
tenantCache: TenantCache;
|
||||
metrics: boolean;
|
||||
disableClientRoutes: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +59,13 @@ export async function createApp(options: AppOptions): Promise<Express> {
|
||||
const passport = createPassport(options);
|
||||
|
||||
// Mount the router.
|
||||
parent.use("/", createRouter(options, { passport }));
|
||||
parent.use(
|
||||
"/",
|
||||
createRouter(options, {
|
||||
passport,
|
||||
disableClientRoutes: options.disableClientRoutes,
|
||||
})
|
||||
);
|
||||
|
||||
// Enable CORS headers for media assets, font's require them.
|
||||
parent.use("/assets/media", cors());
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import express from "express";
|
||||
import express, { Router } from "express";
|
||||
import { minify } from "html-minifier";
|
||||
import path from "path";
|
||||
|
||||
import { cacheHeadersMiddleware } from "talk-server/app/middleware/cacheHeaders";
|
||||
import { Entrypoint } from "../helpers/entrypoints";
|
||||
import { cspTenantMiddleware } from "talk-server/app/middleware/csp/tenant";
|
||||
import { installedMiddleware } from "talk-server/app/middleware/installed";
|
||||
import { tenantMiddleware } from "talk-server/app/middleware/tenant";
|
||||
import logger from "talk-server/logger";
|
||||
import TenantCache from "talk-server/services/tenant/cache";
|
||||
|
||||
import Entrypoints, { Entrypoint } from "../helpers/entrypoints";
|
||||
|
||||
export interface ClientTargetHandlerOptions {
|
||||
/**
|
||||
@@ -28,7 +35,7 @@ export interface ClientTargetHandlerOptions {
|
||||
staticURI: string;
|
||||
}
|
||||
|
||||
export function createClientTargetRouter({
|
||||
function createClientTargetRouter({
|
||||
staticURI,
|
||||
entrypoint,
|
||||
enableCustomCSS = false,
|
||||
@@ -63,3 +70,116 @@ export function createClientTargetRouter({
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
interface MountClientRouteOptions {
|
||||
tenantCache: TenantCache;
|
||||
staticURI: string;
|
||||
}
|
||||
|
||||
export function mountClientRoutes(
|
||||
router: Router,
|
||||
{ staticURI, tenantCache }: MountClientRouteOptions
|
||||
) {
|
||||
// TODO: (wyattjoh) figure out a better way of referencing paths.
|
||||
// Load the entrypoint manifest.
|
||||
const manifest = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"dist",
|
||||
"static",
|
||||
"asset-manifest.json"
|
||||
);
|
||||
const entrypoints = Entrypoints.fromFile(manifest);
|
||||
if (!entrypoints) {
|
||||
logger.error(
|
||||
{ manifest },
|
||||
"could not load the generated manifest, client routes will remain un-mounted"
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Tenant identification middleware.
|
||||
router.use(
|
||||
tenantMiddleware({
|
||||
cache: tenantCache,
|
||||
passNoTenant: true,
|
||||
})
|
||||
);
|
||||
|
||||
// Add CSP headers to the request, which only apply when serving HTML content.
|
||||
router.use(cspTenantMiddleware);
|
||||
|
||||
// Add the embed targets.
|
||||
router.use(
|
||||
"/embed/stream",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
enableCustomCSS: true,
|
||||
entrypoint: entrypoints.get("stream"),
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/embed/auth",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("auth"),
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/embed/auth/callback",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("authCallback"),
|
||||
})
|
||||
);
|
||||
|
||||
// Add the standalone targets.
|
||||
router.use(
|
||||
"/account",
|
||||
// If we aren't already installed, redirect the user to the install page.
|
||||
installedMiddleware(),
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("account"),
|
||||
})
|
||||
);
|
||||
// Add the standalone targets.
|
||||
router.use(
|
||||
"/admin",
|
||||
// If we aren't already installed, redirect the user to the install page.
|
||||
installedMiddleware(),
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("admin"),
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/install",
|
||||
// If we're already installed, redirect the user to the admin page.
|
||||
installedMiddleware({
|
||||
redirectIfInstalled: true,
|
||||
redirectURL: "/admin",
|
||||
}),
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("install"),
|
||||
})
|
||||
);
|
||||
|
||||
// Handle the root path.
|
||||
router.get(
|
||||
"/",
|
||||
// Redirect the user to the install page if they are not, otherwise redirect
|
||||
// them to the admin.
|
||||
installedMiddleware(),
|
||||
(req, res, next) => res.redirect("/admin")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import express, { Router } from "express";
|
||||
import path from "path";
|
||||
import { register } from "prom-client";
|
||||
|
||||
import { AppOptions } from "talk-server/app";
|
||||
import { noCacheMiddleware } from "talk-server/app/middleware/cacheHeaders";
|
||||
import { cspTenantMiddleware } from "talk-server/app/middleware/csp/tenant";
|
||||
import { installedMiddleware } from "talk-server/app/middleware/installed";
|
||||
import playground from "talk-server/app/middleware/playground";
|
||||
import { tenantMiddleware } from "talk-server/app/middleware/tenant";
|
||||
import { RouterOptions } from "talk-server/app/router/types";
|
||||
import logger from "talk-server/logger";
|
||||
|
||||
import Entrypoints from "../helpers/entrypoints";
|
||||
import { basicAuth } from "../middleware/basicAuth";
|
||||
import { createAPIRouter } from "./api";
|
||||
import { createClientTargetRouter } from "./client";
|
||||
import { mountClientRoutes } from "./client";
|
||||
|
||||
export function createRouter(app: AppOptions, options: RouterOptions) {
|
||||
// Create a router.
|
||||
@@ -28,109 +23,13 @@ export function createRouter(app: AppOptions, options: RouterOptions) {
|
||||
attachGraphiQL(router, app);
|
||||
}
|
||||
|
||||
// TODO: (wyattjoh) figure out a better way of referencing paths.
|
||||
// Load the entrypoint manifest.
|
||||
const manifest = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"dist",
|
||||
"static",
|
||||
"asset-manifest.json"
|
||||
);
|
||||
const entrypoints = Entrypoints.fromFile(manifest);
|
||||
if (entrypoints) {
|
||||
// Tenant identification middleware.
|
||||
router.use(
|
||||
tenantMiddleware({
|
||||
cache: app.tenantCache,
|
||||
passNoTenant: true,
|
||||
})
|
||||
);
|
||||
|
||||
// Add CSP headers to the request, which only apply when serving HTML content.
|
||||
router.use(cspTenantMiddleware);
|
||||
|
||||
const staticURI = app.config.get("static_uri");
|
||||
|
||||
// Add the embed targets.
|
||||
router.use(
|
||||
"/embed/stream",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
enableCustomCSS: true,
|
||||
entrypoint: entrypoints.get("stream"),
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/embed/auth",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("auth"),
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/embed/auth/callback",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("authCallback"),
|
||||
})
|
||||
);
|
||||
|
||||
// Add the standalone targets.
|
||||
router.use(
|
||||
"/account",
|
||||
// If we aren't already installed, redirect the user to the install page.
|
||||
installedMiddleware(),
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("account"),
|
||||
})
|
||||
);
|
||||
// Add the standalone targets.
|
||||
router.use(
|
||||
"/admin",
|
||||
// If we aren't already installed, redirect the user to the install page.
|
||||
installedMiddleware(),
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("admin"),
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/install",
|
||||
// If we're already installed, redirect the user to the admin page.
|
||||
installedMiddleware({
|
||||
redirectIfInstalled: true,
|
||||
redirectURL: "/admin",
|
||||
}),
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
cacheDuration: false,
|
||||
entrypoint: entrypoints.get("install"),
|
||||
})
|
||||
);
|
||||
|
||||
// Handle the root path.
|
||||
router.get(
|
||||
"/",
|
||||
// Redirect the user to the install page if they are not, otherwise redirect
|
||||
// them to the admin.
|
||||
installedMiddleware(),
|
||||
(req, res, next) => res.redirect("/admin")
|
||||
);
|
||||
if (!options.disableClientRoutes) {
|
||||
mountClientRoutes(router, {
|
||||
staticURI: app.config.get("static_uri"),
|
||||
tenantCache: app.tenantCache,
|
||||
});
|
||||
} else {
|
||||
logger.warn(
|
||||
{ manifest },
|
||||
"could not load the generated manifest, client routes will remain un-mounted"
|
||||
);
|
||||
logger.warn("client routes are disabled");
|
||||
}
|
||||
|
||||
if (app.metrics) {
|
||||
|
||||
@@ -6,4 +6,9 @@ export interface RouterOptions {
|
||||
* and mount new authentication middleware.
|
||||
*/
|
||||
passport: passport.Authenticator;
|
||||
|
||||
/**
|
||||
* disableClientRoutes will not mount the routes to the client bundles.
|
||||
*/
|
||||
disableClientRoutes: boolean;
|
||||
}
|
||||
|
||||
@@ -181,6 +181,14 @@ const config = convict({
|
||||
env: "DISABLE_MONGODB_AUTOINDEXING",
|
||||
arg: "disableMongoDBAutoindexing",
|
||||
},
|
||||
disable_client_routes: {
|
||||
doc:
|
||||
"Disables mounting of client routes for developing with Webpack Dev Server",
|
||||
format: Boolean,
|
||||
default: false,
|
||||
env: "DISABLE_CLIENT_ROUTES",
|
||||
arg: "disableClientRoutes",
|
||||
},
|
||||
});
|
||||
|
||||
export type Config = typeof config;
|
||||
|
||||
@@ -241,6 +241,10 @@ class Server {
|
||||
// Only enable the metrics server if concurrency is set to 1.
|
||||
const metrics = this.config.get("concurrency") === 1;
|
||||
|
||||
// Disables the client routes to serve bundles etc. Useful for devleoping with
|
||||
// Webpack Dev Server.
|
||||
const disableClientRoutes = this.config.get("disable_client_routes");
|
||||
|
||||
// Create the Talk App, branching off from the parent app.
|
||||
const app: Express = await createApp({
|
||||
parent,
|
||||
@@ -254,6 +258,7 @@ class Server {
|
||||
mailerQueue: this.tasks.mailer,
|
||||
scraperQueue: this.tasks.scraper,
|
||||
metrics,
|
||||
disableClientRoutes,
|
||||
});
|
||||
|
||||
// Start the application and store the resulting http.Server. The server
|
||||
|
||||
Reference in New Issue
Block a user