npm 与 yarn 的区别

全局安装模块

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

END

原文地址:https://www.cnblogs.com/develon/p/14091683.html