pnpm 构建 Monorepo workspace项目

pnpm 构建 Monorepo 项目

使用背景

因为公司要做的项目比较多,项目之间又会相互依赖。目前分为pc后台,pc商城,uniapp项目等等。所以为了代码的复用和代码的规范提交,决定引入pnpm来创建Monorepo项目。

Monorepo是什么呢(是多包单库管理)

Monorepo 简单的说,是指将公司的所有代码放到一个 Git / Mercurial / Subversion 的代码仓库中。对于很多没听说过这个概念的人而言,无异于天方夜谭。Git 仓库不应该是每个项目一个吗?对于很多用 monorepo 的公司,他们的 Git 仓库中不止有自己的代码,还包括了很多的依赖。基本上,只要把 monorepo 用 Git 拖下来,跑一下 ./scripts/install,就可以直接用 Buck / Bazel (在安装脚本中就装到了本地)编译仓库中的所有项目,并且提交修改(安装脚本配置好了代码提交环境,如果用的 Phabricator 的话,Gerrit 不用)

pnpm是什么呢

npm/yarn 采用了直接平铺的方式,而 pnpm 则是采用 .pnpm 隐藏目录隐藏真实的平铺结构,在使用链接(symbollink)的方式将真实安装的目录映射到 node_modules 下

为什么使用workspace呢

因为我们把项目剥离为业务组件层,通用api层,项目三层。项目引入通用api和业务组件相互依赖,所以我们搭建了内网npm。内网npm牵扯到了发包和版本号的问题,所以引入workspace 让项目内部进行引用类似这样

"devDependencies":{
  "**":"workspace:*"  
}

开始

第一步

我们在 packages 中新建以下几个目录。

├── packages
│   ├── ui-uniapp
│   ├── common-api

第二步

在根目录新建 pnpm-workspace.yaml,内容如下

packages:
  - 'packages/*'

第三步

npm init

生成package.json后

第四步

强制pnpm安装依赖

执行工程自身 preinstall
当前 npm 工程如果定义了 preinstall 钩子此时会被执行。

  "scripts": {
    "preinstall": "node preinstall.js",
  },

preinstall.js 中

if (!/pnpm/.test(process.env.npm_execpath || '')) {
  console.warn(
    `\u001b[33mThis repository requires using pnpm as the package manager ` +
      ` for scripts to work properly.\u001b[39m\n`
  )
  process.exit(1)
}

第五步

新增eslint stylelint prettier检测

  "scripts": {
    "preinstall": "node ./scripts/preinstall.js",
    "lint-staged": "lint-staged",
    "lint:eslint": "eslint --cache --max-warnings 0  \"packages/**/*.{vue,ts,tsx}\" --fix",
    "lint:prettier": "prettier --write  \"packages/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
    "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
    },
 "dependencies": {
    "stylelint": "^14.0.1",
    "stylelint-config-html": "^1.0.0",
    "stylelint-config-prettier": "^9.0.3",
    "stylelint-config-standard": "^23.0.0",
    "stylelint-order": "^5.0.0",
    "eslint": "^8.1.0",
    "@typescript-eslint/eslint-plugin": "^5.3.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-define-config": "^1.1.2",
    "eslint-plugin-jest": "^25.2.2",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-vue": "^8.0.3",
    "vue-eslint-parser": "^8.0.1",
    "prettier": "^2.5.1",
    "lint-staged": "^12.3.4",
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "prettier --write"
    ],
    "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
      "prettier --write--parser json"
    ],
    "package.json": [
      "prettier --write"
    ],
    "*.vue": [
      "prettier --write",
      "stylelint --fix"
    ],
    "*.{scss,less,styl,html}": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.md": [
      "prettier --write"
    ]
  }

第六步

增加git钩子
我的钩子命令是 pnpm run lint-staged

husky

npm install husky --save-dev
npm set-script postinstall "husky install"
npm run postinstall
npx husky add .husky/pre-commit " pnpm run lint-staged"
git add .husky/pre-commit

第七步

引入提交方式
安装依赖 commitizen和cz-conventional-changelog

 "scripts": {
    "commit": "cz"
  },
