前端开发中,我们经常会遇到多个项目需要共用相同代码模块的情况。比如公司内部可能有多个项目都使用了相同的UI组件库、工具函数集或者业务逻辑封装。传统做法是每个项目都拷贝一份代码,但这会导致:
我曾经接手过一个企业级项目,其中5个前端应用都包含相同的工具函数库,但版本各不相同。当发现其中一个安全漏洞时,不得不逐个项目修复,耗时耗力。这让我深刻体会到共享模块的重要性。
pnpm采用了一种创新的包管理方式,其核心特点是:
这种设计带来了几个关键优势:
当多个项目使用pnpm安装相同的模块时:
这种机制天然适合共享模块的场景。我们只需要将公共代码发布为npm包,然后在各项目中通过pnpm安装即可实现真正的代码共享。
要创建适合共享的模块,需要考虑以下因素:
我推荐采用monorepo结构管理共享模块:
code复制shared-modules/
├── packages/
│ ├── utils/ # 工具函数
│ ├── ui-kit/ # UI组件
│ └── core/ # 核心逻辑
└── pnpm-workspace.yaml
典型的package.json配置:
json复制{
"name": "@company/utils",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"peerDependencies": {
"react": ">=16.8.0"
}
}
重要提示:避免将共享模块设置为private: true,否则无法发布到仓库
在使用项目中,通过pnpm安装共享模块:
bash复制pnpm add @company/utils
pnpm会自动处理:
对于正在开发的共享模块,可以使用pnpm workspace功能:
yaml复制packages:
- 'packages/*'
- 'apps/*'
bash复制pnpm add @company/utils --workspace
这种模式下,修改共享模块会实时反映在所有使用项目中,极大提升开发效率。
共享模块的版本管理至关重要,我推荐:
使用changesets工具管理版本变更:
bash复制pnpm add -Dw @changesets/cli
npx changeset init
配置CI/CD实现自动发布:
示例GitHub Actions配置:
yaml复制name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- run: pnpm install
- run: pnpm test
- run: npx changeset publish
当多个共享模块依赖不同版本的同个包时:
json复制{
"pnpm": {
"overrides": {
"lodash": "4.17.21"
}
}
}
bash复制pnpm add lodash@4.17.21 -w
bash复制cd shared-module
pnpm link --global
cd ../project
pnpm link --global shared-module
json复制{
"dependencies": {
"@company/utils": "file:../shared-modules/packages/utils"
}
}
bash复制pnpm install --shamefully-hoist
js复制module.exports = {
hooks: {
readPackage(pkg) {
if (pkg.name === 'some-package') {
pkg.dependencies = pkg.dependencies || {}
delete pkg.dependencies['unwanted-dep']
}
return pkg
}
}
}
在某大型电商项目中,我们使用pnpm实现了:
实施效果:
关键配置:
bash复制# .npmrc
shamefully-hoist=true
strict-peer-dependencies=false
auto-install-peers=true
bash复制rm -rf node_modules package-lock.json yarn.lock
bash复制npm install -g pnpm
bash复制pnpm install
常见问题及解决:
bash复制pnpm add -D missing-peer
bash复制# 在.npmrc中
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
bash复制pnpm run --filter=package-name script-name
bash复制pnpm audit
bash复制time pnpm install
bash复制pnpm list --depth=5
bash复制pnpm store path
du -sh $(pnpm store path)
仅安装生产依赖:
bash复制pnpm install --prod
按需安装特定子包:
bash复制pnpm install --filter @company/utils
配置离线存储:
bash复制pnpm config set store-dir /path/to/store
离线安装:
bash复制pnpm install --offline
通过.npmrc配置:
bash复制# 使用自定义registry
registry=https://registry.npm.taobao.org/
# 指定私有仓库
@company:registry=https://npm.company.com/
在monorepo中结合使用:
json复制{
"scripts": {
"bootstrap": "lerna bootstrap --use-pnpm"
}
}
配置rush.json:
json复制{
"pnpmOptions": {
"strictPeerDependencies": false
}
}
优化构建流水线:
json复制{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
}
}
}
bash复制pnpm install --verify-store-integrity
bash复制# .npmrc
save-exact=true
bash复制pnpm config set @company:registry https://npm.company.com/
bash复制pnpm update --latest
bash复制# 清除缓存并重试
pnpm store prune
pnpm install
bash复制# 安装缺失的peer依赖
pnpm add -D missing-peer
bash复制# 检查node_modules结构
pnpm why module-name
bash复制pnpm install --reporter=ndjson
bash复制pnpm list --depth=10
bash复制pnpm root
在实际项目中,我发现随着共享模块数量的增加,需要建立完善的文档和变更通知机制。我们内部开发了一个依赖看板,可以实时可视化所有项目的依赖关系图,这在管理大型代码库时特别有用。