首先说一下Node.js,简单的说 Node.js 就是运行在服务端的 JavaScript。node通过更改连接到服务器的方式,可以处理高并发任务。
npm: nodejs的包管理器,用于node插件管理(包括安装、卸载、管理依赖等)
npm使用一个名为package.json
的文件,用户可以通过npm install --save
命令把项目里所有的依赖项保存在这个文件里。
npm安装速度慢的一个重要原因:npm远程服务器在国外,必须首先遍历所有的项目依赖关系,然后再决定如何生成扁平化的node_modules结构。不过,npm有本地缓存,它保存了已经下载的每个版本的压缩包,缓存可以减少安装时间。
devDependencies:通常是开发的工具(eg:测试用的库),开发环境的依赖
dependencies:与生产环境中应用程序相关的
两者的区别在普通项目中,两者都安装,程序才能跑起来(因为devDependencies一般包含程序运行环境依赖);纯node项目,只安装dependencies就可以运行项目了,而安装了 devDependencies
后,就会让编辑器的 eslint
检测插件开始工作,或者是可以用 jest
进行单元测试:
是真正意义上的开发环境与生产环境分离。
第一种:
直接安装cnpm 安装淘宝提供的cnpm,并更改服务器地址为淘宝的国内地址, 命令:
npm install -g cnpm --registry=https://registry.npm.taobao.org
,以后安装直接采用cpm
替代npm
, 例如原生npm命令为:npm install uniq --save
,cnpm命令为:cnpm install uniq --save
第二种:
替换npm仓库地址为淘宝镜像地址(推荐) 命令:npm config set registry https://registry.npm.taobao.org
, 查看是否更改成功:npm config get registry
,以后安装时,依然用npm命令,但是实际是从淘宝国内服务器下载的
安装 | Yarn 中文文档 (bootcss.com)
快速、可靠、安全的依赖管理工具。
一开始是为了解决由于语义版本控制而导致npm安装的不确定的问题,每次安装都生成yarn.lock
文件,yarn.lock
文件还包含要安装的内容的校验和,以确保使用的库的版本相同。
运行速度得到了显著的提升
像npm一样,yarn使用本地缓存。与npm不同的是,yarn无需互联网连接就能安装本地缓存的依赖项,它提供了离线模式
Yarn Workspaces(工作区)是Yarn提供的monorepo
的依赖管理机制,从Yarn 1.0开始默认支持,用于在代码仓库的根目录下管理多个package的依赖。
Workspace 能更好的统一管理有多个项目的仓库,既可在每个项目下使用独立的 package.json 管理依赖,又可便利的享受一条 yarn命令安装或者升级所有依赖等。更重要的是可以使多个项目共享同一个 node_modules
目录,提升开发效率和降低磁盘空间占用。
Fast, disk space efficient package manager | pnpm官网
全称是 “Performant NPM”,即高性能的 npm。利用硬链接和符号链接来避免复制本地缓存源文件,继承了yarn的所有优点,包括离线模式和确定性安装
内部基于内容寻址的文件系统存储磁盘上所有的文件:
这个文件好处在于:
1.不会重复安装同一个包。设想一下,假如公司的每个项目都用了 vue 全家桶,那么每个项目都需要安装 vue、vue-router、vuex、axios 等几乎相同的库,如果有 100 个项目,那就要重复安装 100 遍!!非常耗费磁盘空间。
2.即使包的不同版本,pnpm也会极大程度的复用之前版本的代码。举个例子,比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的 hardlink
,仅仅写入那一个新增的文件
。
对于多个项目的管理,一般用多个git仓库。但是monorepo的宗旨就是用一个git仓库管理多个子项目,所有子项目都存放在根目录的packages
目录下,那么一个子项目就代表一个package
如果你之前没接触过 monorepo 的概念,建议仔细看看这篇文章以及开源的 monorepo 管理工具lerna,项目目录结构可以参考一下 babel 仓库。
pnpm还保留了非扁平化的node_modules文件夹,避免了扁平化node_modules都带来的幻影依赖,依赖分身的问题。
安装可以使用npm安装:npm i -g pnpm
与依赖提升和扁平化的 node_modules 不同,pnpm 引入了另一套依赖管理策略:内容寻址存储。
与npm用法完全一致
npm安装插件是从国外服务器下载,受网络影响大,可能出现异常。淘宝为我们搭建了一个国内的npm服务器cnpm,它目前是每隔10分钟将国外npm仓库的所有内容“搬运”回国内的服务器上,这样我们直接访问淘宝的国内服务器就可以了.
cnpm 比 npm 快多了
cnpm 没有 package-lock.json
cnpm
最大的隐患:安装时不会产生 package-lock.json
,并且项目中即使有 package-lock.json
,cnpm
也是不管不顾的,只读取 package.json
。阿hi有一个因哈UN就是用的包不一定遵循Semver
规范。
有些依赖包用 cnpm 安装就不能用,用 npm 安装就可以用,这个问题估计和 cnpm
包的使用软链接的方式有关系(并不确定)。
cnpm 和 npm 混用,导致包挂了,这个可以确定是 cnpm
使用软链接的问题。所以,还是尽量不要混用吧。
能用 npm 最好用 npm,公司内部的 私有镜像源
也建议做成 npm
,毕竟 cnpm
还是存在一些隐患。
node_modules
├── A
│ └── node_modules
│ └── foo
└── B
└── node_modules
└── foo
最初,npm就简单通过依赖去递归安装包,A,B都依赖foo,那么就会有两份foo安装。为节省空间,采用了扁平化的node_modules。这样,foo会被提升到顶层,同一个包只会有一份。
node_modules
├── A
├── B
└── foo
但是会带来的问题是引入混乱,扁平化结构可以直接引用foo,但实际上并没有直接指定依赖foo,而是有层级关系,导致了引入上的错乱。如果A,B都不依赖foo,包会报错。
导致的问题:
幻影依赖:项目代码引用的某个包没有直接定义在 package.json
中,而是作为子依赖被某个包顺带安装了。代码里依赖幻影依赖的最大隐患是,对包的语义化控制不能穿透到其子包,也就是包 a@patch
的改动可能意味着其子依赖包 b@major
级别的 Break Change。(也就是说如果包改变了,那么被依赖的包就会破碎,出错)
但还有一种更难以解决的幻影依赖问题,即用户在 Monorepo 项目根目录安装了某个包,这个包可能被某个子 Package 内的代码寻址到,要彻底解决这个问题,需要配合使用 Rush,在工程上通过依赖问题检测来彻底解决。