import { APP_ROUTE_METAS } from '@/defines/appRoutes'; import { NAV_MENU_ITEMS } from '@/defines/navMenu'; import { withLangPrefix } from '@/hooks/useAppNavigate'; export interface NavMenuItem { name: string; /** 完整路径(含语言前缀,按渲染模式而定):SSG → /en/home;CSR → /home。 */ path: string; locale?: string; } /** 渲染模式编译期常量(vite.config 的 define 注入),用于两套实现的编译期隔离。 */ const isCSR = import.meta.env.VITE_RENDER_MODE === 'csr'; // ———————————————————————————————————————————————————————————————— // CSR 模式:从路由「纯数据」清单 APP_ROUTE_METAS 生成菜单(取 hideInMenu !== true 的项)。 // 该清单不 import 任何组件,故不会牵出 routes.tsx→BasicLayout→Topbar 的循环依赖; // routes.tsx 与本文件共同消费这份清单,实现「路由与菜单单一数据源」。 // ———————————————————————————————————————————————————————————————— function getCsrMenuItems(): NavMenuItem[] { return APP_ROUTE_METAS.filter((meta) => meta.hideInMenu !== true).map((meta) => ({ name: meta.name, path: `/${meta.path}`, locale: meta.locale, })); } // ———————————————————————————————————————————————————————————————— // SSG 模式:读静态定义 src/defines/navMenu.ts,路径前缀由 withLangPrefix 按当前语言补齐。 // framework 模式的路由源(src/routes.ts)是 route()/prefix() DSL,无 name/hideInMenu 可反推, // 故菜单独立声明于 navMenu.ts。 // ———————————————————————————————————————————————————————————————— function getSsgMenuItems(lang?: string): NavMenuItem[] { return NAV_MENU_ITEMS.map((item) => ({ name: item.name, path: withLangPrefix(item.segment, lang), locale: item.locale, })); } /** * 获取导航菜单项。两种渲染模式各走各的来源,按编译期常量 VITE_RENDER_MODE 隔离: * - CSR:从 defines/appRoutes.ts 的路由清单派生(与 router/routes.tsx 同源)。 * - SSG:读 defines/navMenu.ts 静态定义,withLangPrefix 补 / 前缀。 * * 构建时非当前模式的分支会被 dead-code 消除。两套数据源都是纯数据、无组件依赖,不构成循环依赖。 * * @param lang 当前语言短码(来自 useParams().lang)。仅 SSG 使用;CSR 忽略。 */ export function getNavMenuItems(lang?: string): NavMenuItem[] { if (isCSR) return getCsrMenuItems(); return getSsgMenuItems(lang); }