【Monorepo实战】pnpm+turbo+vitepress构建公共组件库文档系统

Monorepo架构可以把多个独立的系统放到一起联调,本文记录基于pnpm.workspace功能,如何构建将vitepress和组件库进行联调,并且使用turbo进行任务编排。

技术栈清单: pnpmvitepressturbo

一、需求分析

1、最终目标

我们最终需要实现这样的一个Monorepo项目架构:

--project
  --package.json
  --packages
    --docs
      --package.json
    --project-one
      --package.json
  --pnpm-workspace.yaml

其中各个目录功能如下:

project:根目录

packages:子项目包

packages/docs:基于vitepress的文档项目

packages/project-one:组件库

2、Monorepo技术选型

实现Monorepo架构的方式主要有以下两种:

  • lerna+yarn

  • pnpm中workspace配置

这里选择后者,因为基于pnpm的包管理逻辑使用软硬链接,并且重复使用本地依赖包缓存,可以大大提升安装效率,节省依赖包存储空间。而且pnpm还继承了npm的所有功能,并且支持node版本管理,这里非常推荐pnpm

3、为什么使用vitepress?

之前有使用过vuepress,后来vite伴随vue3一起被推出,体验后果断切换到vite,基于esmodule的调试模式,调试效率直线提升。所以同理,这里也同样推荐使用vitepress,而不是vuepress

4、turbo的作用

turbo全名turborepo,本身也是一个Monorepo管理工具。这里主要使用其任务编排能力,能够按正确的顺序执行Monorepo内的项目的任务。
例如:Monorepo里有三个项目A,B,C。A和C还需要依赖于B。也就是说B项目需要先构建好后,A和C才能构建。

正常每个项目都按照这个顺序做任务编排:lint->build->test->deploy。即检查规范->构建项目->测试项目->部署项目。

img

从上图可以看到,使用lerna时,A、B、Cd这三个项目中的lint、build、deploy都是并行进行的。如果A、C都依赖B,那么A、C在build的时候,很可能 B d还没有build完成,会拖慢A、C的build效率。

但是turbo能够将每个项目里的任务进行拓扑排序再执行。即图中B项目并行执行lint,test,build,之后A和C就可以更快的执行构建,大大提高了整体的效率。

二、开发

1、项目初始化

  1. 创建project根目录packages/docspackages/project-one三个项目目录,然后分别进入这三个目录执行pnpm init做项目初始化,生成package.json文件。
  2. 然后在根目录创建 pnpm-workspace.yaml 文件:
packages:
  - 'apps/*'
  - 'packages/*'

识别packagesapps目录下的项目,作为子项目。这样在执行pnpm -F subProject add XXX --workspace安装命令时,就会到子项目中去寻找名为XXX的包。

完成上述操作后,文件结构如下:

--project
  --package.json
  --packages
    --docs
      --package.json
    --project-one
      --package.json
  --pnpm-workspace.yaml
  --turbo.json

2、turbo编排

  1. 全局安装【turbo】:pnpm add turbo -g
  2. 然后在项目根目录创建turbo.json文件,代码如下:
{
    "$schema": "https://turborepo.org/schema.json",
    "pipeline": {
        "build": {
            "dependsOn": [
                "^build"
            ]
        },
        "test": {
            "dependsOn": [
                "build"
            ],
            "outputs": [],
            "inputs": [
                "src/**/*.tsx",
                "src/**/*.ts",
                "test/**/*.ts",
                "test/**/*.tsx"
            ]
        },
        "lint": {
            "outputs": []
        },
        "deploy": {
            "dependsOn": [
                "build",
                "test",
                "lint"
            ],
            "outputs": []
        }
    }
}

配置项说明:

  • $schema:定义了 json 的类型,类似于 ts 对于 js 的约束
  • dependsOn:表示当前命令所依赖的相关流程
  • pipeline.build:表示当执行 turbo build 时会预先执行 ^build^build 就是所有项目的 package.json 里的那个 build 脚本,^ 是一个标记。如果像 pipeline.test 中的 build,他就指的是 pipeline 中的第一个 build 命令。
  • outputs:指定缓存输出目录
  • inputs: 配置的目录下文件有变化,才会重新执行此命令

了解更多请参照:turbo官网

3、根目录script命令行代理

#package.json
"scripts": {
    "turbo-test": "turbo run test",
    "turbo-build": "turbo run build",
    "test": "echo \"Error: no test specified\" && exit 1",
    "docs:dev": "pnpm --filter \"docs\" dev",
    "docs:build": "pnpm --filter \"docs\" build",
    "docs:serve": "pnpm --filter \"docs\" serve",
    "docs:preview": "pnpm --filter \"docs\" preview",
    "one:dev": "pnpm --filter \"project-one\" dev"
}

#docs package.json
"scripts": {
    "dev": "vitepress dev",
    "build": "vitepress build",
    "serve": "vitepress serve",
    "preview": "vitepress preview",
    "test": "echo \"Error: no test specified\""
}

