首页 >web前端 >js教程 >使用 PNPM 在 Monorepo 中构建并运行您的项目

使用 PNPM 在 Monorepo 中构建并运行您的项目

Patricia Arquette
Patricia Arquette原创
2025-01-19 16:33:12314浏览

Build and run your project in Monorepo with PNPM

项目代码组织:Polyrepo vs. Monorepo

项目代码组织主要有两种方式:

  1. Polyrepo: 将项目代码分散在不同的仓库中。这是当前的标准做法,多个团队分别拥有自己的仓库、构建产物和流水线,拥有自主权。
  2. Monorepo: 将所有项目代码集中在一个仓库中。项目被划分为应用程序和包,方便代码复用和共享标准功能,有助于统一第三方包版本、递归构建依赖项的源代码以及使用相同的工具进行CI/CD流水线。

许多大型科技公司都使用Monorepo,例如Yandex。Monorepo有助于在团队和业务部门之间共享创意和最佳实践。更多关于Monorepo和相关工具的信息,请访问https://www.php.cn/link/b01ccf4f29b57b0b1bdb9407050db28d。本文将重点介绍使用PNPM构建Monorepo的简单方案。

PNPM使用工作区(workspaces)来整合单个仓库中的多个项目。

环境搭建

首先,创建一个空文件夹作为新的Monorepo项目。在仓库内初始化PNPM:

<code class="language-bash">pnpm init</code>

然后,创建一个pnpm-workspace.yaml文件,描述包文件夹:

<code class="language-yaml">// pnpm-workspace.yaml

packages:
  - 'packages/**'
  - 'apps/**'</code>

/packages文件夹存放共享库,/apps文件夹存放应用程序(例如,独立的React Native移动应用程序和使用相同组件或连接库与API服务器通信的Web应用程序)。

本文将使用一个Telegram发布机器人为例,其源代码位于GitHub:https://www.php.cn/link/8164ca2fe04767628ac1c6813e8a0867。下载并解压到/apps/publish-bot文件夹,然后运行安装命令:

<code class="language-bash">pnpm install</code>

创建Telegram工具包

/packages文件夹中创建一个名为telegram-utils的文件夹,初始化PNPM和TypeScript:

<code class="language-bash">pnpm init && pnpm add -D typescript && pnpm tsc --init</code>

该包将提供一个函数,用于组合来自所有消息(文本、视频和照片)的文本和标题。需要安装Telegraf包:

<code class="language-bash">pnpm add telegraf</code>

所有源代码都应位于/src目录中。为了方便功能分组,建议创建不同的文件夹。组合文本的功能位于/texts文件夹中,代码如下:

<code class="language-typescript">// packages/telegram-utils/src/texts/combineTexts.ts

import { Message } from 'telegraf/types';
import { FmtString, join } from 'telegraf/format';

type GroupedMessages = {
    photos: Array<Message.PhotoMessage>;
    videos: Array<Message.VideoMessage>;
    text: Array<Message.TextMessage>;
};

export const combineTexts = ({ photos, videos, text }: GroupedMessages) => {
    const photoTexts = photos
        .map(photo => photo.caption ? new FmtString(photo.caption, photo.caption_entities) : undefined)
        .filter((t): t is Required<FmtString> => t !== undefined);

    const videoTexts = videos
        .map(video => video.caption ? new FmtString(video.caption, video.caption_entities) : undefined)
        .filter((t): t is Required<FmtString> => t !== undefined);

    const allTexts = [];

    if (text.length) allTexts.push(join(text.map(t => new FmtString(t.text, t.entities))), '\n');
    if (photoTexts.length) allTexts.push(join(photoTexts, '\n'));
    if (videoTexts.length) allTexts.push(join(videoTexts, '\n'));

    return join(allTexts, '\n');
};</code>

