深入浅出 package-lock.json


问题思考:

1. package-lock.json的意义?

2. npm 拉包机制和源码实现 ?

3. yarn?

4. package-lock.json有没有必要提交?

5. npmrc?

6. npx?

7. 还有 import 直接导入包的cnd地址 和 安装到本地有啥区别:(打包时候的vender 大小 和 是否在缓存获取的取舍)?

...

1. package-lock.json的意义 蹦到官网

This file is intended to be committed into source repositories, and serves various purposes:

1. Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.

2. Provide a facility for users to "time-travel" to previous states of node_modules without having to commit the directory itself.

3. Facilitate greater visibility of tree changes through readable source control diffs.

4. Optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.

5.  As of npm v7, lockfiles include enough information to gain a complete picture of the package tree, reducing the need to read package.json files, and allowing for significant performance improvements.

该文件旨在提交到源存储库中,并具有多种用途:
1. 描述一个依赖关系树的单一表示,这样可以确保队友,部署和持续集成安装完全相同的依赖关系。
2. 为用户提供一种工具,使其可以“时间旅行”到以前的状态, node_modules而不必提交目录本身。
3. 通过可读的源代码控制差异,提高树更改的可见性。
4. 通过允许npm跳过先前安装的程序包的重复元数据解析来优化安装过程。
5. 从npm v7开始,锁定文件包含足够的信息以获取软件包树的完整图片,从而减少了读取package.json 文件的需求并显着提高了性能。

  2. npm 拉包机制和源码实现 来自拉勾教育,收费的那种0.0

npm install 安装流程图

2.1 npm install 之后执行了哪些步骤?

1. 检查并获取 npm 配置,这里的优先级为:项目级的 .npmrc 文件 > 用户级的 .npmrc 文件> 全局级的 .npmrc 文件 > npm 内置的 .npmrc 文件。
2. 检查项目中是否有 package-lock.json 文件。
3. 3.1 如果,则检查 package-lock.json 和 package.json 中声明的依赖是否一致:
         a: 一致,直接使用 package-lock.json 中的信息,从缓存或网络资源中加载依赖;
         b: 不一致,按照 npm 版本进行处理(不同 npm 版本处理会有不同,具体处理方式如图所示)。
   3.2 如果没有,则根据 package.json 递归构建依赖树。然后按照构建好的依赖树下载完整的依赖资源,在下载时就会检查是否存在相关资源缓存:
        a: 存在,则将缓存内容解压到 node_modules 中;
        b: 否则就先从 npm 远程仓库下载包,校验包的完整性,并添加到缓存,同时解压到 node_modules。
4. 生成 package-lock.json。    

2.2 npm 缓存机制

1. 获取配置缓存的根目录:npm config get cache
2. 缓存目录的内容介绍: 打开_cacache文件后,可以看到三个目录content-v2, index-v5, tmp (空文件)。
    2.1 content-v2 里面基本都是一些二进制文件。为了使这些二进制文件可读,我们把二进制文件的扩展名改为 .tgz,然后进行解压,得到的结果其实就是我们的 npm 包资源。
    2.2 index-v5 文件中,这些内容是 content-v2 里文件的索引。
3. 缓存如何被利用: 
   3.1 当 npm install 执行时,通过pacote把相应的包解压在对应的 node_modules 下面。npm 在下载依赖时,先下载到缓存当中,再解压到项目 node_modules 下。pacote 依赖npm-registry-fetch来下载包,npm-registry-fetch 可以通过设置 cache 属性,在给定的路径下根据IETF RFC 7234生成缓存数据。
    3.2 在每次安装资源时,根据 package-lock.json 中存储的 integrity、version、name 信息生成一个唯一的 key,这个 key 能够对应到 index-v5 目录下的缓存记录。如果发现有缓存资源,就会找到 tar 包的 hash,根据 hash 再去找缓存的 tar 包,并再次通过pacote把对应的二进制文件解压到相应的项目 node_modules 下面,省去了网络下载资源的开销。

注意,这里提到的缓存策略是从 npm v5 版本开始的。在 npm v5 版本之前,每个缓存的模块在 ~/.npm 文件夹中以模块名的形式直接存储,储存结构是:{cache}/{name}/{version}。

