diff --git a/docs/configuration.md b/docs/configuration.md index 2285e319..39013cfc 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -60,6 +60,17 @@ This should be a full URL ending with a /. Defaults to null meaning assume localhost. +### controller.static_url + +Used to override where static assets such as the web bundle is loaded from. +This can be used if you want to put the static assets on a separate cdn url like `https://cdn.example.com/static/` while keeping the API hosted directly by clusterio. +Due to a limitation on how the webpack assets are built the pathname component of the url have to be `/static/`. + +See also the `clusteriocontroller copy-static` command for how to obtain the static asset files that need to be hosted. + +Defaults to null meaning use the internally hosted assets. + + ### controller.tls_certificate Path to TLS certificate to use for the HTTPS server when controller.https_port is configured. diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index cd63d9cf..bcbdd007 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -355,6 +355,8 @@ export default class Controller { this.onSystemMetricsIntervalChanged(); } else if (field === "controller.trusted_proxies") { this.trustedProxies = this.parseTrustedProxies(); + } else if (field === "controller.static_url") { + this.app.locals.staticRoot = this.config.get("controller.static_url"); } lib.invokeHook(this.plugins, "onControllerConfigFieldChanged", field, curr, prev); }); @@ -389,6 +391,7 @@ export default class Controller { } this.app.locals.mainBundle = manifest["main.js"] || "no_web_build"; } + this.app.locals.staticRoot = this.config.get("controller.static_url"); // Load plugins await this.loadPlugins(); @@ -866,7 +869,7 @@ export default class Controller { ); } - static addAppRoutes(app: Application, pluginInfos: any[]) { + static addAppRoutes(app: Application, pluginInfos: lib.PluginNodeEnvInfo[]) { app.use((req: Request, res: Response, next) => { const startNs = process.hrtime.bigint(); stream.finished(res, () => { @@ -915,9 +918,7 @@ export default class Controller { app.get(route, Controller.serveWeb(route)); } - let pluginPackagePath = require.resolve(path.posix.join(pluginInfo.requirePath, "package.json")); - let webPath = path.join(path.dirname(pluginPackagePath), "dist", "web", "static"); - app.use("/static", express.static(webPath, staticOptions)); + app.use("/static", express.static(pluginInfo.webStaticPath, staticOptions)); } } @@ -1231,7 +1232,7 @@ export default class Controller { return function(req: Request, res: Response, next: NextFunction) { let depth = routeDepth + Number(req.path.slice(-1) === "/"); let webRoot = "../".repeat(depth) || "./"; - let staticRoot = `${webRoot}static/`; + let staticRoot = res.app.locals.staticRoot ?? `${webRoot}static/`; let mainBundle: string = ""; if (res.app.locals.mainBundle) { mainBundle = res.app.locals.mainBundle; diff --git a/packages/controller/src/routes.ts b/packages/controller/src/routes.ts index bcd3eaaa..a4e1da70 100644 --- a/packages/controller/src/routes.ts +++ b/packages/controller/src/routes.ts @@ -22,6 +22,7 @@ declare global { export interface Locals { controller: Controller, mainBundle: string, + staticRoot: string | null, devPlugins: Map, streams: Map } diff --git a/packages/controller/web/index.html b/packages/controller/web/index.html index 5a5a8af0..4bf444cd 100644 --- a/packages/controller/web/index.html +++ b/packages/controller/web/index.html @@ -29,7 +29,7 @@