最近在对一个单库多项目的仓库 m-site 做升级迁移,其中一项就跟 npm 有关。根据业务中的问题和检索到的资料,整理了一下思路,简单记录。
对你来说,你能了解到一些有意思的站点、npm最新的发展方向、经过我筛选的文章和一个有点卵用的包。
m-site 现状
- 安装慢(倒杯水再上个厕所可能还在安装)
- merge 代码后 lock 文件冲突 原因1:npm 版本不一致 原因2:多人协作时多个分支安装有重叠依赖的包后,合并分支
- --registry 安装源不一致,导致 lockfile 中 resolved 字段经常变化
- @types/xx 版本与 js module 不一致
- 幽灵依赖(下面细讲)
- 替身依赖
方案对比
为什么会有这么多的包管理工具?它们试图解决什么问题?
(图1) 包管理发展史(来源: time.graphics/line/602344)
Npm: 100s
npm 在这些问题下也做了很多优化,其中最明显的是从v3开始嵌套结构变成了扁平结构,但这带来了新的问题
- 幽灵依赖问题 (phantom dependencies)。
- 多重身问题,无法彻底解决重复依赖,譬如还存在 183 个重复依赖。(doppelgangers)。
- 依赖结构的不确定性。(通过 依赖关系图 可以解决)
- 扁平化算法的复杂度和性能损耗。
- 来看看 umi 的依赖可视化,不愧是依赖黑洞!
- 庞大数量的网络IO和文件IO(根据官方数据计算,平均每秒全世界就有 7w 多个包被下载,要知道国内多数是从taobao下载,真实下载量更让人惊叹)
Yarn: 30s
最原汁原味(稳定)的优化
一开始没有什么“花招”,利用各种缓存策略,尽量的避免不必要的网络请求和 IO 操作
后来,,,yarn install --pnp
(这款方案对使用方式有变化且兼容不好这里不研究)
Cnpm:我没试😂
- 提供国内镜像源加速,10分钟同步一次官方包频率
- 使用 npminstall 安装,借鉴 pnpm
缺点:
- 软链接的缺点一处修改影响全局
- windows 软链接跨磁盘问题
- Electron 应用无法使用 pnpm
Pnpm: 23s
独特的非扁平目录结构,依赖查找关系如图:(真实目录有点难理解,可以对照图文多看几遍)
项目中引入
bar@1.0.0
→
→ {$root}/node_modules/bar@1.0.0
→ 软链到 .pnpm/bar@1.0.0/node_modules/bar@1.0.0
→ 硬链接到全局缓存 ~/.pnpm
- 内容寻址存储(content-addressable store)的方式全局缓存一份:~/.pnpm-store
- 软链接到全局缓存,达到安装 node_modules 效果,减少 IO
- 严格模式,避免bug:
安装后的目录结构
# 使用 ll 命令可以看到
# 软链不占用磁盘空间,相当于快捷方式,指向的真实目录
lrwxr-xr-x *** source-map -> ../../source-map@0.5.7/node_modules/source-map
# 第二列数字大于1,就代表本文件是硬链接(硬链接实际上是文件副本,但是修改任何一个,其余的全部文件都会同步修改)
-rw-r--r-- 2 username staff 1.1K 2 18 18:10
下一代包管理方式 Tnpm - rapid
着实🐂🍺,但是现在没开放,用不了😂,期待一下吧(*❦ω❦) --by 阿里巴巴 回顾npm安装的三大关键步骤,就可以看到
- Fast Resolving:解析依赖需要频繁的网络IO,非常耗时,一个项目得几千个请求才能生成依赖关系图lockfile
- Fast Fetching + Writing:下载聚合请求后的 tar 文件,请求数量减少,总体积也减小
- Without Writing: FUSE 文件系统直接操作 tar 文件
我做了什么
1. 限制 npm 版本:
官方 only-allow 包,只能限制工具类型却不能限制具体版本,所以我 fork 它,然后自己改了下,仓库在这,稍后发个 npm 包
package.json
{
"scripts": {
"preinstall": "node bin.js pnpm@6.0.0"
}
}
2. 固定安装源:
.npmrc
# 可以按域指定 @foo/ 下所有包的安装源
@foo:registry=http://npm.your-registry.com
# 也可以一次性指定所有包的源
registry=http://npm.your-registry.com
# 下面是一些业务中其它工具安装时,用到的国内下载源
http_proxy=http://10.196.x.xxx
disturl=https://r.cnpmjs.org/node
sass_binary_site=https://r.cnpmjs.org/node-sass/
fse_binary_host_mirror=https://r.cnpmjs.org/fsevents
sentrycli_cdnurl=https://cdn.npm.taobao.org/dist/sentry-cli
3. 处理废弃的包:
删除 node_modules 用 npm i 重新安装你的包,会出现一大堆⚠️warning,仔细查看每一个警告修复它,越早处理越好。(接到的这个项目有些年头了,有些包明知道有问题也不敢随意升级😂,因为互相依赖的太多了)
4. ✅幽灵包添加到 package.json
这一项可以把
pnpm
的当做一个严格检查的工具,用pnpm
重新安装,然后运行项目,把module not found的包依次安装到你的package.json
中即可
"@better-scroll/pull-down": "^2.4.2",
"@better-scroll/pull-up": "^2.4.2",
"react": "16.14.0",
"react-dom": "^17.0.2",
"redux": "4.1.2",
使用 pnpm 达到了什么效果(当你做ppt时可以量化的数据)
1. 占用磁盘体积:安装项目越多,效果越明显
2. 安装时间:自然是肉眼可见的快
未来?
云构建? 云协作?
或许不再需要装包了,所有的环境都在云端,你只需要 import 就好。