3. yarn 来自拉勾教育,收费的那种0.0

3.1 yarn的介绍

    当 npm 还处在 v3 时期时,一个叫作 Yarn 的包管理方案横空出世。2016 年,npm 还没有 package-lock.json 文件,安装速度很慢,稳定性也较差,而 Yarn 的理念很好地解决了以下问题。

1. 确定性:通过 yarn.lock 等机制,保证了确定性。即不管安装顺序如何,相同的依赖关系在任何机器和环境下,都可以以相同的方式被安装。(在 npm v5 之前,没有 package-lock.json 机制,只有默认并不会使用的npm-shrinkwrap.json。)
2. 采用模块扁平安装模式:将依赖包的不同版本,按照一定策略,归结为单个版本,以避免创建多个副本造成冗余(npm 目前也有相同的优化)。
3. 网络性能更好:Yarn 采用了请求排队的理念,类似并发连接池,能够更好地利用网络资源;同时引入了更好的安装失败时的重试机制。
4. 采用缓存机制,实现了离线模式(npm 目前也有类似实现)。

3.2 yarn安装机制和背后思想


yarn的安装流程图

Yarn 的安装过程主要有以下 5 大步骤:检测(checking)→ 解析包(Resolving Packages) → 获取包(Fetching Packages)→ 链接包(Linking Packages)→ 构建包(Building Packages)
1. 检测包(checking): 这一步主要是检测项目中是否存在一些 npm 相关文件,比如 package-lock.json 等。如果有,会提示用户注意:这些文件的存在可能会导致冲突。在这一步骤中,也会检查系统 OS、CPU 等信息
2. 解析包(Resolving Packages):这一步会解析依赖树中每一个包的版本信息。
    2.1 首先获取当前项目中 package.json 定义的 dependencies、devDependencies、optionalDependencies 的内容,这属于首层依赖。
    2.2 接着采用遍历首层依赖的方式获取依赖包的版本信息,以及递归查找每个依赖下嵌套依赖的版本信息,并将解析过和正在解析的包用一个 Set 数据结构来存储,这样就能保证同一个版本范围内的包不会被重复解析。
        2.2.1 对于没有解析过的包 A,首次尝试从 yarn.lock 中获取到版本信息,并标记为已解析;
        2.2.2 如果在 yarn.lock 中没有找到包 A,则向 Registry 发起请求获取满足版本范围的已知最高版本的包信息,获取后将当前包标记为已解析。
总之,在经过解析包这一步之后,我们就确定了所有依赖的具体版本信息以及下载地址。

解析包获取流程图

3. 获取包(Fetching Packages):首先需要检查缓存中是否存在当前的依赖包,同时将缓存中不存在的依赖包下载到缓存目录。
如何判断缓存中是否存在当前的依赖包?
    Yarn 会根据 cacheFolder+slug+node_modules+pkg.name 生成一个 path,判断系统中是否存在该 path,如果存在证明已经有缓存,不用重新下载。这个 path 也就是依赖包缓存的具体路径
    对于没有命中缓存的包,Yarn 会维护一个 fetch 队列,按照规则进行网络请求。如果下载包地址是一个 file 协议,或者是相对路径,就说明其指向一个本地目录,此时调用 Fetch From Local 从离线缓存中获取包;否则调用 Fetch From External 获取包。最终获取结果使用 fs.createWriteStream 写入到缓存目录下。

获取包流程图

4. 链接包(Linking Packages):这一步是将项目中的依赖复制到项目 node_modules 下,同时遵循扁平化原则。在复制依赖前,Yarn 会先解析 peerDependencies,如果找不到符合 peerDependencies 的包,则进行 warning 提示,并最终拷贝依赖到项目中。5.

链接包解析流程图

5. 构建包(Building Packages):如果依赖包中存在二进制包需要进行编译,会在这一步进行。

3.3 扁平化安装模式

举个🌰: 项目中有A依赖v1.0, A又依赖Bv1.0。

npm 不同版本的安装结构图

当项目新添加了 C 依赖,而它依赖另一个版本的 B v2.0。这时候版本要求不一致导致冲突,B v2.0 没办法放在项目平铺目录下的 node_moduls 文件当中,npm v3 会把 C 依赖的 B v2.0 安装在 C 的 node_modules 下:

