SSF0SSF0
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
  • HTML

    • html1
    • html2
  • CSS

    • Flex 布局常见问题与解决方案
  • JavaScript

    • 数据类型及引用问题
    • 处理 Blob 类型文件下载问题总结
    • localStorage 与 sessionStorage 区别
    • JavaScript 中的 script 标签问题详解
    • JavaScript 中的`this`指向问题详解
    • SessionStorage踩坑记录:它真的能"只设置一次"吗?
    • 动态加载 JS 脚本方法对比
    • 浏览器页面关闭场景下的数据上报
  • es6

    • Promise
    • es6 模块导出方式全解析
  • Vue2

    • created VS mounted 发起异步请求
    • vue2-2
  • Vue3

    • Vite + Vue3 修改 element-plus 源码
    • Vue v-if 与 v-show
    • Vue3 ref 获取组件
    • Vue3 路由传参
    • 父子组件与组件里 Hooks 加载顺序
    • 第三方组件传入参数TS提示
    • Vue3 Props 在 Hooks 中的响应性处理
    • Vue Router 的两种历史模式及部署配置详解
    • 在Vue 3项目中顺利集成Tailwind CSS的完整指南
    • Vue 3 深度选择器:deep()完全指南
  • Electron

    • 快速构建 electron + vue3 项目
  • TS

    • TS 泛型
    • 记录模板使用断言的问题
    • type 与 interface
  • WebPack

    • Webpack 介绍
  • Vite

    • Vite CLI 常见命令
    • vite 与 webpack 比较
  • 项目工程

    • 前端代码风格
    • Vue3 项目规范
    • npm 镜像问题
    • 包管理工具
    • 使用 engines 限制开发环境依赖
    • 打包与shell交互指定模式
    • 使用 pnpm 构建 Monorepo 实战指南
    • pnpm 修改依赖源码打包报错
  • 记录一下小程序
  • 控制浏览器正确保存网站账号密码的技巧

使用 pnpm 构建 Monorepo 实战指南

1. 项目背景与目标

本文记录了使用 Vue3 创建一个示例集合项目的完整过程。这个项目旨在记录 Vue3 的使用案例、错误案例以及相关 demo,采用了 monorepo 结构组织代码,以便更好地管理多个相关但独立的示例。

2. 项目初始化与技术选型

2.1 核心技术栈

技术选型

  • 框架: Vue 3

  • 语言: TypeScript

  • 构建工具: Vite

  • 包管理工具: pnpm

  • 项目组织: Monorepo (pnpm workspace)

  • 路由: Vue Router 4

目录结构设计

在规划项目结构时,考虑了两种主要分类方式:

  1. 第一种结构:在 demos 下进一步细分

    packages/
    ├── demos/
    │   ├── composition-api/
    │   ├── pinia-store/
    │   ├── vue-router/
    │   └── 其他具体demo...
    ├── best-practices/
    └── error-cases/
  2. 第二种结构:直接在 packages 下放置所有 demo(扁平结构)

    packages/
    ├── demo-composition-api/
    ├── demo-pinia-store/
    ├── demo-vue-router/
    ├── best-practice-performance/
    ├── error-case-lifecycle/
    └── 其他packages...

经过讨论,最终决定采用简化后的第一种结构,将示例分为两大类:

packages/
├── plugins/       # 插件使用说明/案例
│   ├── vue-router/
│   ├── pinia/
│   └── 其他插件...
└── demos/         # 功能演示(包含错误案例及补救方法)
    ├── composition-api/
    ├── lifecycle/
    └── 其他功能性demo...

这种结构的优点是分类明确,容易查找,同时插件使用和功能演示有清晰的区分。

2.3 项目创建步骤

  1. 创建基础项目:

    pnpm create vite . --template vue-ts
    pnpm install
    pnpm add vue-router@4
  2. 创建工作空间结构:

    mkdir packages
    cd packages
    mkdir plugins demos
  3. 配置工作空间:

    创建pnpm-workspace.yaml文件:

    packages:
      - "packages/**/*"
  4. 创建示例项目:

    cd packages/demos
    pnpm create vite demo-composition-api --template vue-ts
    cd ../plugins
    pnpm create vite plugin-vue-router --template vue-ts

3. 常见问题与解决方案

问题 1:子项目依赖重复安装

问题描述:在创建子项目时,每个项目都安装了自己的依赖,导致依赖重复。

解决方案:将共享依赖移到根目录的package.json中,删除子项目中的重复依赖。

更新前的子项目 package.json:

{
  "dependencies": {
    "vue": "^3.5.13",
    "vue-router": "4"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.2.1",
    "@vue/tsconfig": "^0.7.0",
    "typescript": "~5.7.2",
    "vite": "^6.2.0",
    "vue-tsc": "^2.2.4"
  }
}

更新后的子项目 package.json:

{
  "name": "@vue3-example/plugin-vue-router",
  "private": true,
  "version": "0.0.1",
  "type": "module",
  "scripts": {
    "dev": "vite --port 3001",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  }
}

问题 2:项目配置文件的有效性

问题描述:担心将依赖移至根目录后,子项目的配置文件如vite.config.ts和tsconfig.json会失效。

解决方案:子项目的配置文件仍然有效,因为这些配置文件是基于项目路径的。为了验证这一点,我们在每个子项目的vite.config.ts中设置了不同的端口:

// packages/plugins/plugin-vue-router/vite.config.ts
export default defineConfig({
  plugins: [vue()],
  server: {
    port: 3001,
  },
});

