package.json 是 node 项目必备的一个文件,通常用来描述项目的一些元数据,包含项目名称,版本,描述,依赖等等。一个最简单的 package.json 内容通常长这样。

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "A description of my project",
  "scripts": {
    "start": "node index.js",
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "mocha": "^9.1.2"
  }
}

在开发业务项目时可能关注上面几个字段已经足够了,但是在开发 npm 包,则需要了解更多的字段,能辅助我们来实现 npm 包必备的功能。

main

指定包的默认入口,比如用户 require() 引入包,就会加载 main 指定的文件。通常用于 commonjs 的场景

{
  "main": "lib/index.js"
}

module

跟 main 一样指定包的入口,但是是 es 模块的入口

{
  "module": "esm/index.js"
}

通常情况下建议两个字段都声明,这样在 commonjs 和 esm 环境下都可以使用。

bin

bin 属性来指定包的可执行脚本,这样通过 npm i -g 安装包时,会把可执行脚本链接到全局的 path 环境变量里,例如平时用的 cra, vue/cli 命令,都是通过 bin 来实现。下面是 @vue/cli 的 package.json bin声明。

{
  "bin": {
    "vue": "bin/vue.js"
  }
}

exports

exports 定义包的默认导出或者命令导出,在 node 12.17.0 版本上,可以用来替代 main 字段

{
  "exports": {
    ".": "./dist/index.js",
    "./foo":"./dist/foo/index.js"
  }
}

这样可以通过不同方式来引入,比如包名是 @kelen/utils

import utils from '@kelen/utils'
import foo from '@kelen/utils/foo'

typesVersions

上面通过 './foo' 导出模块,但是如果在 ts 项目里,可能会报 Could not find a declaration file for module 'xxx'. 的警告。这时候 typesVersions 就可以派上用场。

{
  "typesVersions": {
    "*": {
      "./foo": "./dist/foo.d.ts"
    }
  }
}

typesVersions 会根据导入的模块路径,去找对应的声明文件。例如导入 @kelen/utils/foo ,会去找 ./dist/foo.d.ts 的声明文件。

types

types 定义包的入口声明文件,通常用于 ts 项目,告诉 ts 编译器如何导入包的类型。

{
  "types": "dist/index.d.ts"
}

files

files 定义包发布的文件,通常用于忽略一些不需要发布的文件,比如测试文件,文档,源文件等。

{
  "files": [
    "dist" // 只发布 dist 目录
  ]
}

peerDependencies

peerDependencies 定义当前包在运行时需要宿主环境提供的依赖,这些依赖不会通过当前包安装,而是期望宿主环境安装这些依赖。

{
  "peerDependencies": {
    "react": "^17.0.0"
  }
}

sideEffects

sideEffects 定义包是否有副作用,比如 css,png 文件,如果没有副作用,可以设置为 false,这样打包工具可以严格进行 tree-shaking。

{
  "sideEffects": false,
}

sideEffects 也可以定义成数组,表示哪些文件有副作用,在打包的时候就不会进行 tree-shaking 处理相关文件。

{
  "sideEffects": [
    "aaa.css",
    "bbb.png"
  ]
}

以上就是开发 npm 包需要了解的 package.json 字段,这些字段可以帮助我们更好的开发 npm 包。