Make route path data available in vanilla context

Test Plan:
Ensure that `require("./src/app/routeData")` works in `node` without any
preprocessing. Ensure that `yarn start` works, and that `yarn build`
then `node ./bin/sourcecred.js start` also works.

wchargin-branch: vanilla-route-data
This commit is contained in:
William Chargin 2018-07-21 10:16:42 -07:00
parent b41009b1f7
commit 73e36b2ab2
6 changed files with 75 additions and 61 deletions

View File

@ -3,7 +3,8 @@
import React from "react";
import {Router, browserHistory} from "react-router";
import {createRoutes, resolveTitleFromPath} from "./routes";
import {createRoutes} from "./createRoutes";
import {resolveTitleFromPath} from "./routeData";
export default class App extends React.Component<{}> {
render() {

View File

@ -3,7 +3,7 @@
import React, {type Node} from "react";
import {Link} from "react-router";
import {routeData} from "./routes";
import {routeData} from "./routeData";
import * as NullUtil from "../util/null";
export default class Page extends React.Component<{|+children: Node|}> {

21
src/app/createRoutes.js Normal file
View File

@ -0,0 +1,21 @@
// @flow
import React from "react";
import {IndexRoute, Route} from "react-router";
import Page from "./Page";
import {routeData} from "./routeData";
export function createRoutes() {
return (
<Route path="/" component={Page}>
{routeData.map(({path, component}) => {
if (path === "/") {
return <IndexRoute key={path} component={component()} />;
} else {
return <Route key={path} path={path} component={component()} />;
}
})}
</Route>
);
}

49
src/app/routeData.js Normal file
View File

@ -0,0 +1,49 @@
// @flow
// NOTE: This module must be written in vanilla ECMAScript that can be
// run by Node without a preprocessor. That means that we use `exports`
// and `require` instead of ECMAScript module keywords, we lazy-load all
// dependent modules, and we use the Flow comment syntax instead of the
// inline syntax.
/*::
type RouteDatum = {|
+path: string,
+component: () => React$ComponentType<{||}>,
+title: string,
+navTitle: ?string,
|};
*/
const routeData /*: $ReadOnlyArray<RouteDatum> */ = [
{
path: "/",
component: () => require("./HomePage").default,
title: "SourceCred",
navTitle: "Home",
},
{
path: "/explorer",
component: () => require("./credExplorer/App").default,
title: "SourceCred explorer",
navTitle: "Explorer",
},
];
exports.routeData = routeData;
function resolveRouteFromPath(path /*: string */) /*: ?RouteDatum */ {
const matches = (candidateRoute) => {
const candidatePath = candidateRoute.path;
const start = path.substring(0, candidatePath.length);
const end = path.substring(candidatePath.length);
return start === candidatePath && (end.length === 0 || end === "/");
};
return routeData.filter(matches)[0] || null;
}
function resolveTitleFromPath(path /*: string */) /*: string */ {
const route = resolveRouteFromPath(path);
const fallback = "SourceCred";
return route ? route.title : fallback;
}
exports.resolveTitleFromPath = resolveTitleFromPath;

View File

@ -1,58 +0,0 @@
// @flow
import React from "react";
import {IndexRoute, Route} from "react-router";
import Page from "./Page";
type RouteDatum = {|
+path: string,
+component: React$ComponentType<{||}>,
+title: string,
+navTitle: ?string,
|};
export const routeData: $ReadOnlyArray<RouteDatum> = [
{
path: "/",
component: require("./HomePage").default,
title: "SourceCred",
navTitle: "Home",
},
{
path: "/explorer",
component: require("./credExplorer/App").default,
title: "SourceCred explorer",
navTitle: "Explorer",
},
];
export function createRoutes() {
return (
<Route path="/" component={Page}>
{routeData.map(({path, component}) => {
if (path === "/") {
return <IndexRoute key={path} component={component} />;
} else {
return <Route key={path} path={path} component={component} />;
}
})}
</Route>
);
}
function resolveRouteFromPath(path: string): ?RouteDatum {
const matches = (candidateRoute) => {
const candidatePath = candidateRoute.path;
const start = path.substring(0, candidatePath.length);
const end = path.substring(candidatePath.length);
return start === candidatePath && (end.length === 0 || end === "/");
};
return routeData.filter(matches)[0] || null;
}
export function resolveTitleFromPath(path: string): string {
const route = resolveRouteFromPath(path);
const fallback = "SourceCred";
return route ? route.title : fallback;
}

View File

@ -5,7 +5,8 @@ import React from "react";
import ReactDOMServer from "react-dom/server";
import {match, RouterContext} from "react-router";
import {createRoutes, resolveTitleFromPath} from "./routes";
import {createRoutes} from "./createRoutes";
import {resolveTitleFromPath} from "./routeData";
import dedent from "./dedent";
export default function render(