NPM基本介绍(一)

一、commonJS规范

在介绍npm的前面,我们先介绍一下commonJS规范。commonJS规范的提出,主要是为了弥补js没有标准的缺陷,已达到Ruby和Java具备开发大型应用的基础能力,如今,commonJS中的大部分规范虽然依旧是草案,但是已经为javascript开发大型应用指明了一条非常棒方向,目前,它依然在成长,目前commonJS规范涵盖了模块、二进制、Buffer、字符集编码、I/O流、进程环境、文件系统、套接字、单元测试、web服务器网关接口、包管理等。而其中的npm则就是commonJS中关于包管理的具体实现。

-摘抄于《深入浅出Nodejs》

二、npm基本介绍

  • Node组织了自身的核心模块,也使得第三方文件模块可以有序的编写和使用。但是在第三方模块中,模块与模块之间仍然是散列在各地的,相互之间不能直接引用。而在模块之外,包和NPM则是将模块连接起来的一种机制。
  • 模块就是:我们可以简单的把它看成一个实现单独功能的文件,模块和文件是一一对应的。
  • 包:包是在模块基础上更深一步的抽象,Node.js的包类似于C/C++的函数库或者java的类库,它讲某个独立的功能封装起来,用于发布、更新、依赖管理的版本控制。开发了npm来解决包的发布和获取需求。 包是由package.json定义的文件或目录
  • npm官方文档:https://docs.npmjs.com/
  • npm解决包的发布和获取需求
  • Node Package(包) Manager(管理器)

三、包结构与包描述文件

1、commonJS规范中包结构

  • package.json: 包描述文件
  • bin:用于存放可执行二进制文件的目录
  • lib:用于存放JavaScript代码的目录
  • doc: 用于存放文档的目录
  • test: 用于存放单元测试用例的代码

2、commonJS 包描述文件

CommonJS为package.json文件定义了如下一些必要字段

  • name:包的名称,必须是唯一的,由小写英文字母、数字和下划线组成,不能包含空格。
  • description:包的简要说明。
  • version: 符合语义化版本识别规范的版本字符串。
    • 主版本号: 当API发生改变,并与之前的版本不兼容的时候
    • 次版本号: 当增加了功能,但是向后兼容的时候
    • 补丁版本号: 当做了向后兼容的缺陷修复的时候
  • keywords:关键字数组,通常用于搜索。
  • maintainers:维护者数组,每个元素要包含name、email(可选)、web(可选)字段。
  • contributors:贡献者数组,格式与maintainers相同。包的作者应该是贡献者数组的第一个元素。
  • bugs:提交bug的地址,可以是网址或者电子邮件地址。
  • licenses:许可证数组,每个元素要包含type(许可证的名称)和url(链接到许可证文本的地址)字段。
  • repositories:仓库托管地址数组。每个元素要包含type(许可证的名称)和url(链接到许可证文本的地址)字段。
  • dependencies:包的依赖,一个关联数组,由包名称和版本组成。

除此之外,还有一些可选字段:

  • homepage: 当前包网站地址
  • os: 操作系统支持列表
  • cpu: cpu架构的支持列表
  • engine: 支持的JavaScript引擎类表,有效的引擎取值为ejs、flusspferd、node、v8等等
  • builtin: 标志当前包是否是内建在底层系统的标准组件
  • directories: 包目录说明
  • implements: 实现规范列表,标志当前包实现了commonJS的那些规范
  • script: 脚本说明对象。npm script 是记录在 package.json 中的 scripts 字段中的一些自定义脚本,使用自定义脚本,用户可以将一些项目中常用的命令行记录在 package.json 不需要每次都要敲一遍。

3、npm 包描述文件

主要多了author、bin、main、devDependencies

  • author: 包作者
  • bin: 一些包作者希望包可以作为命令行工具使用,配置好bin字段后,通过npm install package_name -g命令可以将脚本添加到执行路径中,之后可以在命令行中直接执行。这种称之为全局模式
  • main: 模块引入方法require()在引入包时,会优先检查这个字段,并将其作为包中其余模块入口。如果不存在这个字段,require()方法会查找宝目录下的index.js、index.node、index.json文件作为默认入口
  • devDependencies: 一些模块只有在开发的时候需要依赖,配置这个属性,可以提示包的后续开发者安装依赖包。

