官方说明:​​https://classic.yarnpkg.com/zh-Hans/docs/package-json​


 

​name​​​ 和 ​​version​​​ 是 ​​package.json​​​ 文件里最重要的两个字段,没有它们你的包无法被安装。 ​​name​​​ 和 ​​version​​ 字段一起用来创建一个唯一 id。



yarn add [name]


  这是你的包的名字。它在 URL 中、作为命令行参数、作为 ​​node_modules​​ 里的目录名使用。



node_modules/[name]


https://registry.npmjs.org/[name]/-/[name]-[version].tgz


  

 

添加一个依赖

通过 ​​yarn add​​​ 添加依赖会更新 ​​package.json​​​ 以及 ​​yarn.lock​​ 文件

  1. ​yarn add <packageName>​​​ 依赖会记录在 ​​package.json​​​ 的 ​​dependencies​​ 

  2. ​yarn global add <packageName>​​ 全局安装依赖

 更新一个依赖

​yarn upgrade​​ 用于更新包到基于规范范围的最新版本

yarn upgrade --latest # 忽略版本规则,升级到最新版本,并且更新 package.json


移除一个依赖

​yarn remove <packageName>​

安装 package.json 中的所有文件

​yarn​​​ 或者 ​​yarn install​

运行脚本

​yarn run​​​ 用来执行在 ​​package.json​​​ 中 ​​scripts​​ 属性下定义的脚本

// package.json
{
"scripts": {
"dev": "node app.js",
"start": "node app.js"
}
}
yarn run dev # yarn 执行 dev 对应的脚本 node app.js
npm run # npm

yarn start # yarn
npm start # npm


与 npm 一样 可以有 ​​yarn start​​​ 和 ​​yarn test​​ 两个简写的运行脚本方式

显示某个包信息

​yarn info <packageName>​​ 可以用来查看某个模块的最新版本信息

列出项目的所有依赖

​yarn list   ​​​​# 列出当前项目的依赖​

​yarn global list # 列出全局安装的模块​

 

package-lock.json和yarn.lock的包依赖区别



​npm​​​的全称是 Node Package Manager,简单来说它就是一个包 (package) 管理工具。​​npm​​​的公司买了一个仓库用来存放这些我们日常所用的包,我们只需要安装​​npm​​​,就能很轻易的通过​​npm​​来很方便的安装这些包了。



node包管理
包是一段可以复用的代码,这段代码可以从全局注册表下载到开发者的本地环境。每个包可能会,也可能不会依赖于别的包。简单地说,包管理器是一段代码,它可以让你管理依赖(你或者他人写的外部代码),你的项目需要这些依赖来正确运行。



​npm​​​简化了我们安装各类包的过程,而​​package.json​​​的作用就是记录我们用​​npm​​​安装过哪些包的。​​package.json​​​可以通过初始化语句​​npm init​​​来生成,刚生成的​​package.json​​​的​​"dependencies"​​​里面是空的,随着你逐渐通过​​npm​​​安装各类包,安装过哪些包,版本号是什么,都会记录在​​"dependencies"​​里面



这样,你只需要在把项目的代码和这个​​package.json​​​一起交给别人,他就能知道要运行这个目需要安装哪些包了。更方便的是,他只要在自己的电脑上输入​​npm install​​​,​​npm​​就会自动安所有这些需要的包。


为啥我们需要一个包管理工具呢?因为我们在​​Node.js​​​上开发时,会用到很多别人写的​​JavaScript​​代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。

更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,​​npm​​可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。

于是一个集中管理的工具应运而生:

  1. 大家都把自己开发的模块打包后放到​​npm​​​官网上,如果要使用,直接通过​​npm​​安装就可以直接用,不用管代码存在哪,应该从哪下载。
  2. ​Yarn​​​ 是为了弥补​​npm​​ 的一些缺陷[速度慢,稳定性高]而出现的。”

npm

​npm​​​ 为你和你的团队打开了连接整个 ​​JavaScript​​​ 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(​​package​​​) (即,代码模块)。来自各大洲的开源软件开发者使用 ​​npm​​ 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。

下面是关于 ​​npm​​​ 的快速介绍:​​npm​​ 由三个独立的部分组成:

  • 网站
    网站 是开发者查找包(​​​package​​​)、设置参数以及管理 ​​npm​​ 使用体验的主要途径。
  • 注册表(​​registry​​​)
    注册表 是一个巨大的数据库,保存了每个包(​​​package​​)的信息。
  • 命令行工具 (​​CLI​​​)
    ​​​CLI​​ 通过命令行或终端运行。开发者通过 CLI 与 npm 打交道。

yarn

​Yarn​​​发布于2016年10月,并在​​Github​​​上迅速拥有了2.4万个Star。而​​npm​​​只有1.2万个​​star​​​。这个项目由一些高级开发人员维护,包括了​​Sebastian McKenzie​​​(Babel.js)和​​Yehuda Katz​​(Ember.js、Rust、Bundler等)。

​Yarn​​​一开始的主要目标是解决上一节中描述的由于语义版本控制而导致的npm安装的不确定性问题。虽然可以使用​​npm shrinkwrap​​​来实现可预测的依赖关系树,但它并不是默认选项,而是取决于所有的开发人员知道并且启用这个选项。Yarn采取了不同的做法。每个​​yarn​​​安装都会生成一个类似于​​npm-shrinkwrap.json​​​的​​yarn.lock​​​文件,而且它是默认创建的。除了常规信息之外,​​yarn.lock​​文件还包含要安装的内容的校验和,以确保使用的库的版本相同。

