做了一个代替pnpm的轻量级monorepo工具,对npm项目零配置零修改零侵入,不使用pnpm就可以进行本地多包项目开发

14 阅读4分钟

解决什么问题

想要使用本地monorepo开发+纯npm管理的项目,不想对项目进行pnpm改造的开发者

项目地址

github.com/alamhubb/mo…

Mono

🚀 零侵入式 Monorepo 开发工具

直接使用 TypeScript 源码开发,无需构建,无需改造项目

💡 什么是 Mono?

Mono 是一套零侵入式 monorepo 开发工具。它允许你在开发期间直接使用 TypeScript 源码,无需构建包或重构项目。

pnpm workspace 的「链式污染」问题

使用 pnpm workspace 意味着整条依赖链都被迫使用 pnpm

项目 A (pnpm) → 必须用 pnpm
  └── 项目 B → 必须用 pnpm(被污染)
        └── 项目 C → 必须用 pnpm(被污染)
              └── 项目 D → 必须用 pnpm(被污染)
  • 🔗 所有相关项目都必须改成 pnpm
  • 👥 所有开发人员都必须安装 pnpm
  • 🔧 所有 CI/CD 环境都必须配置 pnpm
  • 📦 新成员 npm install 直接报错:workspace:*

详细分析请阅读:「链式污染」—— 为什么一个 pnpm 项目会逼着整条依赖链都改成 pnpm

Mono 的解决方案

使用 Mono,你只需:

  • ✅ 运行 mono ./src/index.ts - 就这么简单!
  • 修改后无需重新安装 - 修改本地包,立即运行
  • 无需构建 - 直接使用 TypeScript 源码
  • 无需配置 - 自动发现所有本地包
  • 无需 workspace:* - package.json 保持标准格式
  • ✅ 兼容 npm/yarn/pnpm - 项目保持通用性

pnpm workspace vs Mono

方面pnpm workspaceMono
安装必须安装 pnpm可选
配置文件需要 pnpm-workspace.yaml不需要
package.json需要修改为 workspace:*不需要修改
克隆后使用必须 pnpm installnpm/yarn/pnpm 都可以
依赖包需要先构建直接使用源码
团队协作所有人必须用 pnpm不强制

各方案横向对比

方案免安装免编译零配置自动发现复杂度
npm 原生
pnpm workspace⚠️
tsconfig paths
Nx极高
mono极低

⚠️ = 视配置而定


📦 包列表

本仓库包含两个协同工作的包:

用途安装
mono-mjsNode.js CLI - 用于构建工具、Vite 插件npm install -g mono-mjs
vite-plugin-monoVite 插件 - 用于浏览器运行时npm install -D vite-plugin-mono

何时使用哪个?

场景工具
运行脚本、构建工具mono
Vite 插件、编译器mono
浏览器端导入vite-plugin-mono
Vue/React 组件vite-plugin-mono

🚀 快速开始

1. 全局安装 CLI

npm install -g mono-mjs

2. 运行项目

💡 无需重新安装! 修改本地包后立即运行。

# 直接运行 TypeScript - 本地包自动解析
mono ./src/index.ts

# 使用本地包运行 Vite
mono ./node_modules/vite/bin/vite.js

3. (可选)添加 Vite 插件用于浏览器端

npm install -D vite-plugin-mono
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteMono } from 'vite-plugin-mono'

export default defineConfig({
  plugins: [
    viteMono(),  // 放第一个!
    vue()
  ]
})

✨ 特性

🚫 三个「不需要」

传统工作流使用 Mono
添加包后执行 npm install❌ 不需要
修改代码后执行 npm run build❌ 不需要
配置 workspace.yamltsconfig paths❌ 不需要

💡 注意:来自 npm 仓库的第三方包仍然需要 npm install。「无需安装」的优势仅适用于本地包

🔄 对比 npm file: 协议

// 传统 npm 本地依赖方式
{ "my-lib": "file:../packages/my-lib" }
修改本地包后npm file:mono
需要重新运行 npm install✅ 是❌ 否
修改立即生效?❌ 否✅ 是

使用 file: 协议时,npm 会将包复制到 node_modules。每次修改本地包后,必须重新运行 npm install 来更新副本。

使用 mono 时,导入在运行时被重定向到源码。无需复制,无需重新安装。

✅ Mono 带给你的

  • 🎯 零侵入 - 项目保持标准 npm 结构
  • 🔍 自动发现 - 递归查找所有本地包
  • ⚡️ 源码优先 - 直接运行 TypeScript 源码,无需构建产物
  • 📦 包管理器无关 - 支持 npm、yarn、pnpm、bun
  • 🛠️ 零配置 - 默认 ./src/index.ts,可选 local 字段

📚 工作原理

包发现

直线向上查找距离最远的项目根目录 (.idea/.vscode/.git/package.json)
  └── 递归扫描
      └── 查找所有 package.json
          └── 根据 "name" 字段注册

导入拦截

// 你的代码
import { utils } from 'my-utils'

// Mono 重定向到源码
// → /path/to/my-utils/src/index.ts

⚙️ 配置

零配置(默认)

所有包默认使用 ./src/index.ts。无需任何配置!

自定义入口(可选)

package.json 中添加 local 字段:

{
  "name": "my-package",
  "local": "./src/main.ts"
}