server.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var React = require('react');
  4. var router = require('@remix-run/router');
  5. var reactRouterDom = require('react-router-dom');
  6. function _interopNamespace(e) {
  7. if (e && e.__esModule) return e;
  8. var n = Object.create(null);
  9. if (e) {
  10. Object.keys(e).forEach(function (k) {
  11. if (k !== 'default') {
  12. var d = Object.getOwnPropertyDescriptor(e, k);
  13. Object.defineProperty(n, k, d.get ? d : {
  14. enumerable: true,
  15. get: function () { return e[k]; }
  16. });
  17. }
  18. });
  19. }
  20. n["default"] = e;
  21. return Object.freeze(n);
  22. }
  23. var React__namespace = /*#__PURE__*/_interopNamespace(React);
  24. /**
  25. * A <Router> that may not navigate to any other location. This is useful
  26. * on the server where there is no stateful UI.
  27. */
  28. function StaticRouter({
  29. basename,
  30. children,
  31. location: locationProp = "/"
  32. }) {
  33. if (typeof locationProp === "string") {
  34. locationProp = reactRouterDom.parsePath(locationProp);
  35. }
  36. let action = router.Action.Pop;
  37. let location = {
  38. pathname: locationProp.pathname || "/",
  39. search: locationProp.search || "",
  40. hash: locationProp.hash || "",
  41. state: locationProp.state || null,
  42. key: locationProp.key || "default"
  43. };
  44. let staticNavigator = getStatelessNavigator();
  45. return /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, {
  46. basename: basename,
  47. children: children,
  48. location: location,
  49. navigationType: action,
  50. navigator: staticNavigator,
  51. static: true
  52. });
  53. }
  54. /**
  55. * A Data Router that may not navigate to any other location. This is useful
  56. * on the server where there is no stateful UI.
  57. */
  58. function StaticRouterProvider({
  59. context,
  60. router: router$1,
  61. hydrate = true,
  62. nonce
  63. }) {
  64. !(router$1 && context) ? process.env.NODE_ENV !== "production" ? router.invariant(false, "You must provide `router` and `context` to <StaticRouterProvider>") : router.invariant(false) : void 0;
  65. let dataRouterContext = {
  66. router: router$1,
  67. navigator: getStatelessNavigator(),
  68. static: true,
  69. staticContext: context,
  70. basename: context.basename || "/"
  71. };
  72. let hydrateScript = "";
  73. if (hydrate !== false) {
  74. let data = {
  75. loaderData: context.loaderData,
  76. actionData: context.actionData,
  77. errors: serializeErrors(context.errors)
  78. }; // Use JSON.parse here instead of embedding a raw JS object here to speed
  79. // up parsing on the client. Dual-stringify is needed to ensure all quotes
  80. // are properly escaped in the resulting string. See:
  81. // https://v8.dev/blog/cost-of-javascript-2019#json
  82. let json = JSON.stringify(JSON.stringify(data));
  83. hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`;
  84. }
  85. return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterContext.Provider, {
  86. value: dataRouterContext
  87. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterStateContext.Provider, {
  88. value: dataRouterContext.router.state
  89. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, {
  90. basename: dataRouterContext.basename,
  91. location: dataRouterContext.router.state.location,
  92. navigationType: dataRouterContext.router.state.historyAction,
  93. navigator: dataRouterContext.navigator
  94. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Routes, null)))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", {
  95. suppressHydrationWarning: true,
  96. nonce: nonce,
  97. dangerouslySetInnerHTML: {
  98. __html: hydrateScript
  99. }
  100. }) : null);
  101. }
  102. function serializeErrors(errors) {
  103. if (!errors) return null;
  104. let entries = Object.entries(errors);
  105. let serialized = {};
  106. for (let [key, val] of entries) {
  107. // Hey you! If you change this, please change the corresponding logic in
  108. // deserializeErrors in react-router-dom/index.tsx :)
  109. if (router.isRouteErrorResponse(val)) {
  110. serialized[key] = { ...val,
  111. __type: "RouteErrorResponse"
  112. };
  113. } else if (val instanceof Error) {
  114. // Do not serialize stack traces from SSR for security reasons
  115. serialized[key] = {
  116. message: val.message,
  117. __type: "Error"
  118. };
  119. } else {
  120. serialized[key] = val;
  121. }
  122. }
  123. return serialized;
  124. }
  125. function getStatelessNavigator() {
  126. return {
  127. createHref,
  128. encodeLocation,
  129. push(to) {
  130. throw new Error(`You cannot use navigator.push() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)})\` somewhere in your app.`);
  131. },
  132. replace(to) {
  133. throw new Error(`You cannot use navigator.replace() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)}, { replace: true })\` somewhere ` + `in your app.`);
  134. },
  135. go(delta) {
  136. throw new Error(`You cannot use navigator.go() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${delta})\` somewhere in your app.`);
  137. },
  138. back() {
  139. throw new Error(`You cannot use navigator.back() on the server because it is a stateless ` + `environment.`);
  140. },
  141. forward() {
  142. throw new Error(`You cannot use navigator.forward() on the server because it is a stateless ` + `environment.`);
  143. }
  144. };
  145. } // Temporary manifest generation - we should optimize this by combining the
  146. // tree-walks between convertRoutesToDataRoutes, enhanceManualRouteObjects,
  147. // and generateManifest.
  148. // Also look into getting rid of `route as AgnosticDataRouteObject` down below?
  149. function generateManifest(routes, manifest = new Map()) {
  150. routes.forEach(route => {
  151. manifest.set(route.id, route);
  152. if (route.children) {
  153. generateManifest(route.children, manifest);
  154. }
  155. });
  156. return manifest;
  157. }
  158. function createStaticRouter(routes, context) {
  159. let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(reactRouterDom.UNSAFE_enhanceManualRouteObjects(routes));
  160. let manifest = generateManifest(dataRoutes); // Because our context matches may be from a framework-agnostic set of
  161. // routes passed to createStaticHandler(), we update them here with our
  162. // newly created/enhanced data routes
  163. let matches = context.matches.map(match => {
  164. let route = manifest.get(match.route.id) || match.route;
  165. return { ...match,
  166. route: route
  167. };
  168. });
  169. let msg = method => `You cannot use router.${method}() on the server because it is a stateless environment`;
  170. return {
  171. get basename() {
  172. return context.basename;
  173. },
  174. get state() {
  175. return {
  176. historyAction: router.Action.Pop,
  177. location: context.location,
  178. matches,
  179. loaderData: context.loaderData,
  180. actionData: context.actionData,
  181. errors: context.errors,
  182. initialized: true,
  183. navigation: router.IDLE_NAVIGATION,
  184. restoreScrollPosition: null,
  185. preventScrollReset: false,
  186. revalidation: "idle",
  187. fetchers: new Map(),
  188. blockers: new Map()
  189. };
  190. },
  191. get routes() {
  192. return dataRoutes;
  193. },
  194. initialize() {
  195. throw msg("initialize");
  196. },
  197. subscribe() {
  198. throw msg("subscribe");
  199. },
  200. enableScrollRestoration() {
  201. throw msg("enableScrollRestoration");
  202. },
  203. navigate() {
  204. throw msg("navigate");
  205. },
  206. fetch() {
  207. throw msg("fetch");
  208. },
  209. revalidate() {
  210. throw msg("revalidate");
  211. },
  212. createHref,
  213. encodeLocation,
  214. getFetcher() {
  215. return router.IDLE_FETCHER;
  216. },
  217. deleteFetcher() {
  218. throw msg("deleteFetcher");
  219. },
  220. dispose() {
  221. throw msg("dispose");
  222. },
  223. getBlocker() {
  224. throw msg("getBlocker");
  225. },
  226. deleteBlocker() {
  227. throw msg("deleteBlocker");
  228. },
  229. _internalFetchControllers: new Map(),
  230. _internalActiveDeferreds: new Map()
  231. };
  232. }
  233. function createHref(to) {
  234. return typeof to === "string" ? to : reactRouterDom.createPath(to);
  235. }
  236. function encodeLocation(to) {
  237. // Locations should already be encoded on the server, so just return as-is
  238. let path = typeof to === "string" ? reactRouterDom.parsePath(to) : to;
  239. return {
  240. pathname: path.pathname || "",
  241. search: path.search || "",
  242. hash: path.hash || ""
  243. };
  244. }
  245. exports.StaticRouter = StaticRouter;
  246. exports.StaticRouterProvider = StaticRouterProvider;
  247. exports.createStaticRouter = createStaticRouter;