You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在@company/ui包中安全导出React服务端与客户端组件?

不用必须拆成两个独立包,试试这些方案

你遇到的编辑器自动补全丢失问题,主要是server-only风格的exports配置没配合好类型声明导致的,没必要直接拆包,下面几个方案可以解决问题:

1. 分环境的条件导出 + 完整类型声明

在package.json里配置多入口的exports,把客户端、服务端、共享组件分开,同时给每个入口配上对应的.d.ts类型文件,编辑器就能识别并提供补全:

package.json 配置示例

{
  "exports": {
    ".": {
      "import": "./index.js",
      "types": "./index.d.ts"
    },
    "./client": {
      "browser": "./client/index.js",
      "import": "./client/index.js",
      "types": "./client/index.d.ts"
    },
    "./server": {
      "node": "./server/index.js",
      "import": "./server/index.js",
      "types": "./server/index.d.ts"
    }
  }
}

目录结构示例

@company/ui/
├── index.js          # 只导出共享组件(Avatar、ErrorBoundary)
├── index.d.ts
├── client/
│   ├── index.js      # 导出客户端专属组件(Button、Modal)
│   └── index.d.ts
└── server/
    ├── index.js      # 导出服务端专属组件(Layout、Sidebar)
    └── index.d.ts

用户可以按需导入:

// 导入共享组件
import { Avatar } from '@company/ui';
// 导入客户端组件
import { Button } from '@company/ui/client';
// 导入服务端组件
import { Layout } from '@company/ui/server';

每个入口的类型文件都完整声明导出的组件,编辑器就能正常补全了。

2. 给客户端组件加'use client'指令,桶文件全量导出

给所有客户端专属组件的文件顶部加上'use client'指令,然后在根目录的index.js里全量导出所有组件:

客户端组件示例(Button.js)

'use client';

export const Button = ({ children }) => {
  // 客户端组件逻辑
  return <button>{children}</button>;
};

根目录index.js

// 共享组件
export { Avatar, ErrorBoundary } from './shared';
// 客户端组件(已加'use client')
export { Button, Modal } from './client-components';
// 服务端组件
export { Layout, Sidebar } from './server-components';

这种方式下,React会自动识别带'use client'的组件,不会让服务端代码加载客户端逻辑,同时根目录的类型声明文件(index.d.ts)正常导出所有组件的类型,编辑器补全不受影响。

3. 用类型别名区分环境组件

如果不想改目录结构,也可以在类型声明文件里用类型别名把客户端、服务端组件分组,让编辑器能清晰提示:

index.d.ts 示例

import type { Button, Modal } from './client-components';
import type { Layout, Sidebar } from './server-components';
import { Avatar, ErrorBoundary } from './shared';

export { Avatar, ErrorBoundary };
export { Button, Modal };
export { Layout, Sidebar };

// 类型别名,方便编辑器识别分组
export type ClientUIComponents = {
  Button: typeof Button;
  Modal: typeof Modal;
};

export type ServerUIComponents = {
  Layout: typeof Layout;
  Sidebar: typeof Sidebar;
};

这样用户在导入时,编辑器会提示哪些属于客户端组件、哪些属于服务端组件,同时组件的正常导出不受影响。


如果你的团队规模较大,拆成@company/ui-client和@company/ui-server能让职责划分更清晰,那拆包也是可行的,但不是解决问题的必要选项。上面的方案都能在保留单包结构的前提下,解决编辑器补全问题,同时避免污染React服务端组件。

内容的提问来源于stack exchange,提问作者SayJeyHi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:00:12