yarn的优化主要体现在:

  1. 速度快 :
  • 并行安装:无论 npm 还是 Yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。而 Yarn 是同步执行所有任务,提高了性能。
  • 离线模式:如果之前已经安装过一个软件包,用Yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。

  1. 安装版本统一:为了防止拉取到不同的版本,​​Yarn​​​ 有一个锁定文件 (lock file) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,Yarn 就会创建(或更新)​​yarn.lock​​ 这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。
  2. 更好的语义化: ​​yarn​​​改变了一些​​npm​​​命令的名称,比如 ​​yarn add/remove​​​,感觉上比 npm 原本的 ​​install/uninstall​​ 要更清晰。

node包的安装

  1. 执行工程自身 ​​preinstall​
  • 当前 npm 工程如果定义了​​ preinstall​​ 钩子此时会被执行。

  1. 确定首层依赖
  • 模块首先需要做的是确定工程中的首层依赖,也就是 ​​dependencies​​​ 和 ​​devDependencies​​​ 属性中直接指定的模块(假设此时没有添加 ​​npm install​​ 参数)。工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。

  1. 获取模块
  • 获取模块是一个递归的过程,分为以下几步:
  • 获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 ​​package.json​​​ 中往往是 ​​semantic version​​​(semver,语义化版本)。此时如果版本描述文件(​​npm-shrinkwrap.json​​​ 或 ​​package-lock.json​​​)中有该模块信息直接拿即可,如果没有则从仓库获取。如​​ packaeg.json​​​ 中某个包的版本是 ​​^1.1.0,npm​​​ 就会去仓库中获取符合 ​​1.x.x​​ 形式的最新版本。
  • 获取模块实体。上一步会获取到模块的压缩包地址(​​resolved​​ 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。
  • 查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。

  1. 模块扁平化(​​dedupe​​)
  • 上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 ​​loadsh​​​,B 模块同样依赖于 ​​lodash​​​。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。​​yarn​​​和从 ​​npm5​​​ 开始默认加入了一个 ​​dedupe​​​ 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是​​ node-modules​​​ 的第一层。当发现有重复模块时,则将其丢弃。这里需要对重复模块进行一个定义,它指的是模块名相同且 ​​semver​​​ 兼容。每个 ​​semver​​​ 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 ​​dedupe​​ 过程中被去掉。

  1. 安装模块
  • 这一步将会更新工程中的​​node_modules​​​,并执行模块中的生命周期函数(按照 ​​preinstall、install、postinstall​​ 的顺序)。

  1. 执行工程自身生命周期
  • 当前 npm 工程如果定义了钩子此时会被执行(按照 ​​install、postinstall、prepublish、prepare​​ 的顺序)。



Pakage-lock.json文件的作用

在​​5.X.X​​​之后的​​npm​​​版本中,​​pakage-lock.json​​​是会被自动生成的。​​pakage-lock.json​​被创建的目的就是更精确的记录包的各类信息。




​version​​​记录了包的版本,​​resolved​​​记录了包的下载来源。这样,在通过​​npm install​​命令安装时,不仅能够安装相同版本号的包,而且连包的下载源都是一样的,这样,我们就实现了真正意义上的安装一模一样的依赖包,从而确保程序的成功运行。

那么我们在有了​​pakage-lock.json​​​后是不是就不需要​​package.json​​​了呢?不,我们依旧需要​​package.json​​​。这两个文件之间的关系可以这样来理解:​​package.json​​​负责的不仅仅是记录各种依赖包,它还记录了其他信息,包括​​project properties​​​, ​​description​​​, ​​author​​​ & ​​license​​​ 等等,而​​pakage-lock.json​​​的作用仅仅是辅助​​package.json​​​锁定依赖包的版本。​​pakage-lock.json​​​可有可无,没有的话只是不能锁定版本而已,而​​package.json​​是必须要有的。


 

lock文件

锁文件是由包管理器自动生成的。它包含了重现全部的依赖源码树需要的所有信息、你的项目依赖中的所有信息,以及它们各自的版本。

现在值得强调的是,​​Yarn​​​ 使用了锁文件,而​​ npm5​​​以前没有默认锁文件,​​npm5​​之后加入了默认锁文件功能。我们会谈到这种差别导致的一些后果。既然我已经向你介绍了包管理器这部分,现在我们来讨论依赖本身。

目前常见的两种lock文件:

  1. ​packahe-lock.json​​ 是npm5之后默认生成的锁文件
  2. ​yarn.lock​​ 是yarn的锁文件

package-lock.json把所有的包的依赖顺序列出来,第一次出现的包名会提升到顶层,后面重复出现的将会放入被依赖包的node_modules当中。引起不完全扁平化问题。

 



yarn.lock解析

显然yarn.lock锁文件把所有的依赖包都扁平化的展示了出来,对于同名包但是semver不兼容的作为不同的字段放在了yarn.lock的同一级结构中。

 


yarn.lock文件

yarn.lock 锁定了安装包的精确版本以及所有依赖项。有了这个文件,你可以确定项目团队的每个成员都安装了精确的软件包版本,部署可以轻松地重现,且没有意外的 bug,并且这个文件可以使得程序在不同的机器上可以攻取一致的体验

Yarn 锁定文件的和安装算法的存在,确保了将应用程序部署到生产环境时,安装的依赖在开发机器之间,产生的文件和文件夹结构完全相同。