看完本文,你将从整体了解依赖版本锁定原理,package-lock.json
或 yarn.lock
的重要性。首先要从最近接连出现两起有关 npm
安装 package.json
中依赖包,由于依赖包版本更新 bug
造成项目出错问题说起。
项目本地打包正常,但是线上使用 Jenkins
完成 DevOps
交付流水线打包出错问题。报出如下错误:
**17:15:32** ERROR in ./node_modules/clipboard/dist/clipboard.js
**17:15:32** Module build failed (from ./node_modules/babel-loader/lib/index.js):
**17:15:32** Error: Couldn't find preset "@babel/env" relative to directory "/app/workspace/SIT/node_modules/clipboard"
显示错误原因是 clipboard
插件没有安装 @babel/env
预设(preset
)。明显这个是插件问题了,去官方库 clipboard
[1] 查看源码发现该库依赖包很少,大部分是原生实现。再看 issue
别人有没有出现同样的问题,目前来看还没有人提出。以此推断可能是插件本身的 "问题" 了。
但是我本地项目打包正常,线上的出错,可能由于本地版本和线上版本不一致导致(某个小版本出现的 bug
)的。通过查看package.json
配置的 clipboard: "^2.0.4"
,线上实际安装版本是 2.0.7
,而我本地实际安装版本是 2.0.6
因此定位到 2.0.7
出现的 “问题”。
由于是插件本身“问题”,我的临时解决办法是锁定到 2.0.4
版本,也就是 clipboard: "2.0.4"
,后面加上 package-lock.json
。
打破沙锅问到底既然“问题”已经定位到了 2.0.7
版本,进一步通过对比此次版本提交文件内容差异,发现 .babelrc
文件用到的 preset
是 env
。
2.0.7
版本用的是 @bable/env
,将 babel
更新到了 7!
问题基本定位到了,这里就顺便给作者提了一个 issues
[2]。
一直正常使用的 braft-editor
优秀的富文本编辑器插件,最近在其他小伙伴电脑或者在我本地电脑重新部署项目,启动后发现 toHtml()
方法获取富文本 html
内容总是空!
历史版本是正常的,猜测可能又是版本更新造成。同样的,去官方库 braft\-editor[3]看看 issues
别人有没有遇到同样的问题。果然这次有,原因是它的依赖包 draft-js
[4] 更新后的问题,具体的看这个 issues
[5]。
这个是由于插件的依赖包更新出现的问题,直接去锁定当前插件没有作用,不会对它的依赖包产生约束(依赖包还是会去下载最新版本的包)。我的临时解决办法是尝试将版本回退到后一个版本并锁定。这样做的原因是回退版本的依赖包版本肯定会低于现在的,之前的版本是正常的。
其实这两起事件是同一个诱因导致的:没有锁定当前项目依赖树模块的版本。下面就来探究一下依赖包的版本管理。
package.json
在前端工程化中主要用来记录依赖包名称、版本、运行指令等信息字段。其中,dependencies
字段指定了项目运行所依赖的模块,devDependencies
指定项目开发所需要的模块。它们都指向一个对象。该对象的各个成员,分别由模块名和对应的版本要求组成,表示依赖的模块及其版本范围。对应的版本可以加上各种限定,主要有以下几种:
1.2.2
,遵循“大版本.次要版本.小版本”的格式规定,安装时只安装指定版本。tilde
)+指定版本:比如 ~1.2.2
,表示安装 1.2.x
的最新版本(不低于1.2.2
),但是不安装 1.3.x
,也就是说安装时不改变大版本号和次要版本号。caret
)+指定版本:比如 ˆ1.2.2
,表示安装 1.x.x
的最新版本(不低于 1.2.2
),但是不安装 2.x.x
,也就是说安装时不改变大版本号。需要注意的是,如果大版本号为 0,则插入号的行为与波浪号相同,这是因为此时处于开发阶段,即使是次要版本号变动,也可能带来程序的不兼容。当我们使用比如 npm install package -save
安装一个依赖包时,版本是插入号形式。这样每次重新安装依赖包 npm install
时”次要版本“和“小版本”是会拉取最新的。一般的,主版本不变的情况下,不会带来核心功能变动,API
应该兼容旧版,但是这在开源的世界里很难控制,尤其在复杂项目的众多依赖包中难免会引入一些意想不到的 bug
。
正是存在这每次重新安装,依赖树模块版本存在的不确定性,才有了相应的锁定版本机制。
npm5
之前可以通过 npmshrinkwrap
实现。通过运行 npm shrinkwrap
,会在当前目录下生成一个 npm-shrinkwrap.json
文件,它是 package.json
中列出的每个依赖项的大型列表,应安装的特定版本,模块的位置(URI
),验证模块完整性的哈希,它需要的包列表,以及依赖项列表。运行 npm install
的时候会优先使用 npm-shrinkwrap.json
进行安装,没有则使用 package.json
进行安装。
在 npm5
版本后,当我们运行 npm intall
发现会生成一个新文件 package-lock.json
,内容跟上面提到的 npm-shrinkwrap.json
基本一样。
"vue-loader": {
"version": "14.2.4",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-14.2.4.tgz",
"integrity": "sha512-bub2/rcTMJ3etEbbeehdH2Em3G2F5vZIjMK7ZUePj5UtgmZSTtOX1xVVawDpDsy021s3vQpO6VpWJ3z3nO8dDw==",
"dev": true,
"requires": {
"consolidate": "^0.14.0",
"hash-sum": "^1.0.2",
"loader-utils": "^1.1.0",
"lru-cache": "^4.1.1",
"postcss": "^6.0.8",
"postcss-load-config": "^1.1.0",
"postcss-selector-parser": "^2.0.0",
"prettier": "^1.16.0",
"resolve": "^1.4.0",
"source-map": "^0.6.1",
"vue-hot-reload-api": "^2.2.0",
"vue-style-loader": "^4.0.1",
"vue-template-es2015-compiler": "^1.6.0"
},
"dependencies": {
"postcss-load-config": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz",
"integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=",
"dev": true,
"requires": {
"cosmiconfig": "^2.1.0",
"object-assign": "^4.1.0",
"postcss-load-options": "^1.2.0",
"postcss-load-plugins": "^2.3.0"
}
},
}
},
当项目中已有 package-lock.json
文件,在安装项目依赖时,将以该文件为主进行解析安装指定版本依赖包,而不是使用 package.json
来解析和安装模块。因为 package-lock
为每个模块及其每个依赖项指定了版本,位置和完整性哈希,所以它每次创建的安装都是相同的。无论你使用什么设备,或者将来安装它都无关紧要,每次都应该给你相同的结果。
npm5
版本下 install
规则npm
并不是一开始就是按照现有这种规则制定的。
5.0.x
版本:
不管 package.json
中依赖是否有更新,npm install
都会根据 package-lock.json
下载。针对这种安装策略,有人提出了这个 issue[6] ,然后就演变成了 5.1.0
版本后的规则。
5.1.0
版本后:
当 package.json
中的依赖项有新版本时,npm install
会无视 package-lock.json
去下载新版本的依赖项并且更新 package-lock.json
。针对这种安装策略,又有人提出了一个 issue[7] 参考 npm
贡献者 iarna
的评论,得出 5.4.2
版本后的规则。
5.4.2
版本后:
如果只有一个 package.json
文件,运行 npm install
会根据它生成一个 package-lock.json
文件,这个文件相当于本次 install
的一个快照,它不仅记录了 package.json
指明的直接依赖的版本,也记录了间接依赖的版本。
如果 package.json
的 semver-range version
和 package-lock.json
中版本兼容(package-lock.json
版本在 package.json
指定的版本范围内),即使此时 package.json
中有新的版本,执行 npm install
也还是会根据 package-lock.json
下载。
如果手动修改了 package.json
的 version ranges
,且和 package-lock.json
中版本不兼容,那么执行 npm install
时 package-lock.json
将会更新到兼容 package.json
的版本。
yarn
的出现主要目标是解决上面描述的由于语义版本控制而导致的 npm
安装的不确定性问题。虽然可以使用 npm shrinkwrap
来实现可预测的依赖关系树,但它并不是默认选项,而是取决于所有的开发人员知道并且启用这个选项。yarn
采取了不同的做法。每个 yarn
安装都会生成一个类似于npm-shrinkwrap.json
的 yarn.lock
文件,而且它是默认创建的。除了常规信息之外,yarn.lock
文件还包含要安装的内容的校验和,以确保使用的库的版本相同。
yarn
的出现主要做了如下优化:
npm
还是 yarn
在执行包的安装时,都会执行一系列任务。npm
是按照队列执行每个 package
,也就是说必须要等到当前 package
安装完成之后,才能继续后面的安装。而 yarn
是同步执行所有任务,提高了性能。yarn
再次安装时之间从缓存中获取,就不用像 npm
那样再从网络下载了。yarn
有一个锁定文件 (lock file
) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,yarn
就会创建(或更新)yarn.lock
这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。yarn
改变了一些 npm
命令的名称,比如 yarn add/remove
,比 npm
原本的 install/uninstall
要更清晰。preinstall
。当前 npm
工程如果定义了 preinstall
钩子此时会被执行。dependencies
和 devDependencies
属性中直接指定的模块(假设此时没有添加 npm install
参数)。工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm
会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。package.json
中往往是 semantic version
(semver
,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json
或 package-lock.json
)中有该模块信息直接拿即可,如果没有则从仓库获取。如 package.json
中某个包的版本是 ^1.1.0
,npm
就会去仓库中获取符合 1.x.x
形式的最新版本。resolved
字段),npm
会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。1
步,如果没有则停止。4 . 模块扁平化(dedupe
)。上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A
模块依赖于 loadsh
,B
模块同样依赖于 lodash
。在 npm3
以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。yarn
和从 npm5
开始默认加入了一个 dedupe
的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules
的第一层。当发现有重复模块时,则将其丢弃。这里需要对重复模块进行一个定义,它指的是模块名相同且 semver
兼容。每个 semver
都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 dedupe
过程中被去掉。
5 . 安装模块。这一步将会更新工程中的 node_modules
,并执行模块中的生命周期函数(按照 preinstall
、install
、postinstall
的顺序)。
6 . 执行工程自身生命周期。当前 npm
工程如果定义了钩子此时会被执行(按照 install
、postinstall
、prepublish
、prepare
的顺序)。
插件 htmlparser2@^3.10.1
和 dom-serializer@^0.2.2
都有使用了 entities
依赖包,不过使用的版本不同,同时我们自己安装一个版本的 entities
包。具体如下:
--htmlparser2@^3.10.1
|--entities@^1.1.1
--dom-serializer@^0.2.2
|--entities@^2.0.0
--entities@^2.1.0
通过 npm install
安装后,生成的 package-lock.json
文件内容和它的 node_modules
目录结构:
可以发现:
dom-serializer@^0.2.2
的依赖包 entities@^2.0.0
和我们自己安装的 entities@^2.1.0
被实际安装成 entities@^2.2.0
,并放在 node_modules
的第一层。因为这两个版本的semver
范围相同,又先被遍历,所有会被合并安装在第一层;htmlparser2@^3.10.1
的依赖包 entities@^1.1.1
被实际安放在 dom-serializer
包的 node_modules
中,并且和 package-lock.json
描述结构保持一致。通过 yarn
安装后,生成的 yarn.lock
文件内容和它的 node_modules
目录结构:
可以发现与 npm install
不同的是:
yarn.lock
中所有依赖描述都是扁平化的,即没有依赖描述的嵌套关系;yarn.lock
中, 相同名称版本号不同的依赖包,如果 semver
范围相同会被合并,否则,会存在多个版本描述。使用 cnpm install
时候,并不会生成 package-lock.json
文件。cnpm install
的时候,就算你项目中有 package-lock.json
文件,cnpm
也不会识别,仍会根据 package.json
来安装。所以这就是为什么之前你用 npm
安装产生了 package-lock.json
,后面的人用 cnpm
来安装,可能会跟你安装的依赖包不一致。
因此,尽量不要直接使用 cnpm install
安装项目依赖包。但是为了解决直接使用 npm install
速度慢的问题,可以设置 npm
代理解决。
// 设置淘宝镜像代理
npm config set registry https://registry.npm.taobao.org
// 查看已设置代理
npm config get registry
当然,也可以通过 nrm
[8] 工具,快捷操作设置代理。
全局安装
$ npm install -g nrm
查看已安装代理列表
$ nrm ls
* npm ----- https://registry.npmjs.org/
yarn ----- https://registry.yarnpkg.com
cnpm ---- http://r.cnpmjs.org/
taobao -- https://registry.npm.taobao.org/
nj ------ https://registry.nodejitsu.com/
skimdb -- https://skimdb.npmjs.com/registry
切换代理
$ nrm use cnpm //switch registry to cnpm
* Registry has been set to: http://r.cnpmjs.org/
测速
nrm test cnpm
* cnpm --- 618ms
然而,设置这些全局代理可能还是不能满足下载一些特定依赖包(在没有 VPN
情况下),比如:node-sass
、puppeteer
、chromedriver
、electron
等。可以通过 .npmrc
文件设置具体依赖包的国内镜像。该文件在项目 npm install
时会被加载读取,优先级高于 npm
全局设置。
registry=https://registry.npm.taobao.org/
sass_binary_site=http://npm.taobao.org/mirrors/node-sass
chromedriver_cdnurl=http://npm.taobao.org/mirrors/chromedriver
electron_mirror=http://npm.taobao.org/mirrors/electron/ npm install -g electron
puppeteer_download_host=http://npm.taobao.org/mirrors/chromium-browser-snapshots/
项目在以后重新构建,由于依赖树中有版本更新,造成意外事故是不可避免的,究其原因是整个依赖树版本没有锁死。解决方案分为如下四种:
package.json
中固定版本。注意:仅能锁定当前依赖包版本,不能控制整棵依赖树版本。npm+npm-shrinkwrap.json
。npm+package-lock.json
。yarn+yarn-lock.json
。根据自身情况选择~
[1]clipboard
: https://github.com/zenorocha/clipboard.js
[2]issues
: https://github.com/zenorocha/clipboard.js/issues/745
[3]braft-editor: https://github.com/margox/braft-editor
[4]draft-js
: https://github.com/facebook/draft-js
[5]issues
: https://github.com/margox/braft-editor/issues/847
[6]issue: https://github.com/npm/npm/issues/16866
[7]issue: https://github.com/npm/npm/issues/17979
[8]nrm
: https://www.npmjs.com/package/nrm
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/1dQPpG83_Fl69eNJ5ZeTrw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。