From 94200433cca38b65c84ad7662989200234249596 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Mon, 28 Sep 2020 03:31:28 +0200 Subject: [PATCH] Serve interface on all routes for the interface Add all routes the web interface is served on to the express app and serve the index.html file on. Due to the index html not knowing which path it's hosted under, a path to the root of the web interface is replaced using string substitution from the master server. --- packages/master/master.js | 31 ++++ packages/master/package.json | 1 - packages/master/src/routes.js | 16 ++ packages/master/web/basename.jsx | 6 + packages/master/web/components/App.jsx | 13 ++ packages/master/web/index.html | 4 + packages/master/web/index.jsx | 13 +- packages/master/web/layout/index.jsx | 247 ++++++++++--------------- packages/master/webpack.config.js | 4 - 9 files changed, 173 insertions(+), 162 deletions(-) create mode 100644 packages/master/src/routes.js create mode 100644 packages/master/web/basename.jsx create mode 100644 packages/master/web/components/App.jsx diff --git a/packages/master/master.js b/packages/master/master.js index 53ac5d90..c8efaa2b 100755 --- a/packages/master/master.js +++ b/packages/master/master.js @@ -40,6 +40,7 @@ let devMiddleware; // homebrew modules const generateSSLcert = require("./src/generate_ssl_cert"); +const routes = require("./src/routes"); const database = require("@clusterio/lib/database"); const schema = require("@clusterio/lib/schema"); const link = require("@clusterio/lib/link"); @@ -71,6 +72,26 @@ app.use(bodyParser.urlencoded({ app.use(fileUpload()); app.use(compression()); + +// Servers the web interface with the root path set apropriately. +function serveWeb(route) { + // The depth is is the number of slashes in the route minus one, but due + // to lenient matching on trailing slashes in the route we need to + // compensate if the request path contains a slash but not the route, + // and vice versa. + let routeDepth = (route.match(/\//g) || []).length - 1 - (route.slice(-1) === "/"); + return function(req, res, next) { + let depth = routeDepth + (req.path.slice(-1) === "/"); + let webRoot = "../".repeat(depth) || "./"; + fs.readFile(path.join(__dirname, "web", "index.html"), "utf8").then((content) => { + res.type("text/html"); + res.send(content.replace(/__WEB_ROOT__/g, webRoot)); + }).catch(err => { + next(err); + }); + }; +} + // Set folder to serve static content from (the website) app.use(express.static(path.join(__dirname, "static"))); app.use(express.static("static")); // Used for data export files @@ -1698,6 +1719,16 @@ async function startServer() { }); } + // Add routes for the web interface + for (let route of routes) { + app.get(route, serveWeb(route)); + } + for (let pluginInfo of pluginInfos) { + for (let route of pluginInfo.routes || []) { + app.get(route, serveWeb(route)); + } + } + // Load plugins await pluginManagement(pluginInfos); diff --git a/packages/master/package.json b/packages/master/package.json index a18ea824..2827404d 100644 --- a/packages/master/package.json +++ b/packages/master/package.json @@ -43,7 +43,6 @@ "clean-webpack-plugin": "^3.0.0", "css-loader": "^4.3.0", "fast-deep-equal": "^3.1.3", - "html-webpack-plugin": "^4.5.0", "null-loader": "^4.0.0", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/packages/master/src/routes.js b/packages/master/src/routes.js new file mode 100644 index 00000000..7e0ca52a --- /dev/null +++ b/packages/master/src/routes.js @@ -0,0 +1,16 @@ +"use strict"; +// Routes used in the web interface and served by the master server +module.exports = [ + "/", + "/instances", + "/instances/:id/view", + "/slaves", + "/slaves/:id/view", + "/users", + "/users/:id/view", + "/roles", + "/roles/:id/view", + "/permissions", + "/permissions/:id/view", + "/settings", +]; diff --git a/packages/master/web/basename.jsx b/packages/master/web/basename.jsx new file mode 100644 index 00000000..99b8468a --- /dev/null +++ b/packages/master/web/basename.jsx @@ -0,0 +1,6 @@ +// Calculate basedir of application based on current location and +// the provided web_root from master server. +const location = new URL(window.web_root, document.location) +const basename = location.pathname !== "/" ? location.pathname : ""; + +export default basename; diff --git a/packages/master/web/components/App.jsx b/packages/master/web/components/App.jsx new file mode 100644 index 00000000..b1db4c6e --- /dev/null +++ b/packages/master/web/components/App.jsx @@ -0,0 +1,13 @@ +import React from "react"; +import { BrowserRouter } from "react-router-dom"; + +import basename from "../basename"; +import Layout from "../layout"; + +export default function App() { + return ( + + + + ); +} diff --git a/packages/master/web/index.html b/packages/master/web/index.html index 7f77d875..b7a280f7 100644 --- a/packages/master/web/index.html +++ b/packages/master/web/index.html @@ -4,9 +4,13 @@ Clusterio +
+ diff --git a/packages/master/web/index.jsx b/packages/master/web/index.jsx index 5c2828e2..0cb7c8c5 100644 --- a/packages/master/web/index.jsx +++ b/packages/master/web/index.jsx @@ -1,13 +1,8 @@ +import "./index.css" + import React from "react" import ReactDOM from "react-dom" -import { BrowserRouter } from "react-router-dom" -import "./index.css" -import Layout from "./layout" +import App from "./components/App"; -ReactDOM.render( - - - , - document.getElementById('root') -); +ReactDOM.render(, document.getElementById("root")); diff --git a/packages/master/web/layout/index.jsx b/packages/master/web/layout/index.jsx index 58e8b1be..4893ccd9 100644 --- a/packages/master/web/layout/index.jsx +++ b/packages/master/web/layout/index.jsx @@ -1,7 +1,6 @@ import { Layout, Menu } from "antd"; -import { withRouter } from "react-router-dom"; -import { BrowserRouter as Router, Route, Link } from "react-router-dom"; +import { Route, Link, withRouter } from "react-router-dom"; import React, { Component } from "react"; import { Dashboard } from "../pages/dashboard"; @@ -24,8 +23,6 @@ class SiteLayout extends Component { super(props); const { location } = props; - // this.history = useHistory(); - this.state = { collapsed: false, setcollapsed: false, @@ -58,156 +55,110 @@ class SiteLayout extends Component { render() { return ( - - - {document.location.search !== "?hideExtras" ? ( - -

-
- {" "} - {this.state.collapsed ? ( + + {document.location.search !== "?hideExtras" ? ( + +

+
+ {" "} + {this.state.collapsed ? ( + + ) : ( - ) : ( - - )} -
-

-

+ )} +
+

+

- { - let x = this.state.location.pathname.split("/"); - x.shift(); - return x; - })()} - mode="inline" - > - - Slaves - - - - Instances - - - - Users - - - - Roles - - - - Permissions - - - - Settings - - - -
- ) : ( - "" - )} - - { + let x = this.state.location.pathname.split("/"); + x.shift(); + return x; + })()} + mode="inline" > - - - - - - - - - - - - - -
- Clusterio 2.0 web interface https://github.com/clusterio -
-
+ + Slaves + + + + Instances + + + + Users + + + + Roles + + + + Permissions + + + + Settings + + + + + ) : ( + "" + )} + + + + + + + + + + + + + + + + -
+ ); } } diff --git a/packages/master/webpack.config.js b/packages/master/webpack.config.js index ebd45171..4e2dc702 100644 --- a/packages/master/webpack.config.js +++ b/packages/master/webpack.config.js @@ -1,7 +1,6 @@ "use strict"; const path = require("path"); const webpack = require("webpack"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = (env = {}) => ({ @@ -20,9 +19,6 @@ module.exports = (env = {}) => ({ new webpack.DefinePlugin({ "process.env.APP_ENV": JSON.stringify("browser"), }), - new HtmlWebpackPlugin({ - template: "web/index.html", - }), // Make sure ant-design icons use the ES variant new webpack.NormalModuleReplacementPlugin(