Skip to content

Instantly share code, notes, and snippets.

@reyronald
Last active November 20, 2022 11:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reyronald/924b2449d732701666692aa0c6e09ffa to your computer and use it in GitHub Desktop.
Save reyronald/924b2449d732701666692aa0c6e09ffa to your computer and use it in GitHub Desktop.
import React from "react";
import { BrowserRouter, Redirect } from "react-router-dom";
import { CompatRouter, Routes, Route } from "react-router-dom-v5-compat";
import { Internal1 } from "./Internal1";
import { Loadable } from "./Loadable";
const Loading = () => (
<div style={{ width: "100%", height: "100vh", background: "red" }}>Loading</div>
);
const InternalsPack = Loadable(
// factory
() => import("./Internals.Bundle"),
{
fallback: <Loading />,
},
);
const Internal2 = InternalsPack((bundle) => bundle.Internal2);
const Internal3 = InternalsPack((bundle) => bundle.Internal3);
// Or...
// const factory = () => import("./Internals.Bundle");
// const Internal2 = React.lazy(lazyBundle(factory, (b) => b.Internal2));
// const Internal3 = React.lazy(lazyBundle(factory, (b) => b.Internal3));
const Internal4 = React.lazy(() => import("./Internal4"));
export const AppRouterExperiment = () => {
return (
<BrowserRouter>
<CompatRouter>
<AppRoutes />
</CompatRouter>
</BrowserRouter>
);
};
const AppRoutes = () => {
return (
<Routes>
<Route path={"/internal/1"} element={<Internal1 />} />
<Route path={"/internal/2"} element={<Internal2 name="Ronald" />} />
<Route path={"/internal/3"} element={<Internal3 />} />
<Route path={"/internal/4"} element={<Internal4 />} />
<Route path="*" element={<Redirect to={"/internal/1"} />} />
</Routes>
);
};
export function lazyBundle<T, C extends ComponentType<any>>(
factory: () => Promise<{ default: T }>,
getModule: (bundle: T) => C,
) {
return async () => {
const bundle = await factory();
const component = getModule(bundle.default);
return { default: component };
};
}
import React from "react";
import type { ComponentType, ReactElement } from "react";
const _cache = new WeakMap<
() => Promise<{ default: any }>,
{
default: any;
}
>();
export function Loadable<T>(
importBundle: () => Promise<{ default: T }>,
options: {
fallback?: ReactElement | null;
} = {
fallback: null,
},
) {
return <C extends ComponentType<any>>(getComponent: (bundle: T) => C) => {
function LazyComponent(props: any) {
const [Component, setComponent] = React.useState<C | undefined>(() => {
const bundle = _cache.get(importBundle);
if (bundle) {
return getComponent(bundle.default);
}
});
// eslint-disable-next-line use-encapsulation/prefer-custom-hooks -- .
React.useEffect(() => {
async function fetch() {
const bundle = await importBundle();
_cache.set(importBundle, bundle);
const component = getComponent(bundle.default);
setComponent(() => component);
}
if (!Component) {
void fetch();
}
}, [Component]);
if (!Component) {
return options.fallback || null;
}
return <Component {...props} />;
}
LazyComponent.displayName = `LazyComponent`;
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- .
return LazyComponent as C;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment