每日技术:npm模块安装机制

摘要:
例如,模块A依赖于lodash,模块B也依赖于lodach。在npm3之前,它将严格按照依赖树结构进行安装,这将导致模块冗余。默认情况下,从npm3添加了一个重复数据消除过程---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------阅读阮一峰《NPM模块机制简介》的原始注释:http://www.ruanyifeng.com/blog/2016/01/npm-install.htmlnpm它是Node的模块管理器,功能极其强大。这是Node成功的重要原因之一。本文介绍了NPM模块安装机制的细节以及如何解决安装缓慢的问题。registrynpm模块仓库提供了一个名为registry的查询服务。

内容来自:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/22

npm模块安装机制

  • 发出npm install命令
  • 查询node_modules目录之中是否已经存在指定模块
    • 若存在,不再重新安装
    •   若不存在,
      • npm 向register查询模块压缩包的网址
      • 下载压缩包,存放在根目录下的.npm目录里
      • 解压压缩包到当前项目的node_modules目录

npm实现原理

输入npm install命令并敲下回车后,会经历如下几个阶段:

1.执行工程自身preinstall

当前npm工程如果定义了preinstall钩子,此时会被执行

2.确定首层依赖模块

首先,需要做的是确定工程中的首层依赖,也就是dependencies和devDependencies属性中直接指定的模块(假设此时没有添加npm install参数)

工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。

3.获取模块

获取模块是一个递归的过程,分为以下几步:

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

4.模块扁平化

上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如A模块依赖于lodash,B模块同样依赖于lodash,在npm3以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。

从npm3开始默认加入了一个dedupe的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是node-modules下,foo模块依赖lodash@^1.0.0,bar模块依赖lodash@^1.1.0,则^1.1.0为兼容版本。

而当foo依赖lodash@^2.0.0,bar依赖lodash@^1.1.0,则根据semver的规则,二者不存在兼容版本,将会一个版本放在node_modules里,另一个仍保留在依赖树里。

举个例子,假设一个依赖树原本是这样:

node_modules

-- foo

---- lodash@version1

-- bar

---- lodash@version2

假设version1和version2是兼容版本,则经过dedupe会成为下面的形式:

node_module

-- foo

-- bar

-- lodash (保留的版本为兼容版本)

假设version1和version2为非兼容版本,则后面的版本保留在依赖树中

node_modules

-- foo

-- lodash@version1

-- bar

---- lodash@version2

5.安装模块

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

6.执行工程自身生命周期

当前npm工程如果定义了钩子此时会被执行(按照install、postinstall、prepublish、prepare的顺序)

最后一步以生成或更新版本描述文件,npm install过程完成。

 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

读阮一峰《npm模块按照机制简介》笔记

原文:http://www.ruanyifeng.com/blog/2016/01/npm-install.html

npm是Node的模块管理器,功能极其强大。它是Node获得成功的重要原因之一

本文介绍npm模块安装机制的细节,以及如何解决安装速度慢的问题。

一、npm install

如果你希望,一个模块不管是否安装过,npm都要强制重新安装,可以使用-f或-force参数

npm install <packageName> --force

二、npm update

如果想更新已安装模块,就要用到npm update命令

npm update <packageName>

它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。

registry

npm模块仓库提供了一个查询服务,叫做registry。以npmjs.org为例,它的查询服务网址是https://registry.npmjs.org/

这个网址后面跟上模块名,就会得到一个JSON对象,里面是该模块所有版本的信息。比如访问https://registry.npmjs.org/react,就会看到react模块所有版本的信息

它跟下面命令的效果是一样的

npm view react

# npm view 的别名
npm info react
npm show react
npm v react

访问https://registry.npmjs.org/react/v0.14.6就可以看到React的0.14.6版。

返回的JSON对象里面,有一个dist.tarball属性,是该版本压缩包的网址。

dist: {
    shasum:'2a57c2cf8747b483759ad8de0fa47fb0c5cf5c6a',
    tarball:  'http://registry.npmjs.org/react/-/react-0.14.6.tgz'
}

到这个网址下载压缩包,在本地解压,就得到了模块的源码。

缓存目录

npm install 或npm update命令,从registry下载压缩包之后,都存放在本地的缓存目录。

这个缓存目录,在Linux或Mac默认是用户主目录下的.npm目录,在Windows默认是%AppData%/npm-cache.

通过配置命令,可以查看这个目录的具体位置

npm config get cache

浏览目录

ls ~/.npm
#或者
npm cache ls

你会看到里面存放着大量的模块,储存结构是{cache}/{name}/{version}

$ npm cache ls react
~/.npm/react/react/0.14.6/
~/.npm/react/react/0.14.6/package.tgz
~/.npm/react/react/0.14.6/package/
~/.npm/react/react/0.14.6/package/package.json

清空缓存命令

