@modern-js/runtime-utils
Version:
A Progressive React Framework for modern web development.
106 lines (105 loc) • 4.37 kB
JavaScript
import "node:module";
import { jsx } from "react/jsx-runtime";
import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
import { Suspense } from "react";
import { Outlet, Route, createRoutesFromElements } from "react-router";
import { time } from "../time.mjs";
import { getAsyncLocalStorage } from "../universal/async_storage.mjs";
import { DeferredData, activeDeferreds as external_deferreds_mjs_activeDeferreds } from "./deferreds.mjs";
const privateDefer = (data)=>new DeferredData(data);
const transformNestedRoutes = (routes)=>{
const routeElements = [];
for (const route of routes){
const routeElement = renderNestedRoute(route);
routeElements.push(routeElement);
}
return createRoutesFromElements(routeElements);
};
const renderNestedRoute = (nestedRoute, options = {})=>{
const { children, index, id, component, isRoot, lazyImport, config, handle } = nestedRoute;
const Component = component;
const { parent, props = {} } = options;
const routeProps = {
caseSensitive: nestedRoute.caseSensitive,
path: nestedRoute.path,
id: nestedRoute.id,
loader: createLoader(nestedRoute),
action: nestedRoute.action,
hasErrorBoundary: nestedRoute.hasErrorBoundary,
shouldRevalidate: nestedRoute.shouldRevalidate,
handle: {
...handle,
...'object' == typeof config ? config?.handle : {}
},
index: nestedRoute.index,
element: nestedRoute.element,
errorElement: nestedRoute.errorElement
};
if (nestedRoute.error) {
const errorElement = /*#__PURE__*/ jsx(nestedRoute.error, {});
routeProps.errorElement = errorElement;
}
let element;
if (Component) if (parent?.loading && lazyImport) {
const Loading = parent.loading;
element = isLoadableComponent(Component) ? /*#__PURE__*/ jsx(Component, {
fallback: /*#__PURE__*/ jsx(Loading, {})
}) : /*#__PURE__*/ jsx(Suspense, {
fallback: /*#__PURE__*/ jsx(Loading, {}),
children: /*#__PURE__*/ jsx(Component, {})
});
} else element = isLoadableComponent(Component) && lazyImport ? /*#__PURE__*/ jsx(Component, {}) : isRoot ? /*#__PURE__*/ jsx(Component, {
...props
}) : lazyImport ? /*#__PURE__*/ jsx(Suspense, {
fallback: null,
children: /*#__PURE__*/ jsx(Component, {})
}) : /*#__PURE__*/ jsx(Component, {});
else {
nestedRoute.loading = parent?.loading;
routeProps.element = /*#__PURE__*/ jsx(Outlet, {});
}
if (element) routeProps.element = element;
const childElements = children?.map((childRoute)=>renderNestedRoute(childRoute, {
parent: nestedRoute
}));
const routeElement = index ? /*#__PURE__*/ jsx(Route, {
...routeProps,
index: true
}, id) : /*#__PURE__*/ jsx(Route, {
...routeProps,
index: false,
children: childElements
}, id);
return routeElement;
};
function isPlainObject(value) {
return null != value && 'object' == typeof value && Object.getPrototypeOf(value) === Object.prototype;
}
function createLoader(route) {
const { loader } = route;
if (loader) return async (args)=>{
if ('function' == typeof route.lazyImport) route.lazyImport();
const end = time();
const res = await loader(args);
let activeDeferreds = null;
activeDeferreds = "u" < typeof document ? (await getAsyncLocalStorage())?.useContext()?.activeDeferreds : external_deferreds_mjs_activeDeferreds;
if (isPlainObject(res)) {
const deferredData = privateDefer(res);
activeDeferreds.set(route.id, deferredData);
}
const cost = end();
if ("u" < typeof document) {
const storage = await getAsyncLocalStorage();
storage?.useContext().monitors?.timing(`${LOADER_REPORTER_NAME}-${route.id?.replace(/\//g, '_')}`, cost);
}
return res;
};
return ()=>{
if ('function' == typeof route.lazyImport) route.lazyImport();
return null;
};
}
function isLoadableComponent(component) {
return component && 'Loadable' === component.displayName && component.preload && 'function' == typeof component.preload;
}
export { renderNestedRoute, transformNestedRoutes };