Node原理解析之包与NPM

617 阅读4分钟

一、包

1、简介

  Node组织了自身的核心模块,也使得第三方文件模块可以有序地编写和使用。但在第三方模块中,模块与模块之间仍然是散列在各地的,相互之间不能之间引用,因此引入了包的概念,包就是将模块联系起来的一种机制。

QQ截图20220722102752.png   CommonJS的包规范由包结构和包描述文件组成。

2、包结构

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

3、包描述文件

  包描述文件用于表达非代码相关的信息,它是一个JSON文件————package.json,位于包的根目录下,是包的重要组成部分。

package.json定义了如下一些字段

  • name:包名,公布时必须唯一。
  • version:项目版本,通常为major.minor.revision格式,十分重要。

major:大版本号,适用于包出现巨大的革新,或出现大量的重写导致使得程序无法向后兼容时。

minor:小版本号,这指示包有显著的增强,但照顾到了向后兼容性。

revision:修订版本号,一般用于一些功能的完善以及漏洞的修复。

  • main:入口文件,遵循模块机制中的目录分析机制。
  • scripts:可运行的npm命令,使用npm run xxx会新建一个shell脚本,并执行node_modules/.bin下的脚本。
  • private:将该属性设置为true时表明此包为私有包,发布时会报错。
  • dependencies:当前包所需要的依赖的包列表,NPM会通过这个属性自动加载依赖包,格式为 [包名]: [版本号]
  • devDependencies:开发时需要的依赖包列表。

版本号特殊字符:

  • "^":表面尽量使用同一大版本下最新的版本,也就是说除大版本号以外小版本号和修正版本号都可以变。但如果大版本号为0的情况下,则只有修正版本号可以变,因为大版本号为表示该包为非稳定状态,非稳定状态的包允许小版本不向下兼容。
  • "~":表明只能改变最末尾的版本号,如果是!x.y末尾就是y,~x.y.z末尾就是z。
  • ">"、"<"、">="、"<="、"=":接受任何大于、小于、大于等于、小于等于、等于此版本的包。
  • "-":接受一定范围的包。
  • "||":组合集合,如"> 1.2.0 || < 1.6.0"
  • "*":接受任意版本,可以是"1.2.*",也可以直接是"*"
  • author:作者。
  • description:包简介。
  • maintainers:包维护者列表,NPM通过该列表进行权限认证。
  • contributors:贡献者列表,一般在开源项目中使用。
  • bin:命令行指令。
  • bugs:一个可以反馈bug的网站或邮箱。
  • license:许可证列表。
  • keywords:关键词数组,好的关键词有利于用户快速查找到你写的包。
  • respositories:托管源码的位置列表。
  • homepage:当前包的网站地址。
  • engine:支持的JavaScript引擎列表。
  • type:包支持的规范,node13.2.0之后支持,可选值commonjs | module。
  • module:ESM规范下的入口文件。
  • browser:browser环境下的入口文件。

4、发布包

(1) 新建包目录和入口文件

image.png

(2) 编写模块

// index.js
exports.sayHello = () => {
    console.log('Hello npm')
};

(3) 初始化包描述文件

初始化包描述文件的命令是

$ npm init -y

生成package.json文件

image.png

(4) 注册/登录包仓库账号

  • 注册

如果没有npm仓库账号需要先注册

$ npm adduser
Username: (alex)
Email: (alex2022@163.com)

注册成功后会自动登录该账号

  • 登录

如果已经有npm仓库账号则直接登录即可

$ npm login
Username: (alex)
Email: (alex2022@163.com)

(5) 发布

发布包的命令是

$ npm publish .

在这个过程中,NPM会将目录打包为一个存档文件,然后上传到官方源仓库中。 至此,一个自定义的包就发布完成了,我们就可以在别的项目中,通过npm install zhy-package安装它。

5、其他常用命令

(1) 管理包权限

默认情况下,一个包只有创建者拥有权限进行发布。如果需要多人进行发布,可以使用npm owner命令管理包的所有者。

  • 查看包的所有者列表
$ npm owner ls [pkg]
alex <alex2022@163.com>
  • 添加所有者
$ npm owner add <user> [pkg]
  • 查看包的所有者列表
$ npm owner rm <user> [pkg]

(2) 分析包

$ npm ls

这个命令可以为你分析出当前路径下能够通过模块路径找到的所有包,并生成依赖树,如下:

+-- express@4.18.1
| +-- accepts@1.3.8
| | +-- mime-types@2.1.35
| | | `-- mime-db@1.52.0
| | `-- negotiator@0.6.3
| +-- array-flatten@1.1.1
| `-- vary@1.1.2

这个命令常用于确定当前目录下是否能通过require()引入想要的包。

(3) 链接

$ npm link [pkg]

这个命令可以将本地的包链接到项目中,通常用于多个包之间的联调。

例如本地有两个包jack和rose

// jack/index.js
console.log('my name is jack');
// rose/index.js
console.log('my name is rose');
exports.sayLove = () => {
    console.log('You jump, I jump!');
}

如果想要在jack包中调用rose包中的sayLove()方法,第一种方式就是先将rose发布到NPM仓库中,再在jack包中通过npm install rose命令安装,最后执行require('rose').sayLove()。

但是在开发过程中,我们不想每次调试都要发布一个新的包到NPM仓库上,这时我们就可以在jack包中直接执行npm link ../rose/命令链接rose包到node_modules目录下。

这样做的好处是,修改了rose包的内容也不必重新link,jack/node_modules中的rose包随时都是最新的代码,开发过程及其舒畅。

6、bin

package.json的bin字段是命令名到执行文件的映射。

// zhy-package/package.json
{
    "bin": {
        "fly": "./bin/fly.js" // 命令名为fly,执行文件为当前包中bin目录下的fly.js
     }
}
#!/usr/bin/env node
console.log("I can fly");

#!/usr/bin/env node 的作用是,告诉shell去环境变量中寻找node来执行该文件。

  • 局部安装包 时,如果该包的package.json有bin字段,就会在node_modules文件夹下面的.bin目录中生成对应的可执行文件,该可执行文件实际上是一个替身文件,真正执行的是package.json中bin配置对应的那个文件。

image.png

在package.json中script字段配置命令

// other-package/package.json
{
    "scripts": {
        "test": "fly"
     }
}

执行 npm run test

$ npm run test

> TDD@1.0.0 test C:\Users\123\Desktop\other-package
> fly

I can fly

或者直接执行 .\node_modules.bin\fly

$ .\node_modules\.bin\fly
I can fly
  • 全局安装包 时,npm会从fly.js文件创建一个到/usr/local/bin/fly的符号链接(这使你可以直接在命令行执行fly)。
$ npm install -g zhy-package
C:\Program Files\nodejs\fly -> C:\Program Files\nodejs\node_modules\zhy-package\bin\fly.js
+ zhy-package@1.0.0
added 1 package in 0.188s

$ fly
I can fly
  • npm link 的另一个妙用

当我们在开发包时,想测试一下我们写的bin命令在全局安装的情况下的执行效果,我们不必先发布然后再全局安装,只需要在当前包目录下执行 npm link,同样可以创建符号链接,然后就可以直接在命令行执行。

$ npm link 
up to date in 1.474s
found 0 vulnerabilities

C:\Program Files\nodejs\fly -> C:\Program Files\nodejs\node_modules\zhy-package\bin\fly.js
C:\Program Files\nodejs\node_modules\zhy-package -> C:\Users\123\Desktop\node\zhy-package

$ fly
I can fly