rm -rf ~/.npm/*

或者

npm cache clean

模块的安装过程

总结一下,Node模块的安装过程是这样的

1.发出npm install命令

2.npm向registry查询模块压缩包的网址

3.下载压缩包,存放在~/.npm目录

4.解压压缩包到当前项目的node_modules

注意,一个模块安装以后,本地其实保存了两份。一份是~/.npm目录下的压缩包。另一份是node_modules目录下解压后的代码。但是运行npm install的时候,只会检查node_modules目录,而不会检查~/.npm目录。也就是说,如果一个模块在~/.npm下有压缩包,但是没有安装在node_modules目录中,npm依然会从远程仓库下载一次新的压缩包。

这种行为固然可以保证总是取得最新的代码,但有时并不是我们想要的。最大的问题是,它会极大地影响安装速度。即使某个模块的压缩包就在缓存目录中,也要去远程仓库下载,这怎么可能不慢呢?

另外,有些场合没有网络,但是你想安装的模块,明明就在缓存目录之中,这时也无法安装。

--cache-min参数

为了解决这些问题,npm提供了一个--cache-min参数,用于从缓存目录安装模块。

--cache-min参数指定一个时间(单位为分钟),只有超过这个时间的模块,才会从registry下载。

npm install --cache-min 999999 <package-name>

上面命令指定,只有超过999999分钟的模块才从registry下载。实际上就是指定,所有模块都从缓存安装,这样就大大加快了下载速度。

它还有另一种写法

npm install --cache-min Infinity <package-name>

离线安装的解决方案

第一类,Registry代理

  • npm-proxy-cache
  • local-npm
  • npm-lazy

上面三个模块的用法很类似,都是在本机起一个Registry服务,所有npm install命令都要通过这个服务代理。

npm-proxy-cache

npm --proxy http://localhost:8080
--https-proxy http://localhost:8080
--strict-ssl false
install

local-npm

npm set registry http://127.0.0.1:5080

npm-lazy

npm --registry http://localhost:8080/ install socket.io

有了本机的Registry服务,就能完全实现缓存安装,可以实现离线使用

第二类,npm install替代

如果能够改变npm install的行为,就能实现缓存安装。npm-cache工具就是这个思路。凡是使用npm install的地方,都可以使用npm-cache替代

npm-cache install

 

第三类,node_modules作为缓存目录

这个方案的思路是,不使用.npm缓存,而是使用项目的node_modules目录作为缓存。

免责声明:文章转载自《每日技术:npm模块安装机制》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SmartThreadPoolhtml+js超大视频上传解决方案下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

React函数组件模拟生命周期(useEffect)

React Hooks提供React.useEffect来解决函数组件没有生命周期的问题 React.useEffect(fn,?)第一个参数是特定实时机执行的回调函数,第二个参数是指依赖项   1.模拟componentDidMount第一次渲染 useEffect(() => { console.log(''); }, []) // 第二...

react-native 极光推送(jpush-react-native)

极光推送官方支持的 React Native 插件 安装 npm install jpush-react-native --savenpm install jcore-react-native --save ## jpush-react-native 1.4.2 版本以后需要同时安装 jcore-react-native 一、自动配置部分(以下命令均在你的...

零基础 Vue 开发环境搭建 打开运行Vue项目

【相关推荐】IntellIJ IDEA 配置 Vue 支持 打开Vue项目 所需文件 node.js环境(npm包管理器)(node-v8.11.3-x64.msi)(npmV5.6.0) cnpm npm的淘宝镜像 vue-cli 构建工具(脚手架) 一、安装node 安装完node,就自动在path里增加环境变量,但是为了以后的本地部署项目,我们需要找...

ES笔记三:集群管理

1.集群中的节点角色 Ingest Node 如何分配? 如何避免脑裂问题? 2.分片及副本 3.集群健康及监控 3.1 catAPI 3.2Cluster API 3.2.1_cluster 3.2.2_nodes 3.2.3_remote 3.2.4_tasks 3.3 X-Pack 4.扩容 5.故障转移 6.Thread Pool 1.集群中的节...

React Native学习-调取摄像头第三方组件:react-native-image-picker

近期做的软件中图片处理是重点,那么自然也就用到了相机照相或者相册选取照片的功能。 react-native中有image-picker这个第三方组件,但是0.18.10这个版本还不是太支持iPad。 这个组件同时支持photo和video,也就是照片和视频都可以用这个组件实现。 安装  npm install --save react-native-ima...

Laravel-mix 中文文档

镜像地址 : https://segmentfault.com/a/1190000015049847原文地址: Laravel Mix Docs   概览   基本示例 larave-mix 是位于webpack顶层的一个简洁的配置层,在 80% 的情况下使用 laravel mix 会使操作变的非常简单。尽管 webpack 非常的强大,但大部分...