import { renderToString } from 'react-dom/server'; import { StaticRouter } from 'react-router'; import { App } from '@/App'; import { getDocModule, getLastModified } from '@/lib/content'; import { getScopeForPage } from '@/lib/docs-config'; import { buildHead, renderHeadToString } from '@/lib/head'; import { BASE_URL, toAbsoluteUrl } from '@/lib/paths'; import { docsHomeUrl, docsSite, getLocaleByPathname, getRedirects, getSeo, siteConfig, siteName, standalonePages, } from '@/lib/site-config'; export interface RenderResult { html: string; head: string; /** Attributes for the document element: language and text direction. */ htmlAttrs: { lang: string; dir: 'ltr' | 'rtl' }; } export interface SitemapEntry { url: string; lastmod?: string; } export interface LlmsPage { route: string; filePath: string; title: string; description?: string; } /** Base-relative routes for every scope. The prerenderer prepends the deploy base itself. */ export function getRoutes(): string[] { return [...docsSite.pages.map(page => page.url), ...standalonePages.map(page => page.path)]; } /** Redirect rules with exact-match sources, for static redirect pages. */ export { getRedirects }; /** * Source file for every Markdown/MDX page, so the prerenderer can publish raw * markdown next to each HTML page (used by the contextual menu's copy/view * options and by AI tools). TSX standalone pages have no raw Markdown copy. * `filePath` is a module key like "/content/docs/index.mdx", resolved against * the project root. */ export function getMarkdownPages(): { route: string; filePath: string }[] { return [ ...docsSite.pages.map(page => ({ route: page.url, filePath: page.filePath })), ...standalonePages .filter(page => !page.filePath.endsWith('.tsx')) .map(page => ({ route: page.path, filePath: page.filePath })), ]; } /** Navigable Markdown pages used to generate llms.txt and llms-full.txt. */ export function getLlmsPages(): LlmsPage[] { const { indexing } = getSeo(); const pages: LlmsPage[] = []; for (const page of docsSite.pages) { const doc = getDocModule(page.filePath); if ( doc?.frontmatter?.noindex === true || ((page.hidden || getScopeForPage(docsSite, page).hidden) && indexing !== 'all') ) { continue; } pages.push({ route: page.url, filePath: page.filePath, title: doc?.frontmatter?.title || page.label, description: doc?.frontmatter?.description, }); } for (const page of standalonePages) { if (page.filePath.endsWith('.tsx')) continue; const doc = getDocModule(page.filePath); if (doc?.frontmatter?.noindex === true) continue; pages.push({ route: page.path, filePath: page.filePath, title: doc?.frontmatter?.title || page.title || page.path, description: doc?.frontmatter?.description, }); } return pages; } /** * Absolute URLs for the sitemap, honoring `seo.indexing` and per-page * noindex. Empty when the shiso.config `siteUrl` is not configured, since a sitemap * of relative URLs is invalid. */ export function getSitemapEntries(): SitemapEntry[] { const { indexing } = getSeo(); const entries: SitemapEntry[] = []; for (const page of docsSite.pages) { // Hidden pages and pages of hidden scopes (versions/languages) stay out // of the sitemap unless `seo.indexing: "all"` opts them in. if ((page.hidden || getScopeForPage(docsSite, page).hidden) && indexing !== 'all') { continue; } if (getDocModule(page.filePath)?.frontmatter?.noindex === true) { continue; } const url = toAbsoluteUrl(page.url); if (url) { entries.push({ url, lastmod: getLastModified(page.filePath) }); } } // Standalone pages are always navigable; only frontmatter noindex opts out. for (const page of standalonePages) { if (getDocModule(page.filePath)?.frontmatter?.noindex === true) { continue; } const url = toAbsoluteUrl(page.path); if (url) { entries.push({ url, lastmod: getLastModified(page.filePath) }); } } return entries; } export function render(url: string): RenderResult { // basename must match the client's BrowserRouter, or every in the // prerendered HTML would omit the deploy base and mismatch on hydration. const html = renderToString( , ); return { html, head: renderHeadToString(buildHead(url)), htmlAttrs: getLocaleByPathname(url) }; } export const siteDescription = siteConfig.description; export { docsHomeUrl, siteName };