"config": {
    "commitizen": {
    "path": "cz-conventional-changelog"
    }
},
  • feat 增加新功能
  • fix 修复问题/BUG
  • upd 更新某功能
  • style 代码风格相关无影响运行结果的
  • perf 优化/性能提升
  • refactor 重构
  • revert 撤销修改
  • test 测试相关
  • docs 文档/注释
  • chore 依赖更新/脚手架配置修改等
  • workflow 工作流改进
  • ci 持续集成
  • mod 不确定分类的修改
  • wip 开发中
  • types 类型修改
<think>好的,我现在需要帮助用户解决如何使用pnpmmonorepo模式构建包含Vue 3、TypeScript和UniApp的项目,并抽离公共组件的问题。首先,我得回忆一下pnpmmonorepo的基本概念。pnpm是一个包管理工具,通过硬链接节省磁盘空间,而monorepo则是在一个仓库中管理多个项目,共享代码和配置。 接下来,用户的需求涉及Vue 3、TypeScript和UniApp,这三个技术栈的结合。UniApp可能用于多端开发,比如小程序和H5,所以项目结构需要支持多平台。同时,用户希望抽离公共组件,这在monorepo结构下可以通过workspace来实现,把公共组件放在独立的包中,各子项目依赖这个包。 首先,我需要确定项目的基本结构。通常monorepo的根目录会有pnpm-workspace.yaml来定义工作空间,里面包含packages目录,里面可能有多个子项目,比如apps(存放各个应用)和libs(公共组件库)。这样,每个应用都可以引用libs中的组件。 然后,安装必要的依赖。Vue 3和TypeScript的基础配置,可能需要@vitejs/plugin-vue、vue-tsc等。UniApp部分可能需要使用Vite插件,比如@dcloudio/vite-plugin-uni,或者查看官方文档推荐的配置。这里可能需要查阅UniApp的官方文档,确认如何集成到Vite项目中。 接下来是初始化项目。用户提到使用pnpm,所以需要先确保pnpm已安装。然后创建项目结构,初始化各个子项目。每个子项目可能需要自己的package.json,并且在workspace中声明依赖关系,比如apps/h5和apps/miniprogram都依赖libs/components。 然后是配置共享。公共的TypeScript和Vue配置可以放在根目录,通过extends来继承,避免重复。ESLint、Prettier等工具也可以在根目录统一配置,各子项目继承这些配置,保持一致性。 抽离公共组件部分,需要在libs目录下创建组件库项目,导出组件,然后在子项目中通过workspace协议引用。可能需要配置构建工具,如Vite,确保能正确解析workspace的依赖。 在UniApp的集成方面,可能需要特别注意,因为UniApp有自己的构建流程和配置,可能需要调整Vite配置,添加必要的插件,并处理平台特定的代码。 最后是构建和运行命令,需要为每个子项目配置脚本,并且可能需要使用pnpm filter来指定运行哪个子项目的命令。 过程中需要注意的坑点可能包括:workspace依赖的正确声明,TypeScript路径别名的配置,UniApp与Vue 3的兼容性问题,以及公共组件的构建和导出方式。需要确保所有子项目能正确引用公共组件,并且在H5和小程序端都能正常运行。 可能还需要考虑测试和代码规范,比如在根目录统一设置ESLint、Prettier、Husky等工具,保证代码质量。此外,公共组件的版本管理和发布策略也是需要考虑的,但在monorepo中通常通过workspace协议自动处理。 总结步骤应该是:初始化monorepo结构,配置workspace,创建子项目,设置共享配置,抽离公共组件到libs,配置各子项目的依赖和构建脚本,处理UniApp的集成,最后测试整个项目运行。</think>### 使用 pnpmMonorepo 构建 Vue 3 + TypeScript + UniApp 项目的详细步骤 #### 一、环境准备 1. **安装 pnpm** ```powershell # 使用 PowerShell 安装 pnpm(需管理员权限) Invoke-WebRequest 'https://get.pnpm.io/v6.16.js' -UseBasicParsing -o pnpm.js node pnpm.js add --global pnpm Remove-Item pnpm.js ``` 2. **验证安装** ```bash pnpm -v # 输出版本号即成功 ``` --- #### 二、初始化 Monorepo 项目结构 1. **创建项目根目录** ```bash mkdir my-monorepo-project && cd my-monorepo-project ``` 2. **配置 pnpm workspace** 创建 `pnpm-workspace.yaml` 文件,定义工作区范围: ```yaml packages: - 'apps/*' # 存放应用(如 H5、小程序) - 'libs/*' # 存放公共组件/工具库 ``` 3. **初始化根目录 package.json** ```bash pnpm init -y ``` --- #### 三、创建子项目 1. **H5 应用(Vue3 + TypeScript)** ```bash # 使用 Vite 初始化 H5 项目 pnpm create vite apps/h5 --template vue-ts ``` 2. **UniApp 小程序应用** ```bash # 进入 apps 目录,使用 UniApp 官方模板 cd apps && npx degit dcloudio/uni-preset-vue#vite my-uniapp mv my-uniapp miniprogram && cd .. ``` 3. **公共组件库** ```bash mkdir -p libs/components/src cd libs/components && pnpm init -y ``` --- #### 四、配置依赖与共享 1. **安装全局依赖(根目录)** ```bash pnpm add -Dw vue@3 typescript @vitejs/plugin-vue unplugin-auto-import ``` 2. **关联子项目依赖** ```bash # H5 项目安装依赖 pnpm --filter h5 add vue-router axios # UniApp 项目安装依赖 pnpm --filter miniprogram add @dcloudio/uni-app @dcloudio/vite-plugin-uni # 公共组件库声明依赖 pnpm --filter components add vue@3 ``` 3. **共享 TypeScript 配置** 在根目录创建 `tsconfig.base.json`,子项目通过 `extends` 继承: ```json { "compilerOptions": { "target": "ESNext", "module": "ESNext", "strict": true, "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@components/*": ["../../libs/components/src/*"] } } } ``` --- #### 五、抽离公共组件最佳实践 1. **组件库结构示例** ``` libs/components/ ├─ src/ │ ├─ Button/ │ │ ├─ index.vue # 组件实现 │ │ └─ index.ts # 导出组件 │ └─ index.ts # 统一导出所有组件 ├─ package.json # 声明 name: "@myorg/components" ``` 2. **在子项目中引用** 修改子项目的 `vite.config.ts`: ```typescript import { defineConfig } from 'vite' import uni from '@dcloudio/vite-plugin-uni' export default defineConfig({ plugins: [uni()], resolve: { alias: { '@components': 'libs/components/src' } } }) ``` 3. **通过 Workspace 协议声明依赖** 在 `apps/h5/package.json` 中添加: ```json { "dependencies": { "@myorg/components": "workspace:*" } } ``` --- #### 六、构建与运行 1. **全局命令配置(根目录 package.json)** ```json { "scripts": { "dev:h5": "pnpm --filter h5 dev", "build:h5": "pnpm --filter h5 build", "dev:mp": "pnpm --filter miniprogram dev:mp-weixin", "build:mp": "pnpm --filter miniprogram build:mp-weixin" } } ``` 2. **启动项目** ```bash # 启动 H5 项目 pnpm dev:h5 # 启动微信小程序项目 pnpm dev:mp ``` --- ### 关键问题与解决方案 1. **跨项目类型兼容性** - UniApp 需使用 `@dcloudio/vite-plugin-uni` 插件支持 Vue3[^2] - 公共组件避免使用平台特有 API,通过条件编译处理差异: ```vue <!-- 示例:H5 与小程序条件编译 --> <template> <!-- #ifdef H5 --> <div>H5 特有内容</div> <!-- #endif --> </template> ``` 2. **样式共享方案** 在根目录安装全局样式依赖: ```bash pnpm add -Dw sass ``` 通过 `@import "@/styles/variables.scss";` 在组件中引用 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

木贝西

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

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

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

打赏作者

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

抵扣说明:

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

余额充值