使用 pnpm 和 Vite 的 React Monorepo 设置教程:React 项目 + UI、实用程序

2025-06-09

使用 pnpm 和 Vite 的 React Monorepo 设置教程:React 项目 + UI、实用程序

昨天晚上,我在 的文档中发现了一个错误chakra-ui,我最近一直在我的个人项目中使用它。我分叉了这个项目并试图找到错误。该项目被设置为 monorepo,它看起来非常有趣,因为我想有一天尝试设置一个 monorepo。我甚至把它写在了我的待办事项清单上,但我没有机会设置 monorepo。总之,我没有发现错误然后上床睡觉了。我醒得晚了几个小时。我应该睡觉了。当时是凌晨三点。但是我一直想着 mono repo 的结构,无法入睡。几分钟后,我起床并开始使用 pnpm 设置 mono repo。

我想要实现的是以下内容:

  • 为 UI 组件和 Util 函数创建两个包,可以从单独的 React 项目中使用。
  • 创建一个 React 项目并在 React 项目中使用这两个包。
  • 对每个项目进行测试。
  • 安装所有依赖项,运行开发服务器,并从根目录测试每个工作区。

由于实现这些内容是此 mono repo 的主要目标,因此没有考虑常见配置、package.json 和小细节。

在现实世界中,您可能需要考虑很多事情,而且这些事情也可能因各种因素而有所不同。

我将按照以下步骤撰写这篇文章:

  1. 根项目
  2. 网站
  3. 软件包/实用程序
  4. 包/ui
  5. 使用网站上的包
  6. 包起来

此外,我还录制了整个过程并上传到我的 YouTube 频道。由于我创建这个频道是为了练习英语,考虑到我的英语水平,有些内容可能听起来并不自然。不过,如果您想更详细地了解整个过程,我还是建议您观看视频。这是一个纯粹的无剪辑视频,您可以看到我设置 Mono 仓库的所有步骤,例如我搜索了哪些内容、遇到了哪些问题以及如何从头开始解决这些问题。

好的,我们开始吧!


根项目

1.创建文件夹并初始化pnpm



> mkdir monorepo
> cd monorepo
> pnpm init


Enter fullscreen mode Exit fullscreen mode

2. 创建pnpm-workspace.yaml文件并设置工作区路径



packages:
  - 'packages/*'
  - 'website'


Enter fullscreen mode Exit fullscreen mode

网站

1. 使用以下方式设置 React 项目Vite



> pnpm create vite


Enter fullscreen mode Exit fullscreen mode

pnpm create vite 在终端输出

2. 安装软件包



> pnpm install


Enter fullscreen mode Exit fullscreen mode

从根目录安装依赖项。

pnpm 安装输出

pnpm-lock.yaml 及其内容

它将检测工作区并pnpm-lock.yaml在根目录中创建一个。在锁定文件中,依赖项写在包名称下website

3. 添加脚本从根目录运行开发服务器



//...
"scripts": {
  "dev": "pnpm --filter website dev"
},
//...


Enter fullscreen mode Exit fullscreen mode

package.json在根目录的文件中添加脚本。

--filter选项允许我们在工作区下执行脚本website

4.运行dev命令,查看开发服务器是否启动成功



> pnpm run dev


Enter fullscreen mode Exit fullscreen mode

Vite项目初始页面

打开http://localhost:5173,您将看到初始页面。


软件包/实用程序

utils1.在 下创建目录packages



> mkdir -p packages/utils


Enter fullscreen mode Exit fullscreen mode

2. 创建package.json



{
  "name": "@mono/utils",
  "version": "0.0.1",
  "main": "src/index.ts",
  "scripts": {
  }
}


Enter fullscreen mode Exit fullscreen mode

该包已重命名@mono/utils并设置了主文件路径。

3. 设置 TypeScript 环境



> pnpm install -D typescript --filter utils
> pnpm exec tsc --init


Enter fullscreen mode Exit fullscreen mode

4. 在文件中创建函数

在 calc 文件中添加函数

不要忘记从中导出该函数index.ts

5.设置vitest并编写测试代码



>  pnpm install -D vitest --filter utils


Enter fullscreen mode Exit fullscreen mode

[packages/utils/src/calc.test.ts]



import { test, expect } from 'vitest';
import { add } from './calc';

test('add(10, 20) should return 30', () => {
  expect(add(10, 20)).toBe(30);
});


Enter fullscreen mode Exit fullscreen mode

6.在文件中添加测试脚本package.json

[packages/utils/package.json]



{
//...
  "scripts": {
    "test": "vitest run"
  },
//...
}


Enter fullscreen mode Exit fullscreen mode

[package.json]



{
//...
  "scripts": {
    "dev": "pnpm --filter website dev",
    "test:all": "pnpm -r test"
  },
//...
}


Enter fullscreen mode Exit fullscreen mode

-r选项将为每个工作区执行测试命令。

