Skip to content

Commit

Permalink
RRR Step 2 - Server Rendering (#4669)
Browse files Browse the repository at this point in the history
* First pass at SSR using react-router-dom@6.4
* useLoaderData/useActionData generics + useTransition/useFetcher types
* Remove duped router in favor of 1.0.4-pre.0
  • Loading branch information
brophdawg11 committed Dec 1, 2022
1 parent 902bdbd commit 77e6254
Show file tree
Hide file tree
Showing 14 changed files with 341 additions and 2,758 deletions.
1,011 changes: 164 additions & 847 deletions packages/remix-react/components.tsx

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion packages/remix-react/data.ts
@@ -1,9 +1,11 @@
import type { FormMethod as FormMethodRR } from "react-router-dom";

import invariant from "./invariant";
import type { Submission } from "./transition";

export type AppData = any;

export type FormMethod = "get" | "post" | "put" | "patch" | "delete";
export type FormMethod = FormMethodRR;

export type FormEncType =
| "application/x-www-form-urlencoded"
Expand Down
18 changes: 10 additions & 8 deletions packages/remix-react/entry.ts
@@ -1,20 +1,22 @@
import type { AppState } from "./errors";
import type { StaticHandlerContext } from "@remix-run/router";

import type { RouteManifest, EntryRoute } from "./routes";
import type { RouteData } from "./routeData";
import type { RouteMatch } from "./routeMatching";
import type { RouteModules } from "./routeModules";

export interface EntryContext {
appState: AppState;
// Object passed to RemixContext.Provider
export interface RemixContextObject {
manifest: AssetsManifest;
matches: RouteMatch<EntryRoute>[];
routeData: RouteData;
actionData?: RouteData;
routeModules: RouteModules;
serverHandoffString?: string;
future: FutureConfig;
}

// Additional React-Router information needed at runtime, but not hydrated
// through RemixContext
export interface EntryContext extends RemixContextObject {
staticHandlerContext: StaticHandlerContext;
}

export interface FutureConfig {
v2_meta: boolean;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/remix-react/errorBoundaries.tsx
@@ -1,5 +1,5 @@
import React, { useContext } from "react";
import type { Location } from "react-router-dom";
import type { ErrorResponse, Location } from "react-router-dom";

import type {
CatchBoundaryComponent,
Expand Down Expand Up @@ -124,9 +124,8 @@ export function useCatch<
}

type RemixCatchBoundaryProps = React.PropsWithChildren<{
location: Location;
component: CatchBoundaryComponent;
catch?: ThrownResponse;
catch?: ErrorResponse;
}>;

export function RemixCatchBoundary({
Expand All @@ -135,6 +134,7 @@ export function RemixCatchBoundary({
children,
}: RemixCatchBoundaryProps) {
if (catchVal) {
// TODO: Add Status/Data generics to ErrorResponse?
return (
<RemixCatchContext.Provider value={catchVal}>
<Component />
Expand Down
16 changes: 8 additions & 8 deletions packages/remix-react/index.tsx
@@ -1,30 +1,35 @@
export type { RemixBrowserProps } from "./browser";
export { RemixBrowser } from "./browser";
export type {
FormProps,
Location,
NavigateFunction,
Params,
Path,
SubmitFunction,
SubmitOptions,
} from "react-router-dom";
export {
Form,
Outlet,
useFetchers,
useFormAction,
useHref,
useLocation,
useMatches,
useNavigate,
useNavigationType,
useOutlet,
useOutletContext,
useParams,
useResolvedPath,
useSearchParams,
useSubmit,
} from "react-router-dom";

export type {
FetcherWithComponents,
FormProps,
RouteMatch,
SubmitOptions,
SubmitFunction,
RemixNavLinkProps as NavLinkProps,
RemixLinkProps as LinkProps,
} from "./components";
Expand All @@ -34,18 +39,13 @@ export {
Scripts,
Link,
NavLink,
Form,
PrefetchPageLinks,
LiveReload,
useFormAction,
useSubmit,
useTransition,
useFetcher,
useFetchers,
useLoaderData,
useActionData,
useBeforeUnload,
useMatches,
} from "./components";

export type { FormMethod, FormEncType } from "./data";
Expand Down
56 changes: 31 additions & 25 deletions packages/remix-react/links.ts
@@ -1,10 +1,8 @@
import type { AgnosticDataRouteMatch } from "@remix-run/router";
import type { Location } from "react-router-dom";
import { parsePath } from "react-router-dom";

import type { AssetsManifest } from "./entry";
import type { ClientRoute } from "./routes";
import type { RouteMatch } from "./routeMatching";
// import { matchClientRoutes } from "./routeMatching";
import type { RouteModules, RouteModule } from "./routeModules";
import { loadRouteModule } from "./routeModules";

Expand Down Expand Up @@ -223,7 +221,7 @@ export type LinkDescriptor = HtmlLinkDescriptor | PrefetchPageDescriptor;
* loaded already.
*/
export function getLinksForMatches(
matches: RouteMatch<ClientRoute>[],
matches: AgnosticDataRouteMatch[],
routeModules: RouteModules,
manifest: AssetsManifest
): LinkDescriptor[] {
Expand Down Expand Up @@ -322,12 +320,16 @@ export function isHtmlLinkDescriptor(
}

export async function getStylesheetPrefetchLinks(
matches: RouteMatch<ClientRoute>[],
matches: AgnosticDataRouteMatch[],
manifest: AssetsManifest,
routeModules: RouteModules
): Promise<HtmlLinkDescriptor[]> {
let links = await Promise.all(
matches.map(async (match) => {
let mod = await loadRouteModule(match.route, routeModules);
let mod = await loadRouteModule(
manifest.routes[match.route.id],
routeModules
);
return mod.links ? mod.links() : [];
})
);
Expand All @@ -346,19 +348,20 @@ export async function getStylesheetPrefetchLinks(
// This is ridiculously identical to transition.ts `filterMatchesToLoad`
export function getNewMatchesForLinks(
page: string,
nextMatches: RouteMatch<ClientRoute>[],
currentMatches: RouteMatch<ClientRoute>[],
nextMatches: AgnosticDataRouteMatch[],
currentMatches: AgnosticDataRouteMatch[],
manifest: AssetsManifest,
location: Location,
mode: "data" | "assets"
): RouteMatch<ClientRoute>[] {
): AgnosticDataRouteMatch[] {
let path = parsePathPatch(page);

let isNew = (match: RouteMatch<ClientRoute>, index: number) => {
let isNew = (match: AgnosticDataRouteMatch, index: number) => {
if (!currentMatches[index]) return true;
return match.route.id !== currentMatches[index].route.id;
};

let matchPathChanged = (match: RouteMatch<ClientRoute>, index: number) => {
let matchPathChanged = (match: AgnosticDataRouteMatch, index: number) => {
return (
// param change, /users/123 -> /users/456
currentMatches[index].pathname !== match.pathname ||
Expand All @@ -376,29 +379,32 @@ export function getNewMatchesForLinks(
? // this is really similar to stuff in transition.ts, maybe somebody smarter
// than me (or in less of a hurry) can share some of it. You're the best.
nextMatches.filter((match, index) => {
if (!match.route.hasLoader) {
let manifestRoute = manifest.routes[match.route.id];
if (!manifestRoute.hasLoader) {
return false;
}

if (isNew(match, index) || matchPathChanged(match, index)) {
return true;
}

if (match.route.shouldReload) {
return match.route.shouldReload({
params: match.params,
prevUrl: new URL(
location.pathname + location.search + location.hash,
window.origin
),
url: new URL(page, window.origin),
});
if (match.route.shouldRevalidate) {
// TODO: Implement
// return match.route.shouldRevalidate({
// params: match.params,
// prevUrl: new URL(
// location.pathname + location.search + location.hash,
// window.origin
// ),
// url: new URL(page, window.origin),
// });
}
return true;
})
: nextMatches.filter((match, index) => {
let manifestRoute = manifest.routes[match.route.id];
return (
(mode === "assets" || match.route.hasLoader) &&
(mode === "assets" || manifestRoute.hasLoader) &&
(isNew(match, index) || matchPathChanged(match, index))
);
});
Expand All @@ -408,7 +414,7 @@ export function getNewMatchesForLinks(

export function getDataLinkHrefs(
page: string,
matches: RouteMatch<ClientRoute>[],
matches: AgnosticDataRouteMatch[],
manifest: AssetsManifest
): string[] {
let path = parsePathPatch(page);
Expand All @@ -425,7 +431,7 @@ export function getDataLinkHrefs(
}

export function getModuleLinkHrefs(
matches: RouteMatch<ClientRoute>[],
matches: AgnosticDataRouteMatch[],
manifestPatch: AssetsManifest
): string[] {
return dedupeHrefs(
Expand All @@ -446,7 +452,7 @@ export function getModuleLinkHrefs(
// need to include them in a page prefetch, this gives us the list to remove
// while deduping.
function getCurrentPageModulePreloadHrefs(
matches: RouteMatch<ClientRoute>[],
matches: AgnosticDataRouteMatch[],
manifest: AssetsManifest
): string[] {
return dedupeHrefs(
Expand Down
24 changes: 0 additions & 24 deletions packages/remix-react/routeMatching.ts

This file was deleted.

0 comments on commit 77e6254

Please sign in to comment.