-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update Remix to use route.lazy from React Router #7133
Changes from all commits
d532179
16c9364
37f0947
f176cf9
4f1e0b8
12bb75c
a543449
d29615b
67fa0f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@remix-run/react": minor | ||
"@remix-run/server-runtime": minor | ||
"@remix-run/testing": minor | ||
--- | ||
|
||
Update Remix to use React Router `route.lazy` for module loading |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,25 +14,21 @@ import { | |
Await as AwaitRR, | ||
Link as RouterLink, | ||
NavLink as RouterNavLink, | ||
Outlet, | ||
UNSAFE_DataRouterContext as DataRouterContext, | ||
UNSAFE_DataRouterStateContext as DataRouterStateContext, | ||
matchRoutes, | ||
useAsyncError, | ||
useActionData as useActionDataRR, | ||
useLoaderData as useLoaderDataRR, | ||
useRouteLoaderData as useRouteLoaderDataRR, | ||
useMatches as useMatchesRR, | ||
useLocation, | ||
useNavigation, | ||
useHref, | ||
useRouteError, | ||
} from "react-router-dom"; | ||
import type { SerializeFrom } from "@remix-run/server-runtime"; | ||
|
||
import type { AppData } from "./data"; | ||
import type { RemixContextObject } from "./entry"; | ||
import { RemixRootDefaultErrorBoundary } from "./errorBoundaries"; | ||
import invariant from "./invariant"; | ||
import { | ||
getDataLinkHrefs, | ||
|
@@ -83,55 +79,6 @@ function useRemixContext(): RemixContextObject { | |
return context; | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// RemixRoute | ||
|
||
export function RemixRoute({ id }: { id: string }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The only downside is we lose these error messages - so if we think they are worth keeping we can stick with this approach. |
||
let { routeModules } = useRemixContext(); | ||
|
||
invariant( | ||
routeModules, | ||
"Cannot initialize 'routeModules'. This normally occurs when you have server code in your client modules.\n" + | ||
"Check this link for more details:\nhttps://remix.run/pages/gotchas#server-code-in-client-bundles" | ||
); | ||
|
||
let { default: Component, ErrorBoundary } = routeModules[id]; | ||
|
||
// Default Component to Outlet if we expose boundary UI components | ||
if (!Component && ErrorBoundary) { | ||
Component = Outlet; | ||
} | ||
|
||
invariant( | ||
Component, | ||
`Route "${id}" has no component! Please go add a \`default\` export in the route module file.\n` + | ||
"If you were trying to navigate or submit to a resource route, use `<a>` instead of `<Link>` or `<Form reloadDocument>`." | ||
); | ||
|
||
return <Component />; | ||
} | ||
|
||
export function RemixRouteError({ id }: { id: string }) { | ||
let { routeModules } = useRemixContext(); | ||
|
||
// This checks prevent cryptic error messages such as: 'Cannot read properties of undefined (reading 'root')' | ||
invariant( | ||
routeModules, | ||
"Cannot initialize 'routeModules'. This normally occurs when you have server code in your client modules.\n" + | ||
"Check this link for more details:\nhttps://remix.run/pages/gotchas#server-code-in-client-bundles" | ||
); | ||
|
||
let error = useRouteError(); | ||
let { ErrorBoundary } = routeModules[id]; | ||
|
||
if (ErrorBoundary) { | ||
return <ErrorBoundary />; | ||
} else if (id === "root") { | ||
return <RemixRootDefaultErrorBoundary error={error} />; | ||
} | ||
|
||
throw error; | ||
} | ||
//////////////////////////////////////////////////////////////////////////////// | ||
// Public API | ||
|
||
|
@@ -1050,27 +997,6 @@ export interface RouteMatch { | |
handle: undefined | { [key: string]: any }; | ||
} | ||
|
||
export function useMatches(): RouteMatch[] { | ||
let { routeModules } = useRemixContext(); | ||
let matches = useMatchesRR(); | ||
return React.useMemo( | ||
() => | ||
matches.map((match) => { | ||
let remixMatch: RouteMatch = { | ||
id: match.id, | ||
pathname: match.pathname, | ||
params: match.params, | ||
data: match.data, | ||
// Need to grab handle here since we don't have it at client-side route | ||
// creation time | ||
handle: routeModules[match.id].handle, | ||
Comment on lines
-1064
to
-1066
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No longer need to grab |
||
}; | ||
return remixMatch; | ||
}), | ||
[matches, routeModules] | ||
); | ||
} | ||
|
||
/** | ||
* Returns the JSON parsed data from the current route's `loader`. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this we get into I think the same hydration error loop as #1678. I hope to dig deeper into that later today/tomorrow so maybe it'll shed some light on why we need the short circuit, but once I move this up and return (and avoid any router initialization + lazy calls on the wrong route) the E2E test passes and all of my manual testing with rapid forward clicks into a Remix app to cause a mismatched URL at hydration time settle correctly on the final URL after the hard reload.