UNPKG

13.5 kBJavaScriptView Raw
1/**
2 * react-router v8.0.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import { ErrorResponseImpl, compilePath } from "../../router/utils.js";
12import { useRouteError } from "../../hooks.js";
13import invariant from "./invariant.js";
14import { loadRouteModule } from "./routeModules.js";
15import { prefetchRouteCss, prefetchStyleLinks } from "./links.js";
16import { RemixRootDefaultErrorBoundary } from "./errorBoundaries.js";
17import { RemixRootDefaultHydrateFallback } from "./fallback.js";
18import * as React$1 from "react";
19//#region lib/dom/ssr/routes.tsx
20function groupRoutesByParentId(manifest) {
21 let routes = {};
22 Object.values(manifest).forEach((route) => {
23 if (route) {
24 let parentId = route.parentId || "";
25 if (!routes[parentId]) routes[parentId] = [];
26 routes[parentId].push(route);
27 }
28 });
29 return routes;
30}
31function getRouteComponents(route, routeModule, isSpaMode) {
32 let Component = getRouteModuleComponent(routeModule);
33 let HydrateFallback = routeModule.HydrateFallback && (!isSpaMode || route.id === "root") ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : void 0;
34 let ErrorBoundary = routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /* @__PURE__ */ React$1.createElement(RemixRootDefaultErrorBoundary, { error: useRouteError() }) : void 0;
35 if (route.id === "root" && routeModule.Layout) return {
36 ...Component ? { element: /* @__PURE__ */ React$1.createElement(routeModule.Layout, null, /* @__PURE__ */ React$1.createElement(Component, null)) } : { Component },
37 ...ErrorBoundary ? { errorElement: /* @__PURE__ */ React$1.createElement(routeModule.Layout, null, /* @__PURE__ */ React$1.createElement(ErrorBoundary, null)) } : { ErrorBoundary },
38 ...HydrateFallback ? { hydrateFallbackElement: /* @__PURE__ */ React$1.createElement(routeModule.Layout, null, /* @__PURE__ */ React$1.createElement(HydrateFallback, null)) } : { HydrateFallback }
39 };
40 return {
41 Component,
42 ErrorBoundary,
43 HydrateFallback
44 };
45}
46function createServerRoutes(manifest, routeModules, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), spaModeLazyPromise = Promise.resolve({ Component: () => null })) {
47 return (routesByParentId[parentId] || []).map((route) => {
48 let routeModule = routeModules[route.id];
49 invariant(routeModule, "No `routeModule` available to create server routes");
50 let dataRoute = {
51 ...getRouteComponents(route, routeModule, isSpaMode),
52 caseSensitive: route.caseSensitive,
53 id: route.id,
54 index: route.index,
55 path: route.path,
56 handle: routeModule.handle,
57 lazy: isSpaMode ? () => spaModeLazyPromise : void 0,
58 loader: route.hasLoader || route.hasClientLoader ? () => null : void 0
59 };
60 let children = createServerRoutes(manifest, routeModules, future, isSpaMode, route.id, routesByParentId, spaModeLazyPromise);
61 if (children.length > 0) dataRoute.children = children;
62 return dataRoute;
63 });
64}
65function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, ssr, isSpaMode) {
66 return createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSpaMode, "", groupRoutesByParentId(manifest), needsRevalidation);
67}
68function preventInvalidServerHandlerCall(type, route) {
69 if (type === "loader" && !route.hasLoader || type === "action" && !route.hasAction) {
70 let msg = `You are trying to call ${type === "action" ? "serverAction()" : "serverLoader()"} on a route that does not have a server ${type} (routeId: "${route.id}")`;
71 console.error(msg);
72 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
73 }
74}
75function noActionDefinedError(type, routeId) {
76 let article = type === "clientAction" ? "a" : "an";
77 let msg = `Route "${routeId}" does not have ${article} ${type}, but you are trying to submit to it. To fix this, please add ${article} \`${type}\` function to the route`;
78 console.error(msg);
79 throw new ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
80}
81function createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
82 return (routesByParentId[parentId] || []).map((route) => {
83 let routeModule = routeModulesCache[route.id];
84 function fetchServerHandler(singleFetch) {
85 invariant(typeof singleFetch === "function", "No single fetch function available for route handler");
86 return singleFetch();
87 }
88 function fetchServerLoader(singleFetch) {
89 if (!route.hasLoader) return Promise.resolve(null);
90 return fetchServerHandler(singleFetch);
91 }
92 function fetchServerAction(singleFetch) {
93 if (!route.hasAction) throw noActionDefinedError("action", route.id);
94 return fetchServerHandler(singleFetch);
95 }
96 function prefetchModule(modulePath) {
97 import(
98 /* @vite-ignore */
99 /* webpackIgnore: true */
100 modulePath
101);
102 }
103 function prefetchRouteModuleChunks(route) {
104 if (route.clientActionModule) prefetchModule(route.clientActionModule);
105 if (route.clientLoaderModule) prefetchModule(route.clientLoaderModule);
106 }
107 async function prefetchStylesAndCallHandler(handler) {
108 let cachedModule = routeModulesCache[route.id];
109 let linkPrefetchPromise = cachedModule ? prefetchStyleLinks(route, cachedModule) : Promise.resolve();
110 try {
111 return handler();
112 } finally {
113 await linkPrefetchPromise;
114 }
115 }
116 let dataRoute = {
117 id: route.id,
118 index: route.index,
119 path: route.path
120 };
121 if (routeModule) {
122 Object.assign(dataRoute, {
123 ...dataRoute,
124 ...getRouteComponents(route, routeModule, isSpaMode),
125 middleware: routeModule.clientMiddleware,
126 handle: routeModule.handle,
127 shouldRevalidate: getShouldRevalidateFunction(dataRoute.path, routeModule, route, ssr, needsRevalidation)
128 });
129 let hasInitialData = initialState && initialState.loaderData && route.id in initialState.loaderData;
130 let initialData = hasInitialData ? initialState?.loaderData?.[route.id] : void 0;
131 let hasInitialError = initialState && initialState.errors && route.id in initialState.errors;
132 let initialError = hasInitialError ? initialState?.errors?.[route.id] : void 0;
133 let isHydrationRequest = needsRevalidation == null && (routeModule.clientLoader?.hydrate === true || !route.hasLoader);
134 dataRoute.loader = async ({ request, params, context, pattern, url }, singleFetch) => {
135 let _isHydrationRequest = isHydrationRequest;
136 isHydrationRequest = false;
137 return await prefetchStylesAndCallHandler(async () => {
138 invariant(routeModule, "No `routeModule` available for critical-route loader");
139 if (!routeModule.clientLoader) return fetchServerLoader(singleFetch);
140 return routeModule.clientLoader({
141 request,
142 params,
143 context,
144 pattern,
145 url,
146 async serverLoader() {
147 preventInvalidServerHandlerCall("loader", route);
148 if (_isHydrationRequest) {
149 if (hasInitialData) return initialData;
150 if (hasInitialError) throw initialError;
151 }
152 return fetchServerLoader(singleFetch);
153 }
154 });
155 });
156 };
157 dataRoute.loader.hydrate = shouldHydrateRouteLoader(route.id, routeModule.clientLoader, route.hasLoader, isSpaMode);
158 dataRoute.action = ({ request, params, context, pattern, url }, singleFetch) => {
159 return prefetchStylesAndCallHandler(async () => {
160 invariant(routeModule, "No `routeModule` available for critical-route action");
161 if (!routeModule.clientAction) {
162 if (isSpaMode) throw noActionDefinedError("clientAction", route.id);
163 return fetchServerAction(singleFetch);
164 }
165 return routeModule.clientAction({
166 request,
167 params,
168 context,
169 pattern,
170 url,
171 async serverAction() {
172 preventInvalidServerHandlerCall("action", route);
173 return fetchServerAction(singleFetch);
174 }
175 });
176 });
177 };
178 } else {
179 if (!route.hasClientLoader) dataRoute.loader = (_, singleFetch) => prefetchStylesAndCallHandler(() => {
180 return fetchServerLoader(singleFetch);
181 });
182 if (!route.hasClientAction) dataRoute.action = (_, singleFetch) => prefetchStylesAndCallHandler(() => {
183 if (isSpaMode) throw noActionDefinedError("clientAction", route.id);
184 return fetchServerAction(singleFetch);
185 });
186 let lazyRoutePromise;
187 async function getLazyRoute() {
188 if (lazyRoutePromise) return await lazyRoutePromise;
189 lazyRoutePromise = (async () => {
190 if (route.clientLoaderModule || route.clientActionModule) await new Promise((resolve) => setTimeout(resolve, 0));
191 let routeModulePromise = loadRouteModuleWithBlockingLinks(route, routeModulesCache);
192 prefetchRouteModuleChunks(route);
193 return await routeModulePromise;
194 })();
195 return await lazyRoutePromise;
196 }
197 dataRoute.lazy = {
198 loader: route.hasClientLoader ? async () => {
199 let { clientLoader } = route.clientLoaderModule ? await import(
200 /* @vite-ignore */
201 /* webpackIgnore: true */
202 route.clientLoaderModule
203) : await getLazyRoute();
204 invariant(clientLoader, "No `clientLoader` export found");
205 return (args, singleFetch) => clientLoader({
206 ...args,
207 async serverLoader() {
208 preventInvalidServerHandlerCall("loader", route);
209 return fetchServerLoader(singleFetch);
210 }
211 });
212 } : void 0,
213 action: route.hasClientAction ? async () => {
214 let clientActionPromise = route.clientActionModule ? import(
215 /* @vite-ignore */
216 /* webpackIgnore: true */
217 route.clientActionModule
218) : getLazyRoute();
219 prefetchRouteModuleChunks(route);
220 let { clientAction } = await clientActionPromise;
221 invariant(clientAction, "No `clientAction` export found");
222 return (args, singleFetch) => clientAction({
223 ...args,
224 async serverAction() {
225 preventInvalidServerHandlerCall("action", route);
226 return fetchServerAction(singleFetch);
227 }
228 });
229 } : void 0,
230 middleware: route.hasClientMiddleware ? async () => {
231 let { clientMiddleware } = route.clientMiddlewareModule ? await import(
232 /* @vite-ignore */
233 /* webpackIgnore: true */
234 route.clientMiddlewareModule
235) : await getLazyRoute();
236 invariant(clientMiddleware, "No `clientMiddleware` export found");
237 return clientMiddleware;
238 } : void 0,
239 shouldRevalidate: async () => {
240 let lazyRoute = await getLazyRoute();
241 return getShouldRevalidateFunction(dataRoute.path, lazyRoute, route, ssr, needsRevalidation);
242 },
243 handle: async () => (await getLazyRoute()).handle,
244 Component: async () => (await getLazyRoute()).Component,
245 ErrorBoundary: route.hasErrorBoundary ? async () => (await getLazyRoute()).ErrorBoundary : void 0
246 };
247 }
248 let children = createClientRoutes(manifest, routeModulesCache, initialState, ssr, isSpaMode, route.id, routesByParentId, needsRevalidation);
249 if (children.length > 0) dataRoute.children = children;
250 return dataRoute;
251 });
252}
253function getShouldRevalidateFunction(path, route, manifestRoute, ssr, needsRevalidation) {
254 if (needsRevalidation) return wrapShouldRevalidateForHdr(manifestRoute.id, route.shouldRevalidate, needsRevalidation);
255 if (!ssr && manifestRoute.hasLoader && !manifestRoute.hasClientLoader) {
256 let myParams = path ? compilePath(path)[1].map((p) => p.paramName) : [];
257 const didParamsChange = (opts) => myParams.some((p) => opts.currentParams[p] !== opts.nextParams[p]);
258 if (route.shouldRevalidate) {
259 let fn = route.shouldRevalidate;
260 return (opts) => fn({
261 ...opts,
262 defaultShouldRevalidate: didParamsChange(opts)
263 });
264 } else return (opts) => didParamsChange(opts);
265 }
266 return route.shouldRevalidate;
267}
268function wrapShouldRevalidateForHdr(routeId, routeShouldRevalidate, needsRevalidation) {
269 let handledRevalidation = false;
270 return (arg) => {
271 if (!handledRevalidation) {
272 handledRevalidation = true;
273 return needsRevalidation.has(routeId);
274 }
275 return routeShouldRevalidate ? routeShouldRevalidate(arg) : arg.defaultShouldRevalidate;
276 };
277}
278async function loadRouteModuleWithBlockingLinks(route, routeModules) {
279 let routeModulePromise = loadRouteModule(route, routeModules);
280 let prefetchRouteCssPromise = prefetchRouteCss(route);
281 let routeModule = await routeModulePromise;
282 await Promise.all([prefetchRouteCssPromise, prefetchStyleLinks(route, routeModule)]);
283 return {
284 Component: getRouteModuleComponent(routeModule),
285 ErrorBoundary: routeModule.ErrorBoundary,
286 clientMiddleware: routeModule.clientMiddleware,
287 clientAction: routeModule.clientAction,
288 clientLoader: routeModule.clientLoader,
289 handle: routeModule.handle,
290 links: routeModule.links,
291 meta: routeModule.meta,
292 shouldRevalidate: routeModule.shouldRevalidate
293 };
294}
295function getRouteModuleComponent(routeModule) {
296 if (routeModule.default == null) return void 0;
297 if (!(typeof routeModule.default === "object" && Object.keys(routeModule.default).length === 0)) return routeModule.default;
298}
299function shouldHydrateRouteLoader(routeId, clientLoader, hasLoader, isSpaMode) {
300 return isSpaMode && routeId !== "root" || clientLoader != null && (clientLoader.hydrate === true || hasLoader !== true);
301}
302//#endregion
303export { createClientRoutes, createClientRoutesWithHMRRevalidationOptOut, createServerRoutes, noActionDefinedError, shouldHydrateRouteLoader };