使用 Turborepo 管理的 Monorepo 项目中如何共享代码

上篇文章中介绍了 Turborepo 管理 Monorepo 项目的基本使用。其中提到按照常见的开发约束,我们一般会将完整的应用放在 apps 目录下,将共享代码的部分抽取分装成多个包放在 packages 目录下。在实际项目开发中,当项目增多和需求复杂,在不同项目中复用和共享公用代码是十分常见的最佳实践。

本文介绍在使用 Turborepo 管理的 Monorepo 项目中如何共享代码。主要参考以下几篇官方文档:

内部库和外部库(Internal Packages, External packages)

按照 Turborepo 文档 ,会先将公用代码区分为内部库和外部库(Internal Packages, External Packages

  • 内部库(Internal Packages),指只会在同一个 Monorepo 项目中使用的,通常很简单搭建起来,并且不需要经过打包(打包由引用的项目打包时一起打包)、发布版本环节提供给外部项目使用,这是本文主要讨论的使用方式。
  • 外部库(External packages),通常会经过打包、发布版本、推送到一个集中的 npm 仓库提供给不同的项目使用,在跨项目使用的场景下使用,比如团队内基础组件库

搭建一个内部库

1. 创建项目

bash 复制代码
mkdir packages/math-helpers

package.json 申明内部库名称,以及如果有需要的第三方依赖

json 复制代码
{
  "name": "math-helpers",
  "version": "0.0.1",
  "dependencies": {
    "typescript": "latest"
  }
}

创建 src 文件夹,并且导出公共代码。

如在 packages/math-helpers/src/index.ts 中创建 add, subtract 示例函数

typescript 复制代码
export const add = (a: number, b: number) => {
  return a + b;
};

export const subtract = (a: number, b: number) => {
  return a - b;
};

另外由于是 Typescript 项目,不要忘记配置 tsconfig.json

packages/math-helpers/tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "preserveWatchOutput": true,
    "skipLibCheck": true,
    "noEmit": true,
    "strict": true
  },
  "exclude": ["node_modules"]
}

这样一个最简单的内部库即创建完成。

2. 定义导出文件路径

需要在 package.json 中明确申明内部库文件的导出路径,这样使用内部库的应用才能找到对应文件。如定义 exports 这个字段,所有文件都从 ./src/index.ts 引入。

json 复制代码
{
  "name": "math-helpers",
  "exports": {
    ".": "./src/index.ts"
  },
  "dependencies": {
    "typescript": "latest"
  }
}

3. 应用中使用内部库

首先在 apps/web/package.json 中加入依赖,这里由于是项目内文件,直接填 * 即可

json 复制代码
{
  "dependencies": {
    "math-helpers": "*"
  }
}

注意 pnpmnpm, yarn 不同包管理工具对于依赖引用的区别

json 复制代码
{
  "dependencies": {
    "math-helpers": "workspace:*"
  }
}

使用的时候,直接从包名引入,就和我们常见的 npm 包一样使用。

typescript 复制代码
import { add } from "math-helpers";
 
add(1, 2);

4. 配置打包工具识别和打包引用的内部库

如果我们直接启动应用,一般会遇到报错,比如 Next.js 的报错:

bash 复制代码
../../packages/math-helpers/src/index.ts
Module parse failed: Unexpected token (1:21)
You may need an appropriate loader to handle this file type,
currently no loaders are configured to process this file.
See https://webpack.js.org/concepts#loaders
> export const add = (a: number, b: number) => {
|   return a + b;
| };

我们需要配置打包工具,让他能正确识别和打包引用的内部库,不同的打包工具配置不一样,如 Next.js 中的 transpilePackages 配置

javascript 复制代码
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ['math-helpers'],
};
 
module.exports = nextConfig;

Umi 项目中如果开启了 mfsu,建议将内部库排除,避免内部库代码更新由于 mfsu 缓存 而未生效。

javascript 复制代码
{
  mfsu: {
    strategy: 'normal',
    exclude: ['math-helpers'],
  },
}

Vite 项目模式是会打包依赖的,所以不需要额外配置。

实践中遇到的问题

Umi 框架下暂时不支持解析只定义了 exports 导出的依赖。

解决方法:main 字段中定义导出文件路径,如:

json 复制代码
{
  "name": "math-helpers",
  "main": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts"
  },
}

实际上,依赖的路径解析是一个非常复杂的话题,本文不详细展开。具体可以参考 Node.js 文档

参考链接

相关推荐
IT_陈寒43 分钟前
JavaScript里这个隐式类型转换的坑,我终于爬出来了
前端·人工智能·后端
方呵呵1 小时前
一个 3.5k Star Vue H5 项目的二次进化:我把它重构成了 Monorepo 工程体系
前端
_风满楼1 小时前
HTTP 请求的五种传参方式
前端·javascript·后端
木斯佳2 小时前
前端八股文面经大全:字节暑期前端一面(2026-04-22)·面经深度解析
前端
光影少年2 小时前
前端线上屏幕出现卡顿如何排查?
开发语言·前端·javascript·学习·前端框架·node.js
Yeh2020582 小时前
request与response笔记
java·前端·笔记
像我这样帅的人丶你还2 小时前
前端监控体系与实践:从错误上报到内存与 GC 观测
前端·javascript·架构
前端毕业班2 小时前
uni-app 小程序主包瘦身指南 - 分包 node_modules
前端
LinDaiDai_霖呆呆2 小时前
我用 Claude Code 一天搭了个高扩展性的 Web 3D 编辑器 SDK,但最有价值的不是代码 🔥
前端·ai编程·claude
AZaLEan__2 小时前
Flex 弹性布局学习总结
前端·css·css3