代码说明:

  • 函数输入按类型分组的消息:照片、视频或文本;
  • 媒体消息应转换为包含标题和标题实体的FMT字符串。对于后续过滤,应返回undefined
  • 分步连接文本数组,最终将所有文本组合成一条大消息。

创建/texts文件夹的索引文件:

<code class="language-bash">pnpm init</code>

package.json文件中使用exports字段设置包功能的导出:

<code class="language-yaml">// pnpm-workspace.yaml

packages:
  - 'packages/**'
  - 'apps/**'</code>

为了在应用程序中识别Monorepo包,为所有包添加前缀@monorepo。重命名package.json文件中的telegram-utils包:

<code class="language-bash">pnpm install</code>

添加构建脚本:

<code class="language-bash">pnpm init && pnpm add -D typescript && pnpm tsc --init</code>

完整的package.json文件:

<code class="language-bash">pnpm add telegraf</code>

配置TypeScript编译器:启用增量编译以节省构建时间,仅处理更改的部分;启用复合编译以使用项目引用。将/src文件夹定义为rootDir,将包的outDir定义为/dist。更新后的tsconfig.json

<code class="language-typescript">// packages/telegram-utils/src/texts/combineTexts.ts

import { Message } from 'telegraf/types';
import { FmtString, join } from 'telegraf/format';

type GroupedMessages = {
    photos: Array<Message.PhotoMessage>;
    videos: Array<Message.VideoMessage>;
    text: Array<Message.TextMessage>;
};

export const combineTexts = ({ photos, videos, text }: GroupedMessages) => {
    const photoTexts = photos
        .map(photo => photo.caption ? new FmtString(photo.caption, photo.caption_entities) : undefined)
        .filter((t): t is Required<FmtString> => t !== undefined);

    const videoTexts = videos
        .map(video => video.caption ? new FmtString(video.caption, video.caption_entities) : undefined)
        .filter((t): t is Required<FmtString> => t !== undefined);

    const allTexts = [];

    if (text.length) allTexts.push(join(text.map(t => new FmtString(t.text, t.entities))), '\n');
    if (photoTexts.length) allTexts.push(join(photoTexts, '\n'));
    if (videoTexts.length) allTexts.push(join(videoTexts, '\n'));

    return join(allTexts, '\n');
};</code>

整合

回到/apps/publish-bot,将@monorepo/telegram-utils包添加到依赖项中。注意,不需要指定包版本,使用workspace:*表示:

<code class="language-typescript">// packages/telegram-utils/src/texts/index.ts

export * from './combineTexts';</code>

安装依赖项:

<code class="language-json">// packages/telegram-utils/package.json

"exports": {
    "./texts": {
        "import": "./src/texts/index.ts",
        "require": "./dist/texts/index.js"
    }
}</code>

更新发布机器人的preview命令:

<code class="language-json">// packages/telegram-utils/package.json

"name": "@monorepo/telegram-utils"</code>

更新/apps/publish-bot/tsconfig.json

<code class="language-json">// packages/telegram-utils/package.json

"scripts": {
    "build": "tsc -p tsconfig.json"
}</code>

构建应用代码前,需要先构建所有依赖项:

<code class="language-json">// packages/telegram-utils/package.json

{
    "name": "@monorepo/telegram-utils",
    "version": "1.0.0",
    "main": "index.js",
    "scripts": {
        "build": "tsc -p tsconfig.json"
    },
    "keywords": [],
    "license": "ISC",
    "exports": {
        "./texts": {
            "import": "./src/texts/index.ts",
            "require": "./dist/texts/index.js"
        }
    },
    "devDependencies": {
        "typescript": "^5.7.3"
    },
    "dependencies": {
        "telegraf": "^4.16.3"
    }
}</code>

总结

现在,发布机器人使用内部共享库/包,并位于Monorepo中。这使得快速构建新功能和在多个应用程序中重用代码成为可能。

图片来自Unsplash的Gabriel Heinzer

以上是使用 PNPM 在 Monorepo 中构建并运行您的项目的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn