server.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var React = require('react');
  4. var router = require('@remix-run/router');
  5. var reactRouter = require('react-router');
  6. var reactRouterDom = require('react-router-dom');
  7. function _interopNamespace(e) {
  8. if (e && e.__esModule) return e;
  9. var n = Object.create(null);
  10. if (e) {
  11. Object.keys(e).forEach(function (k) {
  12. if (k !== 'default') {
  13. var d = Object.getOwnPropertyDescriptor(e, k);
  14. Object.defineProperty(n, k, d.get ? d : {
  15. enumerable: true,
  16. get: function () { return e[k]; }
  17. });
  18. }
  19. });
  20. }
  21. n["default"] = e;
  22. return Object.freeze(n);
  23. }
  24. var React__namespace = /*#__PURE__*/_interopNamespace(React);
  25. /**
  26. * A `<Router>` that may not navigate to any other location. This is useful
  27. * on the server where there is no stateful UI.
  28. */
  29. function StaticRouter({
  30. basename,
  31. children,
  32. location: locationProp = "/",
  33. future
  34. }) {
  35. if (typeof locationProp === "string") {
  36. locationProp = reactRouterDom.parsePath(locationProp);
  37. }
  38. let action = router.Action.Pop;
  39. let location = {
  40. pathname: locationProp.pathname || "/",
  41. search: locationProp.search || "",
  42. hash: locationProp.hash || "",
  43. state: locationProp.state != null ? locationProp.state : null,
  44. key: locationProp.key || "default"
  45. };
  46. let staticNavigator = getStatelessNavigator();
  47. return /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, {
  48. basename: basename,
  49. children: children,
  50. location: location,
  51. navigationType: action,
  52. navigator: staticNavigator,
  53. future: future,
  54. static: true
  55. });
  56. }
  57. /**
  58. * A Data Router that may not navigate to any other location. This is useful
  59. * on the server where there is no stateful UI.
  60. */
  61. function StaticRouterProvider({
  62. context,
  63. router: router$1,
  64. hydrate = true,
  65. nonce
  66. }) {
  67. !(router$1 && context) ? process.env.NODE_ENV !== "production" ? router.UNSAFE_invariant(false, "You must provide `router` and `context` to <StaticRouterProvider>") : router.UNSAFE_invariant(false) : void 0;
  68. let dataRouterContext = {
  69. router: router$1,
  70. navigator: getStatelessNavigator(),
  71. static: true,
  72. staticContext: context,
  73. basename: context.basename || "/"
  74. };
  75. let fetchersContext = new Map();
  76. let hydrateScript = "";
  77. if (hydrate !== false) {
  78. let data = {
  79. loaderData: context.loaderData,
  80. actionData: context.actionData,
  81. errors: serializeErrors(context.errors)
  82. };
  83. // Use JSON.parse here instead of embedding a raw JS object here to speed
  84. // up parsing on the client. Dual-stringify is needed to ensure all quotes
  85. // are properly escaped in the resulting string. See:
  86. // https://v8.dev/blog/cost-of-javascript-2019#json
  87. let json = htmlEscape(JSON.stringify(JSON.stringify(data)));
  88. hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`;
  89. }
  90. let {
  91. state
  92. } = dataRouterContext.router;
  93. return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterContext.Provider, {
  94. value: dataRouterContext
  95. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterStateContext.Provider, {
  96. value: state
  97. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_FetchersContext.Provider, {
  98. value: fetchersContext
  99. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_ViewTransitionContext.Provider, {
  100. value: {
  101. isTransitioning: false
  102. }
  103. }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, {
  104. basename: dataRouterContext.basename,
  105. location: state.location,
  106. navigationType: state.historyAction,
  107. navigator: dataRouterContext.navigator,
  108. static: dataRouterContext.static,
  109. future: {
  110. v7_relativeSplatPath: router$1.future.v7_relativeSplatPath
  111. }
  112. }, /*#__PURE__*/React__namespace.createElement(DataRoutes, {
  113. routes: router$1.routes,
  114. future: router$1.future,
  115. state: state
  116. })))))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", {
  117. suppressHydrationWarning: true,
  118. nonce: nonce,
  119. dangerouslySetInnerHTML: {
  120. __html: hydrateScript
  121. }
  122. }) : null);
  123. }
  124. function DataRoutes({
  125. routes,
  126. future,
  127. state
  128. }) {
  129. return reactRouter.UNSAFE_useRoutesImpl(routes, undefined, state, future);
  130. }
  131. function serializeErrors(errors) {
  132. if (!errors) return null;
  133. let entries = Object.entries(errors);
  134. let serialized = {};
  135. for (let [key, val] of entries) {
  136. // Hey you! If you change this, please change the corresponding logic in
  137. // deserializeErrors in react-router-dom/index.tsx :)
  138. if (router.isRouteErrorResponse(val)) {
  139. serialized[key] = {
  140. ...val,
  141. __type: "RouteErrorResponse"
  142. };
  143. } else if (val instanceof Error) {
  144. // Do not serialize stack traces from SSR for security reasons
  145. serialized[key] = {
  146. message: val.message,
  147. __type: "Error",
  148. // If this is a subclass (i.e., ReferenceError), send up the type so we
  149. // can re-create the same type during hydration.
  150. ...(val.name !== "Error" ? {
  151. __subType: val.name
  152. } : {})
  153. };
  154. } else {
  155. serialized[key] = val;
  156. }
  157. }
  158. return serialized;
  159. }
  160. function getStatelessNavigator() {
  161. return {
  162. createHref,
  163. encodeLocation,
  164. push(to) {
  165. 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.`);
  166. },
  167. replace(to) {
  168. 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.`);
  169. },
  170. go(delta) {
  171. 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.`);
  172. },
  173. back() {
  174. throw new Error(`You cannot use navigator.back() on the server because it is a stateless ` + `environment.`);
  175. },
  176. forward() {
  177. throw new Error(`You cannot use navigator.forward() on the server because it is a stateless ` + `environment.`);
  178. }
  179. };
  180. }
  181. function createStaticHandler(routes, opts) {
  182. return router.createStaticHandler(routes, {
  183. ...opts,
  184. mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties
  185. });
  186. }
  187. function createStaticRouter(routes, context, opts = {}) {
  188. let manifest = {};
  189. let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(routes, reactRouter.UNSAFE_mapRouteProperties, undefined, manifest);
  190. // Because our context matches may be from a framework-agnostic set of
  191. // routes passed to createStaticHandler(), we update them here with our
  192. // newly created/enhanced data routes
  193. let matches = context.matches.map(match => {
  194. let route = manifest[match.route.id] || match.route;
  195. return {
  196. ...match,
  197. route
  198. };
  199. });
  200. let msg = method => `You cannot use router.${method}() on the server because it is a stateless environment`;
  201. return {
  202. get basename() {
  203. return context.basename;
  204. },
  205. get future() {
  206. return {
  207. v7_fetcherPersist: false,
  208. v7_normalizeFormMethod: false,
  209. v7_partialHydration: opts.future?.v7_partialHydration === true,
  210. v7_prependBasename: false,
  211. v7_relativeSplatPath: opts.future?.v7_relativeSplatPath === true,
  212. v7_skipActionErrorRevalidation: false
  213. };
  214. },
  215. get state() {
  216. return {
  217. historyAction: router.Action.Pop,
  218. location: context.location,
  219. matches,
  220. loaderData: context.loaderData,
  221. actionData: context.actionData,
  222. errors: context.errors,
  223. initialized: true,
  224. navigation: router.IDLE_NAVIGATION,
  225. restoreScrollPosition: null,
  226. preventScrollReset: false,
  227. revalidation: "idle",
  228. fetchers: new Map(),
  229. blockers: new Map()
  230. };
  231. },
  232. get routes() {
  233. return dataRoutes;
  234. },
  235. get window() {
  236. return undefined;
  237. },
  238. initialize() {
  239. throw msg("initialize");
  240. },
  241. subscribe() {
  242. throw msg("subscribe");
  243. },
  244. enableScrollRestoration() {
  245. throw msg("enableScrollRestoration");
  246. },
  247. navigate() {
  248. throw msg("navigate");
  249. },
  250. fetch() {
  251. throw msg("fetch");
  252. },
  253. revalidate() {
  254. throw msg("revalidate");
  255. },
  256. createHref,
  257. encodeLocation,
  258. getFetcher() {
  259. return router.IDLE_FETCHER;
  260. },
  261. deleteFetcher() {
  262. throw msg("deleteFetcher");
  263. },
  264. dispose() {
  265. throw msg("dispose");
  266. },
  267. getBlocker() {
  268. return router.IDLE_BLOCKER;
  269. },
  270. deleteBlocker() {
  271. throw msg("deleteBlocker");
  272. },
  273. patchRoutes() {
  274. throw msg("patchRoutes");
  275. },
  276. _internalFetchControllers: new Map(),
  277. _internalActiveDeferreds: new Map(),
  278. _internalSetRoutes() {
  279. throw msg("_internalSetRoutes");
  280. }
  281. };
  282. }
  283. function createHref(to) {
  284. return typeof to === "string" ? to : reactRouterDom.createPath(to);
  285. }
  286. function encodeLocation(to) {
  287. let href = typeof to === "string" ? to : reactRouterDom.createPath(to);
  288. // Treating this as a full URL will strip any trailing spaces so we need to
  289. // pre-encode them since they might be part of a matching splat param from
  290. // an ancestor route
  291. href = href.replace(/ $/, "%20");
  292. let encoded = ABSOLUTE_URL_REGEX.test(href) ? new URL(href) : new URL(href, "http://localhost");
  293. return {
  294. pathname: encoded.pathname,
  295. search: encoded.search,
  296. hash: encoded.hash
  297. };
  298. }
  299. const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
  300. // This utility is based on https://github.com/zertosh/htmlescape
  301. // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
  302. const ESCAPE_LOOKUP = {
  303. "&": "\\u0026",
  304. ">": "\\u003e",
  305. "<": "\\u003c",
  306. "\u2028": "\\u2028",
  307. "\u2029": "\\u2029"
  308. };
  309. const ESCAPE_REGEX = /[&><\u2028\u2029]/g;
  310. function htmlEscape(str) {
  311. return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]);
  312. }
  313. exports.StaticRouter = StaticRouter;
  314. exports.StaticRouterProvider = StaticRouterProvider;
  315. exports.createStaticHandler = createStaticHandler;
  316. exports.createStaticRouter = createStaticRouter;