Created
December 6, 2023 15:47
-
-
Save kale1d0code/6fec7abec7c921d67e7d4463f155d17d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
createRouter, | |
createBrowserHistory, | |
UNSAFE_ErrorResponseImpl as ErrorResponseImpl | |
} from "@remix-run/router"; | |
import { | |
RouteObject, | |
UNSAFE_mapRouteProperties as mapRouteProperties, | |
} from "react-router"; | |
import type { | |
FutureConfig as RouterFutureConfig, | |
HydrationState, | |
Router as RemixRouter, | |
History | |
} from "@remix-run/router"; | |
declare global { | |
var __staticRouterHydrationData: HydrationState | undefined; | |
} | |
interface DOMRouterOpts { | |
basename?: string; | |
future?: Partial<Omit<RouterFutureConfig, "v7_prependBasename">>; | |
hydrationData?: HydrationState; | |
window?: Window; | |
} | |
const createHistoryRouter = (history: History) => ( | |
routes: RouteObject[], | |
opts?: DOMRouterOpts | |
): RemixRouter => { | |
const router = createRouter({ | |
basename: opts?.basename, | |
future: { | |
...opts?.future, | |
v7_prependBasename: true, | |
}, | |
history: history ?? createBrowserHistory({ window: opts?.window }), | |
hydrationData: opts?.hydrationData || parseHydrationData(), | |
routes, | |
mapRouteProperties, | |
}).initialize(); | |
return router; | |
} | |
function parseHydrationData(): HydrationState | undefined { | |
let state = window?.__staticRouterHydrationData; | |
if (state && state.errors) { | |
state = { | |
...state, | |
errors: deserializeErrors(state.errors), | |
}; | |
} | |
return state; | |
} | |
function deserializeErrors( | |
errors: RemixRouter["state"]["errors"] | |
): RemixRouter["state"]["errors"] { | |
if (!errors) return null; | |
let entries = Object.entries(errors); | |
let serialized: RemixRouter["state"]["errors"] = {}; | |
for (let [key, val] of entries) { | |
// Hey you! If you change this, please change the corresponding logic in | |
// serializeErrors in react-router-dom/server.tsx :) | |
if (val && val.__type === "RouteErrorResponse") { | |
serialized[key] = new ErrorResponseImpl( | |
val.status, | |
val.statusText, | |
val.data, | |
val.internal === true | |
); | |
} else if (val && val.__type === "Error") { | |
// Attempt to reconstruct the right type of Error (i.e., ReferenceError) | |
if (val.__subType) { | |
let ErrorConstructor = window[val.__subType]; | |
if (typeof ErrorConstructor === "function") { | |
try { | |
//@ts-expect-error | |
let error = new ErrorConstructor(val.message); | |
// Wipe away the client-side stack trace. Nothing to fill it in with | |
// because we don't serialize SSR stack traces for security reasons | |
error.stack = ""; | |
serialized[key] = error; | |
} catch (e) { | |
// no-op - fall through and create a normal Error | |
} | |
} | |
} | |
if (serialized[key] == null) { | |
let error = new Error(val.message); | |
// Wipe away the client-side stack trace. Nothing to fill it in with | |
// because we don't serialize SSR stack traces for security reasons | |
error.stack = ""; | |
serialized[key] = error; | |
} | |
} else { | |
serialized[key] = val; | |
} | |
} | |
return serialized; | |
} | |
export { | |
createHistoryRouter | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I haven't shown my store configuration file however | |
all you need to do is call createReduxHistoryContext as normal | |
and call the wrapHistory function on the history instance that is returned from createReduxHistoryContext. | |
you can then pass the modified history instance that wrapHistory returned into your react-router 6.4 router | |
(wrap history adds the encodeLocation and createURL methods to the history instance that is required by the react-router 6.4 routers) | |
//@ts-expect-error in the router file is due to me not being able to find the correct types for history with encodeLocation and createURL from the react-router library. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ComponentType } from "react"; | |
import { createHistoryRouter } from "./custom-history-router.ts"; | |
import routes from "./routes"; | |
import { RouterProvider } from "react-router"; | |
import { ReduxNavtionHistory } from "../../data/utilities/wrap-history"; | |
export type PropsWithHistory<P> = P & { history: ReduxNavtionHistory }; | |
const Router: ComponentType<PropsWithHistory<{}>> = ({ history }) => { | |
//@ts-expect-error | |
const browserRouter = createHistoryRouter(history); | |
const router = browserRouter(routes, { | |
future: { v7_normalizeFormMethod: true }, | |
}); | |
return <RouterProvider router={router} />; | |
}; | |
export default Router; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createPath } from "@remix-run/router"; | |
import { To } from "react-router"; | |
import { IHistoryContext } from "redux-first-history"; | |
export function invariant(value: boolean, message?: string): asserts value; | |
export function invariant<T>( | |
value: T | null | undefined, | |
message?: string, | |
): asserts value is T; | |
export function invariant(value: any, message?: string) { | |
if (value === false || value === null || typeof value === "undefined") { | |
throw new Error(message); | |
} | |
} | |
function createURL(to: To): URL { | |
// window.location.origin is "null" (the literal string value) in Firefox | |
// under certain conditions, notably when serving from a local HTML file | |
// See https://bugzilla.mozilla.org/show_bug.cgi?id=878297 | |
let base = | |
window.location.origin !== "null" | |
? window.location.origin | |
: window.location.href; | |
let href = typeof to === "string" ? to : createPath(to); | |
invariant( | |
base, | |
`No window.location.(origin|href) available to create URL for href: ${href}`, | |
); | |
return new URL(href, base); | |
} | |
function encodeLocation(to: To) { | |
// Encode a Location the same way window.location would | |
let url = createURL(to); | |
return { | |
pathname: url.pathname, | |
search: url.search, | |
hash: url.hash, | |
}; | |
} | |
type HF = IHistoryContext["createReduxHistory"]; | |
export type ReduxNavtionHistory = ReturnType<HF>; | |
const wrapHistory = (history: ReduxNavtionHistory): ReduxNavtionHistory => { | |
const newHistory: ReduxNavtionHistory = Object.assign({ | |
...history, | |
encodeLocation, | |
createURL, | |
}); | |
return newHistory; | |
}; | |
export default wrapHistory; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment