全局安装模块
cnpm without --by=npm
模块将安装在%AppData%
pm
ode_modules
目录下, 列如: C:UsersAdministratorAppDataRoaming
pm
ode_modules
.
Ubuntu: /usr/local/lib/node_modules
.
发现为了节省空间, 其实重复的package是不会重复安装的, 而是在全局项目的node_modules目录下, 为所有的package建立带版本的目录, 并建立符号链接(symbol link).
也就是说依赖全部被展平了放在第一层, 这样, 如果孙子package中有重复的依赖, 并不会重复安装, 从而避免目录黑洞.
带版本目录的命名规则是: _包名@版本@包名
.
举个例子, 我们通过npm安装cnpm, cnpm有个依赖为which, which又有个依赖叫isexe
cnpm
ode_modules $ ls -d *which* # 查询which包的符号链接以及指向的真实目录
_which@1.3.1@which which
# 可以看到确实有一个叫_which@1.3.1@which的目录, 而且which是一个符号链接, 不是真实目录
# 如何证明which就是指向了_which@1.3.1@which呢? 用fsutil命令!
cnpm
ode_modules $ fsutil reparsepoint query "which" # 查询符号链接which的实际指向
打印名称: C:UsersAdministratorAppDataRoaming
pm
ode_modulescnpm
ode_modules\_which@1.3.1@which
# 接下来进入which的模块下查询isexe的指向
cnpm
ode_moduleswhich
ode_modules $ fsutil reparsepoint query "isexe"
打印名称: C:UsersAdministratorAppDataRoaming
pm
ode_modulescnpm
ode_modules\_isexe@2.0.0@isexe
なるほど!不过很可惜, cnpm并不会跨项目建立符号链接. npm更是不会建立任何符号链接, 优先展平放到根模块的node_modules下, 冲突的放到自身node_modules下.
结论: 无论使用npm还是cnpm, 都不会影响这一事实: 全局安装的模块的依赖模块的路径是可以确定的, 一定可以在根模块的node_modules目录下找到, 但孙子不确定.
yarn
模块将安装在%AppData%..LocalYarnDataglobal
ode_modules
目录下, 列如: C:UsersAdministratorAppDataLocalYarnDataglobal
ode_modules
.
Ubuntu: /usr/local/share/.config/yarn/global/node_modules
.
global
目录下会有一个package.json文件, 描述目前全局安装的包:
{
"dependencies": {
"electron": "^11.0.3",
"typescript": "^4.0.5",
"webpack": "^5.1.3",
"webpack-cli": "^4.1.0"
}
}
根据我的猜测:
全局安装的模块的依赖将会优先安装到global
ode_modules
目录下, 如果版本冲突, 则安装到相应模块的node_modules目录下, 和npm孙子冲突类似.
依赖模块绝对路径
对于一个有命名空间的项目, 需要查找以下几个目录:
@namespace/xxx/node_modules <== npm or cnpm
@namespace/xxx/../../node_modules <= Yarn