四、依赖树概念

  • 物理结构和逻辑结构
    • 逻辑结构:npm ls以树状图的方式列下一个项目下面的所有依赖的 逻辑结构
    • 物理结构:具体文件引用结构,通常有npm等包管理工具决定
  • 问题:如果按照逻辑结构来决定物理结构,就会创建了太深的依赖关系树,导致 Windows 上很长的目录路径问题

五、模块查找方式(深入浅出Nodejs p16)

1、三个步骤

在node中引入一个模块需要经过三个步骤

  • 路径分析
  • 文件定位
  • 编译执行

2、路径分析和文件定位

模块的分类:

  • 核心模块
  • 路径形式的文件模块
  • 自定义模块

通常使用npm i安装的npm包都是自定义模块,在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程、速度相对来说比较慢,所以我们这里就什么理解自定义模块的查找方式中的路径生成规则,为什么你的require(包名)就能够将这个包require进来使用。

模块路径生成规则:

  • 当前目录下的node_modules
  • 父目录下的node_modules
  • 父目录的父目录下node_modules
  • 沿着路径向上逐级递归,直到根目录下的node_modules

可见当前文件目录越深,模块查找会耗时更多,这就是模块自定义加载速度是最慢的原因

六、安装依赖

1、扁平化依赖

2、模块安装过程

npm v2解析包的依赖关系

这个版本下安装依赖使用嵌套安装依赖

优点和弊端

优点:解决了版本单一时存在的不兼容问题,实现多版本兼容 缺点:可能造成相同模块大量冗余

哪么如何做到多版本兼容额前提下减少这种模块冗余问题,于是npm3做了一个改进

npm v3解析包的依赖关系

npm v3会尽量把逻辑上某个层级的模块在物理结构上全部放在项目的第一层级,具体摘抄为以下:

  • 在安装某个二级模块的同时,如果发现第一层级层级还没有相同名称的模块,便把这第二层的模块放在第一层级(参考上满模块路径生成规则)
  • 在安装某个二级模块的时,若发现第一层级有相同的名称,相同的版本,便直接复用那个模块
  • 在安装某个二级模块时,若发现第一层级有相同名称,但是版本却不相同的模块,便只能嵌套在自身的父模块下方

但是npm v3仍然没有把npm v2模块冗余的缺陷优化到极致,可能出现这种情况

npm v3模块去重

实际是使用 npm dedupe去除冗余模块原理就是当A模块下的C V1.0模块被更新到 C V2.0情况下,我们可以使用这条命令把所有C v2.0的二级依赖模块“重定向”到一级目录下的那个C v1.0

3、全局安装和局部安装

按照位置来区分:

  • 全局安装是安装在:/c/Users/用户名/AppData/Roaming/npm/node_modules
  • 局部安装是安装在:当前项目的node_modules

按照使用方式:

  • 全局安装:可以直接在命令行里面使用
  • 局部安装:可以require()引用使用

如何选择安装方式

  • 如果您要在程序中使用的require('whatever'),请使用本地安装,然后将其安装在项目的根目录下。
  • 如果你正在安装你想在你的shell中使用的东西,在命令行或者其他东西上,请全局安装它,这样它的二进制文件最终会放到你的PATH环境变量中。

七、缓存目录

  • npm config get cache:查找缓存包存放地址
  • 模块安装步骤:
    • 发出npm install命令
    • npm 向 registry 查询模块压缩包的网址
  • 下载压缩包,存放在npm-cache(缓存目录)
    • 解压压缩包到当前项目的node_modules目录
  • 运行npm install首先会判断项目文件夹node_modules中有没有对应的模块,没有直接去远程下载,然后保存在缓存中,将缓存中的压缩包解压至对应的项目的node_modules中。(不直接从缓存读取是因为缓存中的包版本可能是旧的,所以要去拉最新的包版本)
  • 优先使用缓存安装:--prefer-offline
  • 优先线上安装: --prefer-online
  • 完全离线:--offline

