Sukka 写前端、网络和基础设施时,习惯先把边界和代价摊开。把「React Server Component 初体验与实践 —— 将博客迁移到 Next.js App Router | Sukka's Blog」整理成可落地的中文笔记:问题在哪、默认做法会踩什么坑、该怎么选。原站导航和广告已去掉。

内容管理:从 Hexo 获取数据

我曾经使用 Hexo 驱动博客达三年之久,Hexo 的核心是一个 JSON based NoSQL 关系型数据库 warehouse ,在数据库中维护文章、标签、分类。除了通过 CLI 调用、直接生成静态 HTML,Hexo 还暴露了一系列 JS API 用于获取文章数据。因此从 Hexo 迁移到 Next.js 以后,我在博客的架构中仍然保留了 Hexo 作为 CMS。

为了调用 Hexo 中的文章数据,首先需要初始化 Hexo 实例、让 Hexo 加载插件、从文件系统读取所有的文章、构建标签和分类的数据结构,最后渲染文章:

加载数据:在 React Server Component 中直接使用 Hexo API 和传递 Hexo 内部数据类型

import { cache } from 'react' ; import Hexo from 'hexo' ; let __SECRET_HEXO_INSTANCE__ : Hexo | null = null ; export const initHexo = cache ( async ( ) : Promise < Hexo > => { if ( __SECRET_HEXO_INSTANCE__ ) { return __SECRET_HEXO_INSTANCE__ ; } const hexo = new Hexo ( process . cwd ( ) , { silent : true , // 在本地开发环境中,启用 Hexo 的草稿模式(加载并渲染标记为草稿的文章) drafts : process . env . NODE_ENV !== 'production' } ) ; // Hexo 的 warehouse 的 JSON 写入文件系统的路径 const dbPath = jo

在使用 Next.js Pages Router 时,所有 React 组件都是 React Client Component,SSR / SSG 需要通过 getStaticProps / getServerSideProps 获取数据、序列化成 JSON、然后才能在浏览器中加载、以组件 prop 的形式 populate;而 Hexo 的 API 返回的数据类型大多是 warehouse 的 Document 或 Query 实例,warehouse 为了优化性能, Document 和 Query 实例上的属性大多都是 getter、只有在实际使用时才会 evaluate;因此,在使用 Next.js Pages Router 时,在服务端调用 Hexo 的 API 加载数据时,我需要额外写很多序列化步骤:

页面布局:使用 Next.js App Router 实现 Nested Layout

// src/hexo/index.ts const getHexoPostBySlug = async ( slug : string ) => { const hexo = await initHexo ( ) ; const urlFor = url_for . bind ( hexo ) ; const post = hexo . database . model ( 'Post' ) . findOne ( { path : ` post/ ${ slug } / ` } ) ; // 需要将 return { title : post . title , // post.title 是一个 getter、需要显式调用得到 string date : post . date . toISOString ( ) , // post.date 是一个 Moment.js 的实例、不能被直接序列化、需要 toISOString() updated : post . updated . toISOStri

// src/app/post/[slug]/page.tsx import { notFound } from 'next/navigation' ; export default async function PostPage ( { params } : { params : { slug : string } } ) { const hexo = await initHexo ( ) ; // 直接在 React 组件中调用 Hexo 的 API const post = hexo . database . model ( 'Post' ) . findOne ( { path : { eq : ` post/ ${ slug } / ` } } ) ; if ( ! post ) { // 找不到 post 时返回 404 not found return notFound ( ) ; } return ( < article > < h1 > { post . title } </ h1 > {

性能优化:使用 React Server Component 削减 Client JS Bundle 体积

// src/app/tags/[tag]/page.tsx export default async function TagPostsList ( { params } : { params : { tag : string } } ) { const hexo = await initHexo ( ) ; // 直接在 React 组件里调用 Hexo 的 API // 根据标签的 name 在数据库中寻找对应的 Tag 对象 const tag = hexo . database . model ( 'Tag' ) . findOne ( { name : decodeURIComponent ( params . tag ) } , { lean : true } ) ) ; // 在 Post – Tag 交叉索引数据库中寻找所有包含当前 Tag 的 _id 的文章 const postIds = hexo . database . model ( 'PostTag' ) . find ( {

在 Next.js Page Router 中,需要服务端加载的所有数据被声明在每个页面的 getServerSideProps 、 getStaticProps 或者 getInitialProps 中、再从 React Tree 顶部自上而下 populate;所有页面只共享同一个 _app.tsx 、因此所有的 Layout 都需要声明在 _app.tsx 中:

饭后甜点:迁移、重构和拥抱 React 18.3

┌──────────┐ pageProps │ _app.tsx │◄────────────────────┐ └───┬──┬───┘ │ │ │ │ data │ │ │ ┌────────┘ └────────┐ │ │ │ │ ▼ ▼ │ ┌────────┐ ┌──────────────────┐ │ │ Layout │ │ pages/[slug].tsx │ getStaticProps └────────┘ └──────────────────┘ // src/_app.tsx import type { AppProps } from 'next/app' ; import Layout from './components/layout' ; export default function MyApp ( { Component , pageProps } : AppProps ) { const { layoutDataA , layoutDataB , pageType ,

Next.js App Router 则提供了第一方的 Nested Layout 和 Route Groups 支持,我将所有页面公有的部分( <Header /> 和 <Footer /> )封装成一个顶层的 Root Layout,然后将所有不是文章的页面全部归并到 (non-post) 的 Route Group 之中、共享一个 Layout,文章页面单独使用一个 Layout:

尾声

┌────────────────┐ ┌─► <Header /> │ app/layout.tsx ├──────────────┤ └─┬──────────────┘ └─► <Footer /> │ │ ┌────────────────────────┐ ┌─► <SidebarLeft /> ├─►│ (non-post)/layout.tsx ├─┤ │ └────────────────────────┘ └─► <SidebarRight /> │ │ ┌────────────────────────┐ ┌─► <SidebarLeftForPost /> └─►│ post/[slug]/layout.tsx ├─┤ └────────────────────────┘ └─► <SidebarRightForPost /> // src/app/layout.tsx export default function RootLayout ( { children } : React .

// src/post/components/sidebar-left.tsx export default function SidebarLeftForPost ( { slug } : SidebarLeftForPostProps ) { return ( < aside > < ToCWidget slug = { slug } /> < CatrgoryWidget /> < TagsWidget /> </ aside > ) ; } // src/post/components/toc-widget export default async function ToCWidget ( { slug } : ToCWidgetProps ) { const hexo = await initHexo ( ) ; const post = hexo . database . model ( 'Post' ) . findOne ( { path : { eq : ` post/ ${ slug }

值得单独记下的点

  • 不依赖 webpack-virtual-modules ,因此同一个 Style9Plugin 实例可以在多个 webpack compiler 实例之间共享
  • CSS import 中的额外信息存在 resourceQuery 里、而不使用 inline webpack loader,确保 Next.js App Router 可以正确收集 Server-Side 所有的 CSS,使 style9 可以同时在 React Client Component 和 RSC 中使用
  • 不能在 <Head /> 中使用自己声明的 React 组件:
  • 不能在 <Head /> 中嵌套两层及以上的 Fragment:
  • 不兼容 React 18 Stream Server-Side Rendering 和 Selective Hydration,参见 Library Upgrade Guide: <head> (e.g. react-helmet) – reactwg/react-18 。
  • 依赖 React Context 或 Vue Provide 等框架 API、不仅仅依靠 CSS 实现暗色模式的网站,在模式切换的时候需要更新整个应用
  • 大型表格或列表的搜索、筛选和排序,即使使用 Virtual Scrolling(Windowing)的方案,也至少需要更新 20 到 50 行左右的数据
  • Facebook、Twitter、Mastodon 等社交网站的时间轴、通知列表

落地时建议先做的 5 件事

  1. 用自己的流量和设备测,不要只抄厂商推荐最小配置。
  2. DNS、CDN、代理分流先画清 Fake IP 和 Real IP 的边界。
  3. 前端性能看 CLS、白屏和重复渲染,而不是只看打包体积。
  4. 基础设施变更走 Git,能复现、能回滚。
  5. 结论写成可检查的清单:接口、超时、失败样本、回滚版本。

和智能体产品怎么接

龙虾PRO做 OpenClaw 落地时,网络、DNS 和前端性能笔记最有用的是「边界」:哪一层该加速、哪一层不该假装智能。数字员工调用外部能力前,先把超时和失败路径写死。

本文侧重全链路风控方法论。落地时请用自身业务单据做回放验证,不要把示例阈值直接当生产策略。 相关:风控体检 · 方案资源

常见问题 FAQ

什么是AI智能系统?

「AI智能系统」可概括为:我曾经使用 Hexo 驱动博客达三年之久,Hexo 的核心是一个 JSON based NoSQL 关系型数据库 warehouse ,在数据库中维护文章、标签、分类。除了通过 CLI 调用、直接生成静态 HTML,Hexo 还暴露了一系列 JS API 用于获取文章数据。因此从 Hexo 迁移到 Next.js 以后,我在博客的架构中仍然保留了 Hexo 本文从定义、方法与实践要点展开说明。

为什么要关注AI智能系统?

关注AI智能系统,是因为它直接影响效率、风险与可复制性。文中指出:我曾经使用 Hexo 驱动博客达三年之久,Hexo 的核心是一个 JSON based NoSQL 关系型数据库 warehouse ,在数据库中维护文章、标签、分类。除了通过 CLI 调用、直接生成静态 HTML,Hexo 还暴露了一系列 JS API 用于获取文章数据。因此从 Hexo 迁移到 Next.js 以后,我在博客的架构中仍然保留了 Hexo 作为 CMS。

如何落地AI智能系统?有哪些关键步骤?

建议按以下路径推进AI智能系统:1) 不依赖 webpack-virtual-modules ,因此同一个 Style9Plugin 实例可以在多个 webpack compiler 实例之间共享;2) CSS import 中的额外信息存在 resourceQuery 里、而不使用 inline webpack loader,确保 Next.js App R…;3) 不能在 <Head /> 中使用自己声明的 React 组件:;4) 不能在 <Head /> 中嵌套两层及以上的 Fragment:;5) 不兼容 React 18 Stream Server-Side Rendering 和 Select…

