Nx Next.js 库生成实战:创建库与导出 React Server Components
【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx
导读
@nx/next为 Nx 工作区提供了一整套 Next.js 项目生成器,其中library生成器用于创建可供应用复用的 Next.js 库。与普通的 React 库不同,Next.js 库自带一个额外的src/server.ts入口,专门用于导出 React Server Components(RSC),从而避免客户端组件与服务器组件混用导致运行时错误。本文基于 packages/next/docs/library-examples.md 展开,结合 library 生成器源码 与 schema.json,完整讲解库的创建方式、常用配置项以及 RSC 双入口机制背后的实现原理。读完本文,你将能够熟练地在 Nx 工作区中创建任意路径下的 Next.js 库,并正确组织客户端组件与服务器组件的导出。
创建库的基本命令
@nx/next:library生成器的核心用法与@nx/react:library保持一致,但输出额外包含server入口点和 Next.js 类型声明(详见 schema.json 的描述)。
创建新库
在 Nx 工作区根目录执行以下命令,即可在默认位置生成一个名为my-lib的库:
nx g lib libs/my-lib命令执行后,@nx/next会依次执行内部的初始化流程(调用链见 library.ts):
- 调用
@nx/js的initGenerator完成 JS/TS 工具链初始化; - 调用
nextInitGenerator完成 Next.js 相关依赖与配置初始化; - 复用
@nx/react的libraryGenerator生成 React 库骨架。
也就是说,Next.js 库是 React 库的超集——它继承了 React 库的全部结构,再叠加 Next.js 专属的入口与类型配置。生成器还会自动向tsconfig.lib.json的compilerOptions.types中追加next与@nx/next/typings/image.d.ts(library.ts),确保库内的 Next.js 代码(如Image组件、样式导入)获得正确的类型支持。这一点也有对应的单元测试验证,见 library.spec.ts。
在指定目录下创建库
将directory参数(也支持别名dir)指向一个子目录,即可把库生成在嵌套路径中:
nx g lib libs/shared/my-lib上面的命令会在libs/shared/my-lib位置生成库。directory是生成器的位置参数($default指定为 argv 的第一个参数),它会与name一起经由determineProjectNameAndRootOptions推导出最终的projectRoot与importPath(见 normalize-options.ts)。默认情况下,导入路径由目录结构推导而来,例如libs/shared/my-lib对应的导入名通常为@proj/shared/my-lib(其中proj为工作区名,可通过--importPath显式覆盖)。
常用配置项速查
@nx/next:library的参数与@nx/react:library对齐(测试 library.spec.ts 专门校验了两者的 schema 保持同步),核心选项如下:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
directory | string | — | 库所在的目录,必填,作为位置参数 |
name | string | — | 库名,支持@scope/name形式 |
style | string | css | 样式文件格式,可选css、scss、none |
bundler | string | none | 打包器,可选none、vite、rollup;none表示不可构建 |
linter | string | 工作区默认 | 静态检查工具,可选eslint、oxlint、none |
unitTestRunner | string | none | 单元测试运行器,可选vitest、jest、none |
inSourceTests | boolean | false | 使用 Vitest 时把测试内联到源码文件(import.meta.vitest)而非生成独立 spec 文件 |
importPath | string | 自动推导 | 库的导入路径,如@myorg/my-awesome-lib |
component | boolean | true | 是否生成默认组件 |
js | boolean | false | 生成 JavaScript 而非 TypeScript 文件 |
globalCss | boolean | false | 为true时使用全局 CSS 而非 CSS Modules |
strict | boolean | true | 是否启用 tsconfig 严格模式 |
compiler | string | babel | 编译器,可选babel、swc |
buildable | boolean | false | (已弃用)生成可构建库,请改用bundler |
publishable | boolean | false | 生成可发布库 |
routing | boolean | — | 生成带路由的库,配合appProject使用 |
appProject | string | — | 要将库路由挂载到的应用项目 |
tags | string | — | 为库添加标签(用于约束依赖的 lint 规则) |
skipTsConfig | boolean | false | 不更新tsconfig.json |
skipPackageJson | boolean | false | 不向package.json添加依赖 |
enableTypedLinting | boolean | false | 启用类型感知的 ESLint 检查(为性能默认关闭) |
一个覆盖常见场景的完整示例:
nx g lib libs/shared/ui --style=scss --bundler=vite --unitTestRunner=vitest --importPath=@myorg/ui --tags="scope:shared,type:ui"生成器会为带单元测试运行器的库自动安装@testing-library/react与@testing-library/dom依赖;选择swc编译器时还会自动加入@swc/core(library.ts,测试见 library.spec.ts)。
导出 React Server Components:双入口机制
Next.js 库区别于普通 React 库的核心,在于其第二个入口src/server.ts。这一点在原文档中有明确说明,生成器源码也给出了直接注释:从src/index.ts导出 RSC 会把整个文件标记为 server-only,当客户端组件引入该文件时就会抛错(见 library.ts,相关历史问题见 Nx issue #15830 的注释)。
为什么需要单独的 server 入口
在 React Server Components 架构下,客户端组件(带'use client'指令或需要交互逻辑)与服务器组件(可异步访问数据库、API)的执行环境完全不同。若将两者混在同一个入口文件导出:
- 服务器组件会要求调用方运行在服务器上下文;
- 客户端组件一旦 import 该文件,就会把 server-only 代码带入客户端 bundle,导致构建或运行时错误。
因此生成器在创建库时生成了两个职责明确的入口文件:
src/index.ts:导出 React 客户端组件(带'use client'指令的组件)及其他非服务器工具函数;src/server.ts:专门导出 React 服务器组件。
生成器写入的src/index.ts顶部注释即为:“Use this file to export React client components (e.g. those with 'use client' directive) or other non-server utilities”;src/server.ts则写入“Use this file to export React server components”,并默认导出一个HelloServer异步组件(library.ts)。
应用中的消费方式
原文档给出了在应用中使用库的标准姿势:客户端组件从库根路径导入,服务器组件从/server子路径导入:
// apps/my-app/app/page.tsx import { MyComponent } from '@myorg/my-lib'; import { HelloServer } from '@myorg/my-lib/server';要让@myorg/my-lib/server这条子路径在开发与构建时都能正确解析,生成器会同步完成三处接线(测试断言见 library.spec.ts):
- tsconfig 路径映射:在
tsconfig.base.json的compilerOptions.paths中追加@proj/my-lib/server -> ./my-lib/src/server.ts; - Vite 多入口配置(使用
bundler=vite时):把vite.config.mts中单一的entry: 'src/index.ts'改写为{ index: 'src/index.ts', server: 'src/server.ts' }多入口对象,并将fileName改为按入口名输出的函数(update-vite-config.ts); - package.json exports:向库的
package.json添加./server导出映射,指向./dist/server.js/./dist/server.d.ts(测试见 library.spec.ts)。
在 TS Solution 工作区(使用references+customConditions的现代配置)中,非可构建库会在package.json的exports['./server']里直接映射到源码./src/server.ts,并通过自定义 condition 指向开发源码;可构建库则映射到dist产物(library.ts)。
使用约束与最佳实践
结合原文档与源码,可以总结出以下实践准则:
- 客户端组件与纯工具函数一律放在
src/index.ts中导出; - 服务器组件(如需要直接访问数据库、密钥或服务端 API 的异步组件)放在
src/server.ts中导出; - 不要在
src/index.ts中导出任何服务器组件,否则会污染整个入口的模块边界; - 应用侧按需选择导入路径:页面与客户端组件引用
@myorg/my-lib,仅服务端代码引用@myorg/my-lib/server。
小结
@nx/next的 library 生成器把"创建库"与"RSC 正确导出"这两件事自动化了:一条nx g lib命令即可在任意目录生成结构完整的 Next.js 库,同时自动搭建src/index.ts(客户端)与src/server.ts(服务器组件)的双入口,并完成 tsconfig 路径、Vite 构建入口与 package.json exports 的全部接线。理解这套机制后,你可以在 Nx 工作区中放心地按"客户端/服务器"维度组织库的导出边界,避免 RSC 混用带来的构建陷阱。更多命令示例可参考同目录下的 application-examples.md、component-examples.md 与 page-examples.md;深入理解生成器实现可阅读 library.ts 及其配套测试 library.spec.ts。
【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考