1"use strict"; 2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 if (k2 === undefined) k2 = k; 4 var desc = Object.getOwnPropertyDescriptor(m, k); 5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 desc = { enumerable: true, get: function() { return m[k]; } }; 7 } 8 Object.defineProperty(o, k2, desc); 9}) : (function(o, m, k, k2) { 10 if (k2 === undefined) k2 = k; 11 o[k2] = m[k]; 12})); 13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 Object.defineProperty(o, "default", { enumerable: true, value: v }); 15}) : function(o, v) { 16 o["default"] = v; 17}); 18var __importStar = (this && this.__importStar) || function (mod) { 19 if (mod && mod.__esModule) return mod; 20 var result = {}; 21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 __setModuleDefault(result, mod); 23 return result; 24}; 25var __importDefault = (this && this.__importDefault) || function (mod) { 26 return (mod && mod.__esModule) ? mod : { "default": mod }; 27}; 28Object.defineProperty(exports, "__esModule", { value: true }); 29exports.getManifest = exports.getStaticContent = void 0; 30/** 31 * Copyright © 2023 650 Industries. 32 * 33 * This source code is licensed under the MIT license found in the 34 * LICENSE file in the root directory of this source tree. 35 */ 36require("@expo/metro-runtime"); 37const native_1 = require("@react-navigation/native"); 38const Font = __importStar(require("expo-font/build/server")); 39const react_1 = __importDefault(require("react")); 40const server_1 = __importDefault(require("react-dom/server")); 41const react_native_web_1 = require("react-native-web"); 42const getRootComponent_1 = require("./getRootComponent"); 43const _ctx_1 = require("../../_ctx"); 44const ExpoRoot_1 = require("../ExpoRoot"); 45const getLinkingConfig_1 = require("../getLinkingConfig"); 46const getRoutes_1 = require("../getRoutes"); 47const head_1 = require("../head"); 48const loadStaticParamsAsync_1 = require("../loadStaticParamsAsync"); 49const debug = require('debug')('expo:router:renderStaticContent'); 50react_native_web_1.AppRegistry.registerComponent('App', () => ExpoRoot_1.ExpoRoot); 51/** Get the linking manifest from a Node.js process. */ 52async function getManifest(options) { 53 const routeTree = (0, getRoutes_1.getRoutes)(_ctx_1.ctx, { preserveApiRoutes: true, ...options }); 54 if (!routeTree) { 55 throw new Error('No routes found'); 56 } 57 // Evaluate all static params 58 await (0, loadStaticParamsAsync_1.loadStaticParamsAsync)(routeTree); 59 return (0, getLinkingConfig_1.getNavigationConfig)(routeTree); 60} 61exports.getManifest = getManifest; 62function resetReactNavigationContexts() { 63 // https://github.com/expo/router/discussions/588 64 // https://github.com/react-navigation/react-navigation/blob/9fe34b445fcb86e5666f61e144007d7540f014fa/packages/elements/src/getNamedContext.tsx#LL3C1-L4C1 65 // React Navigation is storing providers in a global, this is fine for the first static render 66 // but subsequent static renders of Stack or Tabs will cause React to throw a warning. To prevent this warning, we'll reset the globals before rendering. 67 const contexts = '__react_navigation__elements_contexts'; 68 global[contexts] = new Map(); 69} 70function getStaticContent(location) { 71 const headContext = {}; 72 const ref = react_1.default.createRef(); 73 const { 74 // NOTE: The `element` that's returned adds two extra Views and 75 // the seemingly unused `RootTagContext.Provider`. 76 element, getStyleElement, } = react_native_web_1.AppRegistry.getApplication('App', { 77 initialProps: { 78 location, 79 context: _ctx_1.ctx, 80 wrapper: ({ children }) => (react_1.default.createElement(Root, null, 81 react_1.default.createElement("div", { id: "root" }, children))), 82 }, 83 }); 84 const Root = (0, getRootComponent_1.getRootComponent)(); 85 // Clear any existing static resources from the global scope to attempt to prevent leaking between pages. 86 // This could break if pages are rendered in parallel or if fonts are loaded outside of the React tree 87 Font.resetServerContext(); 88 // This MUST be run before `ReactDOMServer.renderToString` to prevent 89 // "Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported." 90 resetReactNavigationContexts(); 91 const html = server_1.default.renderToString(react_1.default.createElement(head_1.Head.Provider, { context: headContext }, 92 react_1.default.createElement(native_1.ServerContainer, { ref: ref }, element))); 93 // Eval the CSS after the HTML is rendered so that the CSS is in the same order 94 const css = server_1.default.renderToStaticMarkup(getStyleElement()); 95 let output = mixHeadComponentsWithStaticResults(headContext.helmet, html); 96 output = output.replace('</head>', `${css}</head>`); 97 const fonts = Font.getServerResources(); 98 debug(`Pushing static fonts: (count: ${fonts.length})`, fonts); 99 // debug('Push static fonts:', fonts) 100 // Inject static fonts loaded with expo-font 101 output = output.replace('</head>', `${fonts.join('')}</head>`); 102 return '<!DOCTYPE html>' + output; 103} 104exports.getStaticContent = getStaticContent; 105function mixHeadComponentsWithStaticResults(helmet, html) { 106 // Head components 107 for (const key of ['title', 'priority', 'meta', 'link', 'script', 'style'].reverse()) { 108 const result = helmet?.[key]?.toString(); 109 if (result) { 110 html = html.replace('<head>', `<head>${result}`); 111 } 112 } 113 // attributes 114 html = html.replace('<html ', `<html ${helmet?.htmlAttributes.toString()} `); 115 html = html.replace('<body ', `<body ${helmet?.bodyAttributes.toString()} `); 116 return html; 117} 118//# sourceMappingURL=renderStaticContent.js.map