AI智能系统适合哪些人或团队?

AI智能系统更适合:产品/技术负责人、运营与增长团队、需要落地智能体或自动化的中小团队、关注「AI智能系统」方向的读者。若你只需要单次聊天式问答,可先读概念;若要上生产,请重点看步骤、权限与风控相关段落。

关于「内容管理:从 Hexo 获取数据」,本文给出了什么结论?

在「内容管理:从 Hexo 获取数据」部分,要点是:仍然保留了 Hexo 作为 CMS。 为了调用 Hexo 中的文章数据,首先需要初始化 Hexo 实例、让 Hexo 加载插件、从文件系统读取所有的文章、构建标签和分类的数据结构,最后渲染文章: 加载数据:在 React Server Component 中直接使用 Hexo API 和传递 Hexo 内部数据类型 import { cache } from 'react' ; import Hexo from 'hexo' ; let

关于「加载数据:在 React Server Component 中直接使用 Hexo API 和传递 Hexo 内部数据类型」,本文给出了什么结论?

在「加载数据:在 React Server Component 中直接使用 Hexo API 和传递 Hexo 内部数据类型」部分,要点是:Client Component,SSR / SSG 需要通过 getStaticProps / getServerSideProps 获取数据、序列化成 JSON、然后才能在浏览器中加载、以组件 prop 的形式 populate;而 Hexo 的 API 返回的数据类型大多是 warehouse 的 Document 或 Query 实例,warehouse 为了优化性能, Document 和 Query 实…