npm内部机制与核心原理

devtools/2024/10/20 10:05:20/

npm 的核心目标:
Bring the best of open source to you, your team and your company.
npm 最重要的任务是安装和维护开源库。

npm 安装机制与背后思想

npm 的安装机制非常值得探究。Ruby 的 Gem,Python 的 pip 都是全局安装机制,但是 npm 的安装机制秉承了不同的设计哲学。

它会优先安装依赖包到当前目录,使得不同应用项目的依赖各成体系,同时还能减轻包作者的 API 兼容性压力,但这样的缺陷也很明显:如果项目 A 和项目 B 都依赖的公共库 C,那么 C 一般会在项目A和项目B中各被安装一次。

当然,对于一些工具模块,比如 supervisor 和 gulp,仍然可以使用全局安装模式,这样方便注册 path 变量,利用我们在任何地方直接使用 supervisor、gulp 命令。不过,一般建议不同项目维护自己局部的 gulp 开发工具以适配不同的项目需求。

下面的流程图体现了 npm 的安装机制:
在这里插入图片描述构建依赖树时,当前依赖项目无论是直接依赖还是子依赖,我们都应该遵循扁平化原则优先将其放置在 node_modules 根目录下。在这个过程中,遇到相同模块应先判断已放置在依赖树中的模块版本是否符合对新模块版本的要求,如果符合就跳过,不符合则在当前模块的 node_modules 下放置该模块。

npm 缓存机制

对于一个依赖包的同一版本进行本地化缓存,这是当代依赖包管理工具的常见设计。使用时要先执行以下命令:

npm config get cache
// C:\Users\xxxxxx\AppData\Local\npm-cache

cd 命令进入缓存目录可以看到 _cacache 文件夹。在 npm v5 版本之后,缓存数据均放在根目录的 _cacache 中请添加图片描述
content-v2: 存放一些二进制文件。为了使这些二进制文件可读,将文件的扩展名改为 .tgz,然后进行解压,得到的结果其实就是npm包资源。
index-v5:存放一些描述性文件,事实上就是 content-v2 中文件的索引。
tmp:临时文件

这些缓存是如何被存储并利用的呢?

这就和 npm install机 制联系在一起了。当 npm install 执行时,会通过 pacote 将相应的包资源解压在对应的 node_modules 下面。npm 下载依赖时,会先将依赖下载到缓存中,再将其解压到项目的 node_modules 下。pacote 依赖 npm-registry-fetch 来下载包资源,npm-registry-fetch 可以通过设置 cache 属性在给定的路径下根据 IETF RFC 7234 生成缓存数据。

接着,在每次安装资源时,根据 package-lock.json 中存储的 integrity、version、name 信息生成一个唯一的 key,这个 key 能对应到 index-v5 下的缓存记录。如果发现有缓存资源,就会找到 tar 包的 hash 值,根据 hash 值找到缓存的包,并再次通过 pacote 将对应的二进制文件解压到相应的项目 node_modules 下,省去了网络下载资源的时间。

npm 不完全指南

自定义 npm init

npm 支持自定义 npm init,快速创建一个符合自己需求的自定义项目。npm init 命令本身并不复杂,它的功能其实就是调用Shell 脚本输出一个初始化的 package.json 文件。相应地,我们要自定义 npm init 命令,就是写一个 Node.js 脚本,它的 module.exports 即为 package.json 配置内容。

为了实现更加灵活的自定义功能,我们可以使用 prompt() 方法,获取用户输入内容:

const desc = prompt('请输入项目描述', '描述...')
module.exports = {key: 'value',name: prompt('name?', process.cwd().split('/').pop()),version: prompt('version?', '0.1.1'),description: desc,main: 'index.js',repository: prompt('github repository url', '', function() {if (url) {run('touch README.md');run('git init');run('git add README.md');run('git commit -m "first commit"');run(`git remote add origin ${url}`);run('git push -u origin master');}return url})
}

假设该脚本名为 .npm-init.js,执行以下命令来确保 npm init 所对应的脚本指向正确的文件

npm config set init-module ~\.npm-init.js

我们也可以通过配置 npm init 默认字段来自定义 npm init 内容:

npm config set init.author.name "Lucas"
npm config set init.author.email "xxx.com"
npm config set init.author.url "xxx.com"
npm config set init.license "MIT"
npx 的作用