7. 测试



> pnpm run test:all


Enter fullscreen mode Exit fullscreen mode

测试:所有命令输出


包/ui

ui1.使用设置包Vite



> cd packages
> pnpm create vite


Enter fullscreen mode Exit fullscreen mode

使用 vite 创建一个 React 项目

由于该ui软件包是由 创建的Vite,因此实现 UI 组件时可能不需要的一些文件会随附其中。Vite虽然我以前设置得很快,但您可以ui自行设置软件包。这样更合适,因为您可以安装所需的特定依赖项并进行配置。

2.删除不必要的文件

  • src目录下的所有文件
  • 索引.html
  • 公共目录

删除所有不需要的文件后的 UI 目录结构

3.安装依赖项



> pnpm install


Enter fullscreen mode Exit fullscreen mode

命令 pnpm install 的输出

4.创建组件

[packages/ui/src/Button.tsx]



import { ComponentProps } from "react";

const Button = (props: ComponentProps<'button'>) => {
  return (
    <button {...props} />
  )
}

export default Button;


Enter fullscreen mode Exit fullscreen mode

[packages/ui/src/index.ts]



export { default as Button } from './Button';


Enter fullscreen mode Exit fullscreen mode

vitest5. 使用和设置测试环境react-testing-library



> pnpm add -D --filter ui @testing-library/jest-dom vitest jsdom @testing-library/react


Enter fullscreen mode Exit fullscreen mode

[packages/ui/vitest.config.ts]



import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react-swc';

export default defineConfig(({ mode }) => ({
  plugins: [react()],
  resolve: {
    conditions: mode === 'test' ? ['browser'] : [],
  },
  test: {
    environment: 'jsdom',
    setupFiles: ['./vitest-setup.js'],
  },
}));


Enter fullscreen mode Exit fullscreen mode

[packages/ui/vitest-setup.js]



import '@testing-library/jest-dom/vitest';


Enter fullscreen mode Exit fullscreen mode

[packages/ui/tsconfig.json]



{
//...
    "types": ["@testing-library/jest-dom"],
//...
}


Enter fullscreen mode Exit fullscreen mode

import '@testing-library/jest-dom/vitest';来自 vitest-setup.js 使您能够使用 jest-dom 函数,例如toBeInDocumentwith vitest

此外,要查看正确的类型,您应该在字段中添加 jest-dom 类型types

6.编写测试代码

[src/packages/ui/Button.test.tsx]



import { test, expect} from 'vitest';
import { render, screen} from '@testing-library/react'
import Button from './Button';

test('Button shuold be rendered', () => {
  render(<Button>Hello</Button>);

  expect(screen.getByText(/Hello/)).toBeInTheDocument();
});


Enter fullscreen mode Exit fullscreen mode

7.添加测试脚本

[src/packages/ui/package.json]



{
  "name": "@mono/ui",
  "main": "src/index.ts",
//...
  "scripts": {
    "test": "vitest run"
  },
//...
}


Enter fullscreen mode Exit fullscreen mode

该包已重命名@mono/ui并设置了主文件路径。

8. 运行测试:全部

测试结果:all 命令


使用网站上的包

1.在package.json中添加依赖项

[网站/package.json]



{
//...
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "@mono/ui": "workspace:*",
    "@mono/utils": "workspace:*"
  },
//...
}


Enter fullscreen mode Exit fullscreen mode

2.安装依赖项



pnpm install


Enter fullscreen mode Exit fullscreen mode

3.编写代码

[网站/src/App.tsx]



import { ChangeEvent, useState } from 'react'
import { Button } from '@mono/ui';
import { add } from '@mono/utils';

function App() {
  const [nums, setNums] = useState({
   a: '',
   b: '', 
  })

  const handleNumChange = (key: keyof typeof nums) => (e: ChangeEvent<HTMLInputElement>) => {
    setNums(prevNums => ({
      ...prevNums,
      [key]: e.target.value,
    }));
  };


  return (
    <div>
      <input type='text' value={nums.a} onChange={handleNumChange('a')} />
      <input type='text' value={nums.b} onChange={handleNumChange('b')} />
      <Button onClick={() => {
        alert(add(Number(nums.a), Number(nums.b)));
      }}>Add</Button>
    </div>
  )
}

export default App


Enter fullscreen mode Exit fullscreen mode

4. 结果

结果


包起来

探索一些 mono repos,您将了解如何设置您的项目。husky,tsconfig 文件的常见设置等,您可以设置很多东西,还需要考虑版本控制,依赖关系等。

我希望您发现它有用并且编码愉快!


完整源代码

鏂囩珷鏉ユ簮锛�https://dev.to/lico/react-monorepo-setup-tutorial-with-pnpm-and-vite-react-project-ui-utils-5705
PREV
如何阅读更多书籍📚
NEXT
全栈琐事:你能在 5 分钟内回答这些面试问题吗?