Use relative paths for router links (#672)

Summary:
As the next step for #643, this patch enables the app to be rendered at
non-root gateways by incorporating the relative-path history
implementation developed in #666. The app is not fully functional:
our React components do not yet know how to resolve assets, and so
fetches of resources like the repository will be against the wrong URLs.

Test Plan:
  - Note that `yarn start` still works.
  - Run `./scripts/build_static_site.sh` to build the site into, say,
    `/tmp/gateway`.
  - Run a static web server from `/tmp/gateway/` and note that (a) the
    paths listed in the page source are relative, and (b) everything
    works as intended, with no console messages in either Chrome or
    Firefox.
  - Run a static web server from `/tmp/` and navigate to `/gateway/` in
    the browser. Note that the app loads properly, and that refreshes
    work (i.e., the `pushState` paths are real paths). Note that the
    repository registry cannot yet be loaded, and so PageRank cannot be
    run.

wchargin-branch: relative-router
This commit is contained in:
William Chargin 2018-08-15 15:35:12 -07:00 committed by GitHub
parent 91f0459753
commit ce2867a8d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 9 deletions

View File

@ -1,16 +1,17 @@
// @flow
import React from "react";
import {Router, browserHistory} from "react-router";
import {Router} from "react-router";
import type {History /* actually `any` */} from "history";
import {createRoutes} from "./createRoutes";
import {resolveTitleFromPath} from "./routeData";
export default class App extends React.Component<{}> {
export default class App extends React.Component<{|+history: History|}> {
render() {
return (
<Router
history={browserHistory}
history={this.props.history}
routes={createRoutes()}
onUpdate={function() {
const router = this;

View File

@ -1,14 +1,31 @@
// @flow
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import createBrowserHistory from "history/lib/createBrowserHistory";
import createRelativeHistory from "./createRelativeHistory";
import normalize from "../util/pathNormalize";
import App from "./App";
const root = document.getElementById("root");
if (root == null) {
import "./index.css";
const target = document.getElementById("root");
if (target == null) {
throw new Error("Unable to find root element!");
}
ReactDOM.hydrate(<App />, root);
let initialRoot: string = target.dataset.initialRoot;
if (initialRoot == null) {
console.error(
`Initial root unset (${initialRoot}): this should not happen! ` +
'Falling back to ".".'
);
initialRoot = ".";
}
const basename = normalize(`${window.location.pathname}/${initialRoot}/`);
const history = createRelativeHistory(createBrowserHistory(), basename);
ReactDOM.hydrate(<App history={history} />, target);
// In Chrome, relative favicon URLs are recomputed at every pushState,
// although other assets (like the `src` of an `img`) are not. We don't

View File

@ -1,12 +1,14 @@
// @flow
import {StyleSheetServer} from "aphrodite/no-important";
import createMemoryHistory from "history/lib/createMemoryHistory";
import React from "react";
import ReactDOMServer from "react-dom/server";
import {match, RouterContext} from "react-router";
import Page from "./Page";
import {Assets, rootFromPath} from "./assets";
import createRelativeHistory from "./createRelativeHistory";
import ExternalRedirect from "./ExternalRedirect";
import {createRoutes} from "./createRoutes";
import {resolveRouteFromPath, resolveTitleFromPath} from "./routeData";
@ -19,6 +21,7 @@ export default function render(
const path = locals.path;
const root = rootFromPath(path);
const assets = new Assets(root);
const history = createRelativeHistory(createMemoryHistory(path), "/");
{
const route = resolveRouteFromPath(path);
if (route && route.contents.type === "EXTERNAL_REDIRECT") {
@ -31,7 +34,7 @@ export default function render(
function renderStandardRoute() {
const bundlePath = locals.assets["main"];
const routes = createRoutes();
match({routes, location: path}, (error, redirectLocation, renderProps) => {
match({history, routes}, (error, redirectLocation, renderProps) => {
if (error) {
callback(error);
} else if (renderProps) {
@ -53,7 +56,7 @@ export default function render(
<style data-aphrodite>${css.content}</style>
</head>
<body style="overflow-y:scroll">
<div id="root">${html}</div>
<div id="root" data-initial-root="${root}">${html}</div>
<script src="${assets.resolve(bundlePath)}"></script>
</body>
</html>