八、npm缺陷

  • 频繁使用的代码包创建了太深的依赖关系树,导致 Windows 上很长的目录路径问题(虽然v3版本使用扁平化算法进行优化。但是有时候也避免不了)
  • 当被不同的依赖关系需要时,代码包会被复制粘贴多次,比较占存储空间
  • 扁平化依赖树的算法相当复杂
  • 不能保证同一份package.json在不同机器上安装着相同的依赖,可能间接导致错误(不可靠)

九、npx: 包执行器

当升级npm@5.2.0,会安装一个新的包npx

npx 的使用很简单,就是执行 npx command 即可,这里的 command 默认就是 ./node_modules 目录中安装的可执行脚本名。

了解很少,这篇博文讲的比较好npx介绍

十、常用命令

  • npm help <????>: 查看某一命令的帮助
  • npm install <package> :默认使用–save,如果不想保存到package.json中,可以添加--no-save参数;还可以指定–save-dev 或 -g参数
  • npm install --production: npm将不会安装在中列出的模块 devDependencies
  • npm install npm -g: npm更新命令
  • npm init:在此目录生成package.json文件,可以添加-y | --yes 参数则默认所有配置为默认yes
  • npm root -g:查看全局安装地址
  • npm run:列出项目所有脚本命令参数,
  • npm uninstall <package>:卸载依赖包, 默认使用–save参数,即从package.json中移除
  • npm ls [-g] [--depth=0]:查看当前目录或全局的依赖包,可指定层级为0
  • npm outdated:查看当前过期依赖,其中current显示当前安装版本,latest显示依赖包的最新版本,wanted显示我们可以升级到可以不破坏当前代码的版本
  • npm search <string>:查找包含该字符串的依赖包,根据keywords进行查找
  • npm prune:移除当前不在package.json中但是存在node_modules中的依赖
  • npm repo <package>:浏览器端打开项目地址(GitHub)
  • npm home <package> :在浏览器端查看项目(项目主页)
  • npm info <package>: 查看package的package.json
  • npm view <package>: 等同于npm info
  • npm dedupe: 去除冗余模块

十一、学习资料

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java帮帮-微信公众号-技术文章全总结

集群间如何实现session共享【面试+工作】

3.3K8
来自专栏木头编程 - moTzxx

CentOS7 ab压力测试安装与解释

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

2662
来自专栏祥子的故事

python | os包常用命令介绍

3905
来自专栏用户2442861的专栏

socket阻塞与非阻塞,同步与异步I/O模型

作者:huangguisu 原文出处:http://blog.csdn.net/hguisu/article/details/7453390

2231
来自专栏零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(十四):用户密码找回

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

3261
来自专栏塔奇克马敲代码

Windows环境下的RTKPlot_Qt版本编译时遇到的问题和解决方法

1705
来自专栏七夜安全博客

小知识点--crontab

这两周学了很多东西,还把golang语言基本掌握了,收获还是挺多的。在做安全的过程中,有很多需要定时执行的任务,比如抓取主机数量,端口数据等,这都逃不开linu...

752
来自专栏Alice

iOS开发多线程在实际项目中的运用

        同一时间,CPU只能处理一条线程,也就是只有一条线程在工作。所谓多线程并发(同时)执行,

862
来自专栏极客猴

Python定时任务(下)

上篇文章,我们了解到有三种办法能实现定时任务,但是都无法做到循环执行定时任务。因此,需要一个能够担当此重任的库。它就是 APScheduler。

2603
来自专栏用户2442861的专栏

深入讲解GCC和Make的区别(有涉及makefile文件哟!!!)

gcc是编译器 而make不是 make是依赖于Makefile来编译多个源文件的工具 在Makefile里同样是用gcc(或者别的编译器)来编译程序.

1.2K3

扫码关注云+社区

领取腾讯云代金券