first post on http://blog.xgheaven.com/2018/05/03/npm-to-yarn-to-npm/html
从接触到 node 环境来讲,其中一个不可或缺的一部分即是 npm 包管理,可是因为官方的 npm 有各类各样的问题,因而催生了不少不一样的版本,这其中的曲折也许只有过来人才知道。node
在上古版本(应该是 npm3 之前的版本,具体我也记不清了),npm 的安装策略并非扁平化的,也就是说好比你安装一个 express
,那么你会在 node_modules
下面只找到一个 express
的文件夹。而 express
依赖的项目都放在其文件夹下。linux
- app/
- package.json
- node_modules/
- express/
- index.js
- package.json
- node_modules/
- ...
复制代码
这个带来的问题或许 windows 用户深谙其痛,由于在这种安装环境下,会致使目录的层级特别高,而对于 windows 来讲,最大的路径长度限制在 248 个字符(更多请见此),再加上 node_modules
这个单词又特别长,因此你懂得,哈哈哈。解决方案啥的本身去搜索吧,反正估计如今也没人会用上古版本了。git
除了 windows 用户出现的问题之外,还有一个更严重的问题,就是模块都是独立的,好比说位于 express
下面的 path-to-regexp
和 connect
下面的 path-to-regexp
的模块是两个不一样的模块。 那么这个会带来什么影响呢?其实在使用上,并无什么太大的影响,可是内存占用过大。由于不少相同模块位于不一样模块下面就会致使有多个实例的出现(为何会加载多个实例,请查看 Node 模块加载)。你想一想,都是一样的功能,为何要实例这么屡次呢?不能就加载一次,复用实例么?github
上古时代的 npm 的缺点能够说仍是不少的:express
后面,有人为了解决目录嵌套层次太高的问题,引入的软连接的方案。npm
简单来讲,就是将全部的包都扁平化安装到一个位置,而后经过软连接(windows 快捷方式)的方式组合到 node_modules
中。json
- app/
- node_modules
- .modules/
- express@x.x.x/
- node_modules
- connect -> ../../connect@x.x.x
- path-to-regexp -> ../../path-to-regexp@x.x.x
- ... -> ../../package-name@x.x.x
- connect@x.x.x/
- path-to-regexp@x.x.x/
- ...others
- express -> ./.modules/express@x.x.x
复制代码
这样作的好处就是能够将总体的逻辑层级简化到不多的几层。并且对于 node 的模块解析来讲,能够很好的解决相同模块不一样位置致使的加载多个实例,进而致使内存占用的状况。windows
基于这种方案,有 npminstall 以及 pnpm 这个包实现了这种方案,其中 cnpm 使用的就是 npminstall,不过他们实现的方式和我上面讲的是有差别的,具体请看。简单来说,他们没有 .modules
这一层。更多的内容,请看 npminstall 的 README。缓存
总的来说这种解决方案有还有如下几个好处:
那么缺点也是挺致命的:
最大的改变就是将目录层级从嵌套变到扁平化,能够说很好的解决了上面嵌套层级过深以及实例不共享的问题。可是,npm3 在扁平化方案下,选择的并非软链接的方式,而是说直接将全部模块都安装到 node_modules
下面。
- app/
- node_modules/
- express/
- connect/
- path-to-regexp/
- ...
复制代码
若是出现了不一样版本的依赖,好比说 package-a
依赖 package-c@0.x.x
的版本,而 package-b
依赖 package-c@1.x.x
版本,那么解决方案仍是像以前的那种嵌套模式同样。
- app/
- node_modules/
- package-a/
- package-c/
- // 0.x.x
- package-b/
- node_modules/
- package-c/
- // 1.x.x
复制代码
至于那个版本在外面,那个版本在里面,彷佛是根据安装的前后顺序有关的,具体的我就不验证了。若是有人知道的话,欢迎告诉我。
在这个版本以后,解决了大部分问题,能够说 npm 跨入了一个新的世界。可是还要一个问题就是,他的安装速度依旧很慢,相比 cnpm 来讲。因此他还有不少进步的空间。
随着 Node 社区的愈来愈大,也有愈来愈多的人将 Node 应用到企业级项目。这也让 npm 暴露出不少问题:
因此,此时 yarn 诞生了,为的就是解决上面几个问题。
那个时候我还在使用 cnpm,我特意比较了一下,发现仍是 cnpm 比较快,因而我仍是继续使用着 cnpm,由于对于我来讲足够了。可是后面发现 yarn 真的愈来愈火,再加上 cnpm 长久不更新。我也尝试着去了用 yarn,在尝试以后,我完全放弃了 cnpm。并且直到如今,彷佛尚未加入 lock 的功能。
固然 yarn 还不仅只有这么几个好处,在用户使用方面:
yarn global
下面都是与全局模块相关的命令。并且提示很是彻底,一眼就能看明白是什么意思。不会像 npm 同样,npm --help
就是一坨字符串,还不讲解一下是什么用处,看着头疼。-S
参数node_modules/.bin
下的可执行文件。这个是我用 yarn 最高的频率。好比你安装了 yarn add mocha
,而后就能够经过 yarn run mocha
直接运行 mocha
。而不须要 ./node_modules/.bin/mocha
运行。是我最喜欢的一个功能npm outdated
看看那些包须要更新,而后经过 npm update [packages]
更新指定的包。而在 yarn 当中,能够经过交互式的方式,来选择那些须要更新,那些不须要。/usr/lib/node_modules
下面安装,而后经过软链接链接到 /usr/local/bin
目录下。而 yarn 的作法是选择一个目录,这个目录就是全局模块安装的地方,而后将全部的全局模块当作一个项目,从而进行管理。这个好处就是,你能够直接备份这个目录当中的 package.json 和 yarn.lock 文件,从而能够很方便的在另外一个地方还原你安装了那些全局模块。至于这个目录的问题,经过 yarn global dir
命令就能够找到,mac 下是在 ~/.config/yarn/global/
,linux 我没有测试过。能够说 yarn 用起来很是舒服,可是惟一的缺点就是否是 npm 官方出的,更新力度、兼容性都会差一些。但这也阻挡不住 yarn 在 Node 社区的火热程度。很快,你们纷纷从 npm 切换到 yarn 上面。
在受到 yarn 的冲击以后,npm 官方也决定改进这几个缺点,因而发布了和 Yarn 对抗(这个词是我意淫的)的 npm5 版本。
-S
参数至此,yarn 和 npm 的差距已经很是很是小了,更多的差距体如今用户体验层面,我使用 yarn 的功能也只剩下全局模块管理、模块交互式更新和 yarn run
这个命令了。
可是后面推出的 npx 让我放弃了使用 yarn run
这个命令。不是说 npx 比 yarn 有多好,而是说 npm 集成了这个功能,也就不必再去使用第三方的工具了。并且 npx 还支持临时安装模块,也就是那种只用一次的命令,用完就删掉了。
后面我又发现了 npm-check
这个工具,我用它来替代了 yarn 的交互式更新。
然而 npm6 的出现加入了缓存,而且又进一步提高了速度,能够说直逼 yarn。
因而 yarn 对我来讲只剩下一个全局模块管理的功能了。个人整个开发流程以及从 yarn 切换回 npm 上面了。或许后面的日子我也会让 npm 来接管全局模块管理,从而放弃使用 yarn。可是我仍是会装 yarn,毕竟有一些老项目仍是用 yarn 的。
我经历了从 npm -> cnpm -> yarn -> (npm + npm-check + npx) 的一个循环,也见证了 npm 社区的一步步发展。并且 yarn 的更新频率也很是慢,可能一个月才更新一次,这也让我逐渐放弃使用 yarn。
有的时候感受,第三方的终究是第三方,仍是没有原生的好用和方便,并且用起来安心。