尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

bulletproof-react 的 Next.js Pages 应用如何通过 pages re-export 保持 app 层代码隔离?

bulletproof-react 的 Next.js Pages 应用如何通过 pages re-export 保持 app 层代码隔离? bulletproof-react 的 Next.js Pages 应用如何通过 pages re-export 保持 app 层代码隔离【免费下载链接】bulletproof-react️ ⚛️ A simple, scalable, and powerful architecture for building production ready React applications.项目地址: https://gitcode.com/GitHub_Trending/bu/bulletproof-react在 bulletproof-react 的apps/nextjs-pages应用中所有业务页面组件都放在src/app/pages下而 Next.js Pages Router 要求的路由文件src/pages里几乎只剩一行 re-export。本文沿着仓库中的真实文件走一遍这个模式为什么这样做、re-export 具体转发了哪些导出、app 层页面文件承担了哪些职责并给出本地启动验证路径的方法。适用对象是直接基于apps/nextjs-pages模板开发或需要理解其目录约定的开发者。为什么 pages 目录只留 re-exportapps/nextjs-pages/README.md 在 Project Structure 一节直接给出了动机Since thepagesfolder isnt very flexible and doesnt allow file collocation, we are keeping theappfolder which is our application layer where we compose all the features, and then we just re-export Next.js page specific files (the pages andgetServerSideProps) from thepagesfolder so Next.js can pick them up and serve as pages.也就是说pages目录不灵活、也不支持文件就近组织file collocation所以真正的页面代码放在src/app/pages这个应用层里完成 feature 组合src/pages下只 re-export Next.js 页面专属的导出页面组件和getServerSideProps让 Next.js 能识别并作为路由提供。准备环境并跑起来README 给出的前置条件与命令Node 20Yarn 1.22cd apps/nextjs-pages cp .env.example .env yarn install按 README 要求先启动 mock server 再启动应用yarn run-mock-servermock server 运行在 http://localhost:8080/api。之后在另开终端中执行yarn dev到 http://localhost:3000 查看应用。pages 目录里的 re-export 长什么样逐行查看src/pages下的路由文件业务路由全部是单行 re-export// src/pages/app/index.tsx export { DashboardPage as default } from /app/pages/app/dashboard;// src/pages/app/discussions/[discussionId].tsx export { DiscussionPage as default } from /app/pages/app/discussions/discussion;需要同时转发getServerSideProps时用命名导出再补上即可// src/pages/public/discussions/[discussionId].tsx export { getServerSideProps, PublicDiscussionPage as default, } from /app/pages/app/discussions/discussion;仓库中其余业务路由同样如此login re-exportLoginPageregister re-exportRegisterPageusers re-exportUsersPageprofile re-exportProfilePagediscussions 列表 re-exportDiscussionsPage。例外只有三个文件它们在pages目录下直接定义而非 re-export_app.tsxPages Router 的入口约定文件必须存在于pagesindex.tsx首页 landing 页直接定义HomePage404.tsx直接定义NotFoundPage。re-export 中的/别名由 tsconfig.json 中的paths: { /*: [./src/*] }提供即/app/pages/app/dashboard解析到src/app/pages/app/dashboard。app 层页面文件承载了哪些页面专属导出re-export 之所以够用是因为 Next.js 页面专属的导出全部集中在src/app/pages的对应文件里。以 discussion.tsx 为例它同时导出了getServerSideProps服务端预取数据并脱水注入export const getServerSideProps (async ({ query, req }) { const queryClient new QueryClient(); const discussionId query.discussionId as string; const cookie req.headers.cookie; await queryClient.prefetchQuery( getDiscussionQueryOptions(discussionId, cookie), ); await queryClient.prefetchInfiniteQuery( getInfiniteCommentsQueryOptions(discussionId, cookie), ); return { props: { dehydratedState: dehydrate(queryClient), }, }; }) satisfies GetServerSidePropsDiscussionPageProps;DiscussionPage页面组件本体内部组合/features/discussions与/features/comments的组件和 API hooksDiscussionPage.getLayout静态属性声明页面布局PublicDiscussionPage同一文件里的第二个页面组件用HydrationBoundary包住DiscussionPage供 public 路由使用。这正是 public 路由那条 re-export 需要转发两个导出的原因public 详情页和 app 内详情页共用同一个getServerSideProps但布局不同。getLayout的约定落在 _app.tsx// eslint-disable-next-line typescript-eslint/ban-types export type NextPageWithLayoutP {}, IP P NextPageP, IP { getLayout?: (page: ReactElement) ReactNode; }; // ... const getLayout Component.getLayout ?? ((page) page); return AppProvider{getLayout(Component {...pageProps} /)}/AppProvider;App通过Component.getLayout读取布局回调读不到时退化为原样渲染。由于 re-export 语句转发的是同一个组件对象DashboardPage、DiscussionPage都附带getLayout静态属性见 dashboard.tsx、users.tsxpages层的单行 re-export 不会丢失任何页面专属行为——布局、SSR、鉴权如UsersPage内Authorization的allowedRoles{[ROLES.ADMIN]}都留在 app 层。隔离是如何被维持的这个模式从两个方向保证 app 层不被框架文件侵入文件边界Next.js 从pages目录识别路由所以路由文件必须在那里但项目约定这些文件只做 re-export页面逻辑、getServerSideProps、布局组合全部放在src/app/pages与/features、/components、/lib正常 import。想新增页面时按同一约定操作先在src/app/pages下写页面组件需要 SSR 时导出getServerSideProps再在src/pages下建对应文件做一行 re-export。import 方向docs/project-structure.md 描述了单向依赖代码库——shared → features → appapp 可以从 features 和 shared 导入反之不行src/app下的 routes 就是应用层组织 feature 的地方。文档给出了用 ESLint 强制该方向的示例配置import/no-restricted-paths: [ error, { zones: [ // Previous restrictions... // enforce unidirectional codebase: // e.g. src/app can import from src/features but not the other way around { target: ./src/features, from: ./src/app, }, // e.g src/features and src/app can import from these shared modules but not the other way around { target: [ ./src/components, ./src/hooks, ./src/lib, ./src/types, ./src/utils, ], from: [./src/features, ./src/app], }, ], }, ],文档同时说明app文件夹结构“may differ based on the meta framework used”视所用 meta 框架而定并把跨 feature 导入也一并禁用。框架专属的文件被压进pages这一层薄壳之后src/app以下的代码与 Pages Router 的目录约定解耦这也是项目能在nextjs-pages、nextjs-app、react-vite三个应用间共用同一套features代码的结构基础。如何验证这套约定启动yarn run-mock-serverhttp://localhost:8080/api再执行yarn dev打开 http://localhost:3000确认首页与/app下的各路由可访问对照src/pages的文件结构与路由app/index.tsx→/appDashboardPageapp/users.tsx→/app/users仅 admin 可见内容app/discussions/index.tsx→ 讨论列表app/discussions/[discussionId].tsx→ 讨论详情public/discussions/[discussionId].tsx→ 公开详情auth/login.tsx、auth/register.tsx→ 登录与注册文件级检查除_app.tsx、index.tsx、404.tsx外src/pages下每个文件应只有 re-export 语句任何页面逻辑、getServerSideProps、布局组合都不应出现在pages目录中而应位于src/app/pages的对应文件内。如果后续要扩大隔离范围docs/project-structure.md 中列出的import/no-restricted-pathszones禁止跨 feature 导入 单向依赖是文档给出的对应手段本文不展开 ESLint 配置落地细节。【免费下载链接】bulletproof-react️ ⚛️ A simple, scalable, and powerful architecture for building production ready React applications.项目地址: https://gitcode.com/GitHub_Trending/bu/bulletproof-react创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表