Skip to content

Commit 77e6254

Browse files
committed
RRR Step 2 - Server Rendering (#4669)
* First pass at SSR using [email protected] * useLoaderData/useActionData generics + useTransition/useFetcher types * Remove duped router in favor of 1.0.4-pre.0
1 parent 902bdbd commit 77e6254

File tree

14 files changed

+341
-2758
lines changed

14 files changed

+341
-2758
lines changed

packages/remix-react/components.tsx

Lines changed: 164 additions & 847 deletions
Large diffs are not rendered by default.

packages/remix-react/data.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import type { FormMethod as FormMethodRR } from "react-router-dom";
2+
13
import invariant from "./invariant";
24
import type { Submission } from "./transition";
35

46
export type AppData = any;
57

6-
export type FormMethod = "get" | "post" | "put" | "patch" | "delete";
8+
export type FormMethod = FormMethodRR;
79

810
export type FormEncType =
911
| "application/x-www-form-urlencoded"

packages/remix-react/entry.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
import type { AppState } from "./errors";
1+
import type { StaticHandlerContext } from "@remix-run/router";
2+
23
import type { RouteManifest, EntryRoute } from "./routes";
3-
import type { RouteData } from "./routeData";
4-
import type { RouteMatch } from "./routeMatching";
54
import type { RouteModules } from "./routeModules";
65

7-
export interface EntryContext {
8-
appState: AppState;
6+
// Object passed to RemixContext.Provider
7+
export interface RemixContextObject {
98
manifest: AssetsManifest;
10-
matches: RouteMatch<EntryRoute>[];
11-
routeData: RouteData;
12-
actionData?: RouteData;
139
routeModules: RouteModules;
1410
serverHandoffString?: string;
1511
future: FutureConfig;
1612
}
1713

14+
// Additional React-Router information needed at runtime, but not hydrated
15+
// through RemixContext
16+
export interface EntryContext extends RemixContextObject {
17+
staticHandlerContext: StaticHandlerContext;
18+
}
19+
1820
export interface FutureConfig {
1921
v2_meta: boolean;
2022
}

packages/remix-react/errorBoundaries.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useContext } from "react";
2-
import type { Location } from "react-router-dom";
2+
import type { ErrorResponse, Location } from "react-router-dom";
33

44
import type {
55
CatchBoundaryComponent,
@@ -124,9 +124,8 @@ export function useCatch<
124124
}
125125

126126
type RemixCatchBoundaryProps = React.PropsWithChildren<{
127-
location: Location;
128127
component: CatchBoundaryComponent;
129-
catch?: ThrownResponse;
128+
catch?: ErrorResponse;
130129
}>;
131130

132131
export function RemixCatchBoundary({
@@ -135,6 +134,7 @@ export function RemixCatchBoundary({
135134
children,
136135
}: RemixCatchBoundaryProps) {
137136
if (catchVal) {
137+
// TODO: Add Status/Data generics to ErrorResponse?
138138
return (
139139
<RemixCatchContext.Provider value={catchVal}>
140140
<Component />

packages/remix-react/index.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
11
export type { RemixBrowserProps } from "./browser";
22
export { RemixBrowser } from "./browser";
33
export type {
4+
FormProps,
45
Location,
56
NavigateFunction,
67
Params,
78
Path,
9+
SubmitFunction,
10+
SubmitOptions,
811
} from "react-router-dom";
912
export {
13+
Form,
1014
Outlet,
15+
useFetchers,
16+
useFormAction,
1117
useHref,
1218
useLocation,
19+
useMatches,
1320
useNavigate,
1421
useNavigationType,
1522
useOutlet,
1623
useOutletContext,
1724
useParams,
1825
useResolvedPath,
1926
useSearchParams,
27+
useSubmit,
2028
} from "react-router-dom";
2129

2230
export type {
2331
FetcherWithComponents,
24-
FormProps,
2532
RouteMatch,
26-
SubmitOptions,
27-
SubmitFunction,
2833
RemixNavLinkProps as NavLinkProps,
2934
RemixLinkProps as LinkProps,
3035
} from "./components";
@@ -34,18 +39,13 @@ export {
3439
Scripts,
3540
Link,
3641
NavLink,
37-
Form,
3842
PrefetchPageLinks,
3943
LiveReload,
40-
useFormAction,
41-
useSubmit,
4244
useTransition,
4345
useFetcher,
44-
useFetchers,
4546
useLoaderData,
4647
useActionData,
4748
useBeforeUnload,
48-
useMatches,
4949
} from "./components";
5050

5151
export type { FormMethod, FormEncType } from "./data";

packages/remix-react/links.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1+
import type { AgnosticDataRouteMatch } from "@remix-run/router";
12
import type { Location } from "react-router-dom";
23
import { parsePath } from "react-router-dom";
34

45
import type { AssetsManifest } from "./entry";
5-
import type { ClientRoute } from "./routes";
6-
import type { RouteMatch } from "./routeMatching";
7-
// import { matchClientRoutes } from "./routeMatching";
86
import type { RouteModules, RouteModule } from "./routeModules";
97
import { loadRouteModule } from "./routeModules";
108

@@ -223,7 +221,7 @@ export type LinkDescriptor = HtmlLinkDescriptor | PrefetchPageDescriptor;
223221
* loaded already.
224222
*/
225223
export function getLinksForMatches(
226-
matches: RouteMatch<ClientRoute>[],
224+
matches: AgnosticDataRouteMatch[],
227225
routeModules: RouteModules,
228226
manifest: AssetsManifest
229227
): LinkDescriptor[] {
@@ -322,12 +320,16 @@ export function isHtmlLinkDescriptor(
322320
}
323321

324322
export async function getStylesheetPrefetchLinks(
325-
matches: RouteMatch<ClientRoute>[],
323+
matches: AgnosticDataRouteMatch[],
324+
manifest: AssetsManifest,
326325
routeModules: RouteModules
327326
): Promise<HtmlLinkDescriptor[]> {
328327
let links = await Promise.all(
329328
matches.map(async (match) => {
330-
let mod = await loadRouteModule(match.route, routeModules);
329+
let mod = await loadRouteModule(
330+
manifest.routes[match.route.id],
331+
routeModules
332+
);
331333
return mod.links ? mod.links() : [];
332334
})
333335
);
@@ -346,19 +348,20 @@ export async function getStylesheetPrefetchLinks(
346348
// This is ridiculously identical to transition.ts `filterMatchesToLoad`
347349
export function getNewMatchesForLinks(
348350
page: string,
349-
nextMatches: RouteMatch<ClientRoute>[],
350-
currentMatches: RouteMatch<ClientRoute>[],
351+
nextMatches: AgnosticDataRouteMatch[],
352+
currentMatches: AgnosticDataRouteMatch[],
353+
manifest: AssetsManifest,
351354
location: Location,
352355
mode: "data" | "assets"
353-
): RouteMatch<ClientRoute>[] {
356+
): AgnosticDataRouteMatch[] {
354357
let path = parsePathPatch(page);
355358

356-
let isNew = (match: RouteMatch<ClientRoute>, index: number) => {
359+
let isNew = (match: AgnosticDataRouteMatch, index: number) => {
357360
if (!currentMatches[index]) return true;
358361
return match.route.id !== currentMatches[index].route.id;
359362
};
360363

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

383387
if (isNew(match, index) || matchPathChanged(match, index)) {
384388
return true;
385389
}
386390

387-
if (match.route.shouldReload) {
388-
return match.route.shouldReload({
389-
params: match.params,
390-
prevUrl: new URL(
391-
location.pathname + location.search + location.hash,
392-
window.origin
393-
),
394-
url: new URL(page, window.origin),
395-
});
391+
if (match.route.shouldRevalidate) {
392+
// TODO: Implement
393+
// return match.route.shouldRevalidate({
394+
// params: match.params,
395+
// prevUrl: new URL(
396+
// location.pathname + location.search + location.hash,
397+
// window.origin
398+
// ),
399+
// url: new URL(page, window.origin),
400+
// });
396401
}
397402
return true;
398403
})
399404
: nextMatches.filter((match, index) => {
405+
let manifestRoute = manifest.routes[match.route.id];
400406
return (
401-
(mode === "assets" || match.route.hasLoader) &&
407+
(mode === "assets" || manifestRoute.hasLoader) &&
402408
(isNew(match, index) || matchPathChanged(match, index))
403409
);
404410
});
@@ -408,7 +414,7 @@ export function getNewMatchesForLinks(
408414

409415
export function getDataLinkHrefs(
410416
page: string,
411-
matches: RouteMatch<ClientRoute>[],
417+
matches: AgnosticDataRouteMatch[],
412418
manifest: AssetsManifest
413419
): string[] {
414420
let path = parsePathPatch(page);
@@ -425,7 +431,7 @@ export function getDataLinkHrefs(
425431
}
426432

427433
export function getModuleLinkHrefs(
428-
matches: RouteMatch<ClientRoute>[],
434+
matches: AgnosticDataRouteMatch[],
429435
manifestPatch: AssetsManifest
430436
): string[] {
431437
return dedupeHrefs(
@@ -446,7 +452,7 @@ export function getModuleLinkHrefs(
446452
// need to include them in a page prefetch, this gives us the list to remove
447453
// while deduping.
448454
function getCurrentPageModulePreloadHrefs(
449-
matches: RouteMatch<ClientRoute>[],
455+
matches: AgnosticDataRouteMatch[],
450456
manifest: AssetsManifest
451457
): string[] {
452458
return dedupeHrefs(

packages/remix-react/routeMatching.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)