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

在Turborepo+shadcn/ui的Next.js Monorepo中配置可复用组件

Monorepo 中 shadcn/ui 可复用组件跨应用复用问题解决

问题描述

已按照 shadcn/ui 指导完成 Monorepo 配置,但遇到核心问题:用 shadcn/ui 构建的可复用组件该存放在哪里?例如 apps 目录下的多数应用会用到结构相似、仅背景和标题等细节不同的落地页组件,希望将这类组件统一放在 packages/shared 目录中。参考 v0.dev 方案配置后,无法在 apps 目录的应用中成功导入这些组件。请问该如何解决?是否必须将组件复制到每个应用,还是有更优方式?

当前配置信息

packages/shared/package.json:

{
    "name": "@workspace/shared",
    "version": "0.0.1",
    "type": "module",
    "license": "MIT",
    "scripts": {
        "lint": "eslint ."
    },
    "dependencies": {
        "@workspace/ui": "workspace:*",
        "lucide-react": "0.456.0",
        "next-themes": "^0.4.3",
        "next": "^15.1.0",
        "react": "^19.0.0",
        "react-dom": "^19.0.0"
    },
    "devDependencies": {
        "@turbo/gen": "^2.2.3",
        "@types/node": "^22.9.0",
        "@types/react": "18.3.0",
        "@types/react-dom": "18.3.1",
        "@workspace/eslint-config": "workspace:*",
        "@workspace/typescript-config": "workspace:*",
        "@workspace/ui": "workspace:*",
        "react": "^18.3.1",
        "tailwindcss": "^3.4.14",
        "typescript": "^5.6.3"
    },
    "exports": {
        "./components/*": "./components/*.tsx"
    }
}

根目录 package.json:

{
  "name": "monorepo",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "lint": "turbo lint",
    "format": "prettier --write \"**/*.{ts,tsx,md}\""
  },
  "devDependencies": {
    "@workspace/eslint-config": "workspace:*",
    "@workspace/typescript-config": "workspace:*",
    "@workspace/shared": "workspace:*",
    "prettier": "^3.2.5",
    "turbo": "^2.3.0",
    "typescript": "5.5.4"
  },
  "packageManager": "pnpm@9.12.3",
  "engines": {
    "node": ">=20"
  }
}

问题修复与最优方案

1. 修正 exports 配置,支持组件递归导入

当前 @workspace/shared 的 exports 仅支持单文件导入,无法覆盖嵌套子目录的组件,调整为:

"exports": {
  "./components": "./components/index.ts",
  "./components/*": "./components/*.tsx",
  "./components/**/*": "./components/**/*.tsx"
}

同时建议在 packages/shared/components 下创建 index.ts,统一导出所有可复用组件,简化应用侧导入:

// packages/shared/components/index.ts
export { default as LandingPage } from './landing-page/LandingPage';
export { default as LandingHeader } from './landing-page/Header';

2. 统一依赖版本,消除冲突

@workspace/shared 中同时存在 React 19 和 React 18 依赖,会导致版本冲突,需统一版本:

  • 删除 devDependencies 中的 react: ^18.3.1,保持 dependencies 中 React 版本一致(或根据项目实际统一为 18.x)
  • 确保 @workspace/ui 等内部包的依赖版本与 shared 包、apps 应用完全匹配

3. 在应用侧正确安装依赖

根目录仅声明 @workspace/shared 为开发依赖是不够的,需在每个 apps 应用中添加生产依赖:

# 在 apps/目标应用目录下执行
pnpm add @workspace/shared@workspace:*

4. 检查 TypeScript 配置一致性

  • 根目录 tsconfig.json 需添加对 packages/shared 的引用:
{
  "references": [{ "path": "./packages/shared" }]
}
  • packages/shared 的 tsconfig.json 需确保编译配置正确:
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "strict": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist"
  },
  "include": ["components/**/*", "index.ts"],
  "exclude": ["node_modules"]
}

5. 验证导入路径正确性

应用侧导入组件时使用以下两种合法路径:

// 方式1:通过统一入口导入
import { LandingPage } from '@workspace/shared/components';

// 方式2:直接导入单个组件
import LandingPage from '@workspace/shared/components/landing-page/LandingPage';

最优实践总结

不需要复制组件到每个应用,推荐的复用方式:

  • 将通用业务组件(如落地页、通用布局)放在 packages/shared
  • 将shadcn/ui 基础组件(如 Button、Card)放在 packages/ui
  • 通过 package.json 的 exports 清晰定义组件导出路径
  • 应用侧通过工作区协议安装依赖,实现跨应用组件复用

内容的提问来源于stack exchange,提问作者habib-N19

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:37:01