npm 不同版本的安装结构图

接下来,在 npm v3 中,假如我们的 App 现在还需要依赖一个 D,而 D 也依赖 B v2.0 ,我们会得到如下结构:

npm 不同版本的安装结构图

为什么 B v1.0 出现在项目顶层 node_modules,而不是 B v2.0 出现在 node_modules 顶层呢

假设这时候项目又添加了一个依赖 E ,E 依赖了 B v1.0 ,安装 E 之后,我们会得到这样一个结构:

npm 不同版本的安装结构图

如果我们想更新模块 A 为 v2.0,而模块 A v2.0 依赖了 B v2.0,npm v3 会怎么处理呢?它的结构如下:

为什么Bv1.0依然存在?

npm 不同版本的安装结构图

这时模块 B v2.0 分别出现在了 A、C、D 模块下——重复存在了。

通过这一系列操作我们可以看到:npm 包的安装顺序对于依赖树的影响很大。模块安装顺序可能影响 node_modules 内的文件数量

这里一个更理想的依赖结构理应是:

npm 不同版本的安装结构图

过了一段时间,模块 E v2.0 发布了,并且 E v2.0 也依赖了模块 B v2.0 ,npm v3 更新 E 时会怎么做呢?

npm 不同版本的安装结构图

此时顶层已经有了B v2.0,如何删除嵌套层多余的B v2.0?
1. 删除node_modules, 重新安装。
2. npm dedupe命令
结构如下:

npm 不同版本的安装结构图

实际上,Yarn 在安装依赖时会自动执行 dedupe 命令。整个优化的安装过程,就是扁平化安装模式

4. package-lock.json有没有必要提交?

看项目定位。

1. 如果开发一个应用,我建议把 package-lock.json 文件提交到代码版本仓库。这样可以保证项目组成员、运维部署成员或者 CI 系统,在执行 npm install 后,能得到完全一致的依赖安装内容。
2. 如果你的目标是开发一个给外部使用的库,那就要谨慎考虑了,因为库项目一般是被其他项目依赖的,在不使用 package-lock.json 的情况下,就可以复用主项目已经加载过的包,减少依赖重复和体积。
3. 如果我们开发的库依赖了一个精确版本号的模块,那么提交 lockfiles 到仓库可能会造成同一个依赖不同版本都被下载的情况。如果作为库开发者,真的有使用某个特定版本依赖的需要,一个更好的方式是定义 peerDependencies。

因此,一个推荐的做法是:把 package-lock.json 一起提交到代码库中,不需要 ignore。但是执行 npm publish 命令,发布一个库的时候,它应该被忽略而不是直接发布出去。

补充: package-lock.json是无法发布

5. npmrc 蹦官网

npm 的配置文件

npm gets its config settings from the command line, environment variables, and npmrc files.

The four relevant files are:
    1. per-project config file (/path/to/my/project/.npmrc)
    2. per-user config file (~/.npmrc)
    3. global config file ($PREFIX/etc/npmrc)
    4. npm builtin config file (/path/to/npm/npmrc)

6. npx 

npm 从5.2版开始,增加了 npx 命令。Node 自带 npm 模块,所以可以直接使用 npx 命令。万一不能用,就要手动安装一下。
npm install -g npx

使用场景: 
1. 调用项目安装的模块, (npx mocha --version)
2. 避免全局安装模块 (npx http-server)
3. 使用不同版本的 node (npx node@0.12.8 -v)
4. 执行 GitHub 源码 (npx github:piuccio/cowsay hello)
    注意,远程代码必须是一个模块,即必须包含package.json和入口脚本。

7. cdn vs local?

影响因素:

1. 离线开发?
2. cdn大文件,local小文件?
3. 预缓存保证?
4. 禁止访问(国家/地区 封锁某些cdn服务的域或IP)
5. 两点故障?(站点宕机)
6. 安全性?(修改代码,收集用户系统数据。。。)
7. 失去控制权?(网站文件控制权)
8. 访问速度?

参考: 

npm官网
npx
拉勾教育
cdn&local
不用cdn的7个理由
cdn大文件 vs local小文件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容