#project-one package.json
"scripts": {
    "dev": "node index2.js",
    "build": "node index2.js",
    "test": "echo \"Error: no test specified\""
}

4、初始化project-one项目

代码如下:

#index.js
const addOne = (x = 0, msg = '未填') => {
    console.log('调用project-one的项目是:', msg);
    return x + 1;
}
export default addOne

#index2.js
console.log('nihao index2');

5、初始化docs项目

docs使用vitepress构建,打开终端,进入docs目录,执行下面命令,对docs初始化:

# 安装vitepress
pnpm add -D vitepress 

# 初始化项目,这里会出现交互式命令行,默认回车下一步就行
pnpm dlx vitepress init

调整docs/package.json代码如下:

{
  "name": "docs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "vitepress dev",
    "build": "vitepress build",
    "serve": "vitepress serve",
    "preview": "vitepress preview",
    "test": "echo \"Error: no test specified\""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "project-one": "workspace:^",
    "vitepress": "1.0.0-rc.20",
    "vue": "^3.2.45"
  },
  "devDependencies": {}
}

创建docs/index.md文件,代码如下:

---
layout: home
hero:
  name: VitePress
  text: Vite & Vue powered static site generator.
  tagline: Lorem ipsum...
  actions:
    - theme: brand
      text: Get Started
      link: https://github.com/jkkdeng
    - theme: alt
      text: View on GitHub
      link: https://github.com/jkkdeng

features:
  - icon: 🛠️
    title: Simple and minimal, always
    details: Lorem ipsum...
  - icon: 🛠️
    title: Simple and minimal, always
    details: Lorem ipsum...
  - icon: 🛠️
    title: Simple and minimal, always
    details: Lorem ipsum...
---
<script setup>
import addOne from 'project-one'
addOne(10,'docs')
</script>

注:import addOne from 'project-one',这行会在所有子项目中寻找project-one项目,然后识别project-one/package.json"main": "index.js",配置,然后获取到exportaddOne方法。最终打印到浏览器控制台。

6、执行

到这里就基本都配置完成了,这里我们把项目跑起来,看下运行效果。

我们打开终端命令行,进入project根目录.

  1. 执行pnpm run turbo-build

    #turbo.json 
    "build": {
       "dependsOn": ["^build"]
    },
    

    系统会找到turbo.jsonpipeline.build下的配置:"dependsOn": ["^build"]^build含义是指上游的build任务优先执行。猜测turbo应该对各个子包中的package.json进行扫描,查看是否存在依赖关系,例如我们这里是docs项目依赖project-one项目,所有优先对proect-one项目进行build,然后在对docs进行build。看下面的运行结果也的确如此。
    image-20231009164000877

  2. 执行pnpm run turbo-test

    #turbo.json 
    "test": {
       "dependsOn": ["build"]
    },
    

    这里的build就是pipeline中的build任务,含义是:每个项目要执行自己的test任务,就要先执行build任务。

    可以看到执行顺序依次是:

    • project-one -> build
    • docs -> build
    • project-one -> test
    • docs -> test image-20231009165111296
  3. 执行pnpm run one:dev
    image-20231009165422131

  4. 执行pnpm run docs:dev
    image-20231009165515955

image-20231009165640512

源码

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,让我们解释一下这些术语的含义: - Monorepo:将多个相关项目放在同一个代码中的做法。 - PNPM:一种 Node.js 包管理器,类似于 npm 和 yarn。 - React:一个流行的 JavaScript ,用于构建用户界面。 现在,我们来看一下如何在 Monorepo 中使用 PNPM 和 React: 1. 创建一个 Monorepo 项目,将所有相关项目放在同一个代码中。 2. 在根目录下创建一个 `package.json` 文件,并添加以下内容: ``` { "private": true, "workspaces": [ "packages/*" ] } ``` 这个配置告诉 PNPM,这是一个 Monorepo 项目,并且它应该将所有 `packages/*` 目录下的包视为一个工作空间。 3. 在 `packages/` 目录下创建一个新的 React 应用程序。你可以使用 `create-react-app` 工具来快速创建一个新项目: ``` npx create-react-app my-app ``` 4. 确保在 `packages/my-app` 目录下有一个 `package.json` 文件,并添加以下内容: ``` { "name": "my-app", "version": "0.1.0", "dependencies": { "react": "^17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { "react-scripts": "^4.0.3" } } ``` 这个配置告诉 PNPM,这个包依赖于 React 和 React DOM ,并且需要从 `react-scripts` 包中获取开发依赖项。 5. 在 `packages/my-app` 目录下运行以下命令,安装依赖项: ``` pnpm install ``` 6. 在 `packages/my-app` 目录下运行以下命令,启动 React 应用程序: ``` npm start ``` 这就是在 Monorepo 中使用 PNPM 和 React 的基本步骤。你可以使用相同的方法添加其他包和应用程序,并使用 PNPM 管理它们的依赖项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT飞牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值