跳到主要内容

package 和 package.json

不同于 module,package 往往是大量 module 的集成

它能作为 Package 存在,最为显著的特征是 package.json 文件

(不一定要发包到 npm 官方上,本地也可以使用)

在 npm 中,package 是一个用 package.json 来描述的文件。 其中 package.json 中定义了包的名称(name)、版本(version)等信息,其他文件往往为源代码及相关的说明文档。当这些信息通过 npm publish 上传后,将产生一个 gzip 的压缩包,通常称为 tar 包(tarball)

当我们装包时在装什么​

这里以 react@18.0.0 为例。在执行 npm install react@18.0.0 时,本质上下载的是 react-18.0.0.tgz 这个压缩文件。文件下载解压后目录结构如下。

包含了源代码和说明性文档(开源 LICENSE,readme)之类的


$ tree react-18.0.0
react-18.0.0
├── LICENSE
├── README.md
├── cjs
├── index.js
├── jsx-dev-runtime.js
├── jsx-runtime.js
├── package.json
├── react.shared-subset.js
└── umd

2 directories, 20 files

package.json​

理论上,当一个 package.json 中包含合法的 name 和 version 字段时, npm CLI 和 npm registry 就认为当前执行环境是一个合法的 npm package。比如我们可以通过新建一个文件夹,仅仅在 package.json 中写入 name 和 version 字段,执行 npm publish,npm 并不会阻止发布。

// package.json
{"name": "@bnpm-test/example","version": "1.0.0"
}

显然,我们非常不推荐通过上述方式发布你的 npm package。具体原因我们在后面阐述,我们先将核心的 package.json 字段来描述下。当我们在命令行中执行 npm init -y 时, npm 默认会在当前目录生成一份 package.json 文件,包含了以下字段

{
"name": "@bnpm-test/example",
"version": "1.0.0","main": "index.js",
"scripts":
{
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}

package 必要字段​

name​

表示当前 npm package 的包名,包名不宜过长,必须 <=214 个字符,包含 scope 的长度

scripts​

脚本文件,通常为 npm run 时使用,非必要情况下,在 npm package 中合理使用依赖项,避免 postinstall/install/prepare 等 hook 脚本

keywords​

关键词,有利于包搜索的 SEO,助于你更好的搜索到 npm package

author​

包的作者,标注包的出处,当包产生问题时可以便于联系

license​

包的许可证,表示包的开源许可,通常来讲,开源软件大部分为 MIT,更多相关的 license 可以自行查找 wiki,这里不展开解释。

description​

描述信息,有利于包搜索的 SEO,助于你更好的搜索到 npm package

package 重要字段​

repository​

表示源代码出处,方便其他使用者研究和学习,也利于 npm 分析当前 package 的维护情况

homepage​

如果你的 package 有对应的预览页面的话,比如 antd 的组件库文档,可以填写该字段

publishConfig​

发布配置,比如 registry,你可以在 publishConfig 中设置,则不需要每次拼写 --registry 参数,一切在 npm config 中的配置,都可以在 publishConfig 中配置

config​

npm 自定义配置参数,例如配置端口号 config.port: 8080,该 config 具有一定的特殊性,即可以在 npm scripts 中获取其值,我常常用他将前置的一些运行命令组装,使得 script 很“干净”。比如你定义了 config.doas = "doas -p p.s.m",可以在 scripts.dev 命令中如下书写 "$npm_package_config_doas node index.js",而不是每次都手工 doas -p p.s.m npm run dev 或者在 dev 命令中拼写一堆前缀操作

什么是 scope​

Scope 在实际应用上,往往表示一个组织所管理的 pacakge,例如 @babel,表示 babel 开源组织下的 package。 从用户角度来讲,如果你用过 @babel 的其他 package,再次使用一个新的以 @babel scope 为前缀命名的包时,往往会觉得这个 package 比较可靠,且维护性高。

打包成两种格式​

打包成两种格式就是为了让自己的库有更好的兼容性,使用者可以根据情况来选择使用 esm 还是 cjs。那么如何配置发包配置呢? 在 package.json 文件中,"exports"、"module" 和 "main" 字段有着不同的作用。

"exports" 字段是在 Node.js 版本 12 及以上引入的,它用于指定模块的导出方式。导入模块时应该使用 cjs 还是 esm 取决于使用时的导入语法。 "module" 字段是在 Node.js 版本 8 及以上引入的,它用于指定 ES 模块的入口文件路径。在使用支持 ES 模块的环境中,例如现代浏览器或 Node.js 版本 13 及以上,这个字段可以用来指定默认的模块入口。 "main" 字段是 Node.js 中常用的字段,它用于指定 CommonJS 模块的入口文件路径。在使用 CommonJS 模块的环境中,例如 Node.js 版本 12 及以下,这个字段可以用来指定默认的模块入口。

export 优先级最高,其次是 Module 和 main

package.json
{
"main": "lib/cjs/index.js",
"module": "lib/esm/index.mjs"
"typings": "lib/cjs/types/index.d.ts",
"exports": {
".": {
// 使用import语句,则types的入口在 /lib/esm/types/index.d.mts
// default 为项目入口文件
"import": {
"types": "./lib/esm/types/index.d.mts",
"default": "./lib/esm/index.mjs"
},
"require": {
"types": "./lib/cjs/types/index.d.ts",
"default": "./lib/cjs/index.js"
}
}
}
}


如果只有 umd,"main"字段可以配 umd,umd 是 cjs 的超集

  "main": "dist/axios.umd.js",

关于包 size 的概念​

install size​

包安装时包括各个依赖的 size

对 serverless 应用有重要用处

package size​

包括包中 md 和 example 文件等杂七杂八的 size

bundle size​

实际被引用后,打包成 bundle 后的 size

package 的可靠性​

PQM 利他

试想一下,如果在某些场景需要借助第三方 SDK 来实现,那你应该通过什么方式来快速验证某个 呢?

  • github star 数、npm 下载量...
  • 源代码质量、文档、单元测试...
  • Github 更新的频率、维护者的个数、issue/commit 的个数... npm 搜索借助 P(popularity)、Q(quality)、M(maintainance) 三个指标分别对应以上三种情况进行了量化。往往 Q、M 的指标高时,P 不会太差。当然也有个例,比如 lodash 这种老牌库,不再需要 M 了,但他的 P、Q 仍然很高。 这些信息与上文中描述的 package.json 息息相关,可以说,一份规范的 package.json ,就是 npm package “SEO” 的最佳手段。

引用​

原文作者:z__r 转自链接:https://learnku.com/articles/16798/quick-view-of-npm-and-yarn-global-installed-packages 版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请保留以上作者信息和原文链接。