npx 在 npm v5.2 版本中被引入,解决了使用 npm 时面临的快速开发、调试,以及在项目内使用全局模块的痛点。

在传统 npm 模式下,如果需要使用代码检测工具 ESLint,就要先进行安装,命令如下:

npm install eslint --save-dev

然后在项目根目录下执行命令,或通过项目脚本和 package.json 的 npm scripts 字段调用 ESLint。

./node_modules/.bin/eslint --init
./node_modules/.bin/eslint yourfile.js

而使用 npx 就简单多了:

npx eslint --init
npx eslint yourfile.js

npx 可以直接运行 node_modules/.bin 文件夹下的文件。npx 可以自动去 node_modules/.bin 路径和环境变量 $PATH 里面检查命令是否存在,而不需要再在 package.json 中定义相关的 script。

npx 另一个更实用的特点是,它在执行模块时会优先安装依赖,但是在安装成功后便删除此依赖,避免了全局安装带来的问题。

npm 多源镜像和企业级部署私服原理

npm 中的源(regsitry) 其实就是一个查询服务。我们可以通过 npm config 命令来设置安装源或某个作用范围域对应的安装源,很多企业也会搭建自己的 npm 源。我们可以通过 npm-preinstall 的钩子和 npm 脚本,在安装公共依赖前自动切换源。

"scripts": {"preinstall": "node ./bin/preinstall.js"
}
// 其中 preinstall.js 脚本的逻辑是通过 Node.js 执行 npm config set 命令
require(' child_process').exec('npm config get registry', function(error, stout, stderr) {if (!stdout.toString().match(/registry\.x\/com/)) {exec('npm config set @xscope:registry https://xxx.com/npm/')}
})

http://www.ppmy.cn/devtools/10267.html

相关文章

跟着Datawhale重学数据结构与算法(3)---排序算法

开源链接:【 教程地址 】【电子网站】 【写博客的目的是记录自己学习过程,方便自己复盘,专业课复习】 数组排序: #mermaid-svg-F3iLcKsVv8gcmqqC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16p…

日语对话构建调查研究

日语对话构建调查研究 一,OKWave(オウケイウェイヴ)网站NLP数据调研 1.OKWave速递 OKWave网址:OKWave 网站印象图 2.调研结论 (1)可行性:无特殊反爬手段,可直接从OKWave网站抓…

CSS3新增特性(一)

目录 一、CSS3 新增选择器 1. 子级选择器 2. 兄弟选择器 相邻兄弟选择器 其他兄弟选择器 3. 结构伪类选择器 ① E:first-child ② E:last-child ③ nth-child(n) n为数字: n为关键字: n为公式: ④ E: firs…

授人以渔 选购篇九:扫地机器人(扫拖机器人)选购要点

文章目录 系列文章自动上下水导航技术:立体激光导航视觉导航,多传感器清洁能力:胶条刷、旋转拖布健康卫生:热水洗拖布、热风烘干智能功能品牌其他 系列文章 授人以渔 选购篇一:信用卡选购要点 授人以渔 选购篇二&…

【机器学习300问】77、什么是梯度消失和梯度爆炸?

一、梯度消失(Vanishing gradients) (1)定义 在训练深度神经网络时,随着误差梯度从输出层向输入层逐层回传,梯度可能因为连乘效应逐渐减小。当使用激活函数的导数的最大值小于1时,深度网络中越…

设计模式之访问者模式(上)

访问者模式 1)概述 1.概念 访问者模式包含访问者和被访问元素两个主要组成部分。 处方单中的各种药品信息就是被访问的元素,而划价人员和药房工作人员就是访问者,被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行…

vi, vim,data,wc,系统常用命令-读书笔记(十)

vi 文本编辑器 基本上 vi 共分为三种模式,分别是“一般指令模式”、“编辑模式”与“命令行命令模式”。这三种模式的作用分别是: 一般指令模式(command mode)以 vi 打开一个文件就直接进入一般指令模式了(这是默认的…

Java后端中如何随意接收参数

目录 一、参数名相同 二、参数名不同,使用RequestParam注解 大概访问流程是:先访问test控制器,test控制器跳转到index页面(此时index页面收到了test控制器传来的数据),然后在index页面跳转到t5控制器&…