另外,还可以在package.json的 scripts 中通过命令行参数设置端口:

"scripts": {
  "dev": "vite --port 3001"
}

问题 3:工作空间命令执行

问题描述:如何避免进入每个子项目目录来启动它们?

解决方案:在根目录的package.json中添加特定的启动命令:

"scripts": {
  "dev:composition-api": "cd packages/demos/demo-composition-api && pnpm dev",
  "dev:lifecycle": "cd packages/demos/demo-lifecycle && pnpm dev",
  "dev:router": "cd packages/plugins/plugin-vue-router && pnpm dev",
  "dev": "pnpm -r dev",
  "build": "pnpm -r build",
  "preview": "pnpm -r preview",
  "clean": "pnpm -r clean",
  "type-check": "pnpm -r type-check"
}

这样可以从根目录直接启动特定的子项目。

关于 -r 选项:pnpm -r 是 --recursive 的缩写,用于递归地执行命令。这意味着当你在根目录运行带有 -r 选项的命令时,pnpm 会在所有子项目中递归执行该命令。这种方式可以方便地在整个 monorepo 中执行相同的命令,而不需要手动进入每个子项目目录。

问题 4:依赖安装位置的影响

问题描述:如果依赖安装在子包 A 中,子包 B 是否可以使用?

解决方案:在 pnpm 中,依赖是严格隔离的。如果依赖只安装在子包 A 中,子包 B 将无法直接使用该依赖。为了让多个子包共享依赖,应该在工作区根目录安装这些依赖。使用以下命令在根目录安装共享依赖:

pnpm add ts-node typescript -w

关于 -w 标志:-w 是 --workspace 的缩写,用于在整个工作区范围内安装依赖。这意味着安装的依赖会被放置在工作区的根目录下,所有子包都可以访问这些依赖。这种方式可以减少重复安装,确保所有子包使用相同版本的依赖,并简化依赖管理。

4. 项目优化与完善

添加清理和类型检查脚本

为了更好地管理项目,我们添加了以下脚本:

"scripts": {
  "clean": "pnpm -r clean",
  "clean:all": "rimraf node_modules && rimraf packages/*/node_modules && rimraf packages/*/dist",
  "type-check": "pnpm -r type-check"
}

同时在每个子项目中添加对应的脚本:

"scripts": {
  "clean": "rimraf dist",
  "type-check": "vue-tsc --noEmit"
}

版本控制和 GitHub 集成

  1. 初始化 Git 仓库:

    git init
    git add .
    git commit -m "初始化项目:Vue3示例集合"
  2. 创建 GitHub 仓库并推送代码:

    git remote add origin https://github.com/SSF0/vue3-example.git
    git branch -M main
    git push -u origin main

5. Monorepo 实践经验总结

  1. Monorepo 优势:

    • 共享依赖,减少重复安装

    • 便于管理多个相关但独立的项目

    • 统一版本控制和配置

  2. pnpm 工作空间使用技巧:

    • 使用pnpm-workspace.yaml定义工作空间

    • 在根目录添加共享依赖

    • 使用pnpm -r或pnpm --filter执行命令

      # 递归执行命令
      pnpm -r dev
      # 指定执行命令的子包
      pnpm --filter @vue3-example/00-starter dev
    • 使用pnpm -w安装工作区依赖

  3. 项目配置最佳实践:

    • 使用命名空间(如@vue3-example/*)命名子项目

    • 在根目录添加辅助脚本简化操作

    • 为每个子项目设置不同的端口避免冲突

  4. 命名空间的价值:

    • 避免命名冲突:在 npm 中,包名必须全局唯一。使用命名空间(如 @A/utils 和 @B/utils)可以避免不同团队发布同名包时的冲突。

    • 清晰的项目结构:命名空间帮助在 monorepo 中更清晰地组织和管理包,便于识别和管理。

    • 私有包管理:命名空间可以用于创建私有包,确保内部工具不会被意外发布到公共 npm 注册表。

    • 版本管理:命名空间允许独立发布和更新每个包,而不影响其他包。

  5. Vue3 学习方向:

    • 组合式 API 的基本使用

    • 生命周期钩子的变化

    • 路由配置与使用

    • 状态管理整合

  6. 关于 Monorepo 和命名空间的关系:

    • Monorepo 特点:在单一代码库中管理所有子项目,方便代码共享、版本控制和依赖管理。

    • 命名空间在 Monorepo 中的作用:即使在 monorepo 中,使用命名空间仍然是一个好习惯,特别是在发布到 npm 时。命名空间可以确保即使在不同的 monorepo 中,包名也不会冲突。

    • 避免同名包:在 monorepo 中,通常通过命名规范和代码审查来避免同名包的创建。

通过这个项目,我们搭建了一个灵活的 Vue3 示例集合,可以方便地添加、测试和展示各种 Vue3 功能和最佳实践。

6. 项目发展规划

  1. 添加更多 Vue3 特性的示例

  2. 集成 Pinia 状态管理示例

  3. 添加常见错误案例及解决方案

  4. 完善文档和注释

通过这个项目,我们搭建了一个灵活的 Vue3 示例集合,可以方便地添加、测试和展示各种 Vue3 功能和最佳实践。

7. 项目地址

本项目已发布到 GitHub,欢迎访问、star 和提交 issues:

  • GitHub 仓库:https://github.com/SSF0/vue3-example

如有任何问题或建议,请通过 GitHub issues 反馈。

最后更新时间:
贡献者: 何风顺
上一页
打包与shell交互指定模式
下一页
pnpm 修改依赖源码打包报错