package.json stuff

package.json 字段

一个前端模块的身份证。

查看官网 (opens in a new tab)发现具体字段的含义/作用:

exports

官方文档说明 (opens in a new tab)(node 12+)

对于一个 npm 包来说,是比较推荐用 exports 指明入口文件

相比与 main 更加现代,能够更加清晰的定义更多的入口文件,同时能屏蔽除了指定入口外的路径访问。

{
  "exports": {
    ".": "./index.js",
    "./submodule.js": "./src/submodule.js"
  }
}

如果当前目录就是主入口,下面可以改写成

{
  "exports": {
    ".": "./index.js"
  }
}
// 可以简写
{
  "exports": "./index.js"
}

有 esm 和 cjs 两种的情况下分条件导出 (opens in a new tab)(build 了两份,或者 wrapper 出一份 mjs),可以通过 require and import

  "exports": {
    ".": {
      "import": "./dist/esm/index.js",
      "require": "./dist/cjs/index.js"
    },
  },

对于 TS package 来说 (opens in a new tab)

  • 首先也是可以用的
  • 如果 main 指向的是 ./lib/index.js TS 则会去找 ./lib/index.d.ts,同时也可以用 "types" 字段去指明
  • 对于 "import""require" 来说,也可以指定不同的类型路径
// package.json
{
  "name": "my-package",
  "type": "module",
  "exports": {
    ".": {
      // Entry-point for `import "my-package"` in ESM
      "import": {
        // Where TypeScript will look.
        "types": "./types/esm/index.d.ts",
        // Where Node.js will look.
        "default": "./esm/index.js"
      },
      // Entry-point for `require("my-package") in CJS
      "require": {
        // Where TypeScript will look.
        "types": "./types/commonjs/index.d.cts",
        // Where Node.js will look.
        "default": "./commonjs/index.cjs"
      }
    }
  },
  // Fall-back for older versions of TypeScript
  "types": "./types/index.d.ts",
  // CJS fall-back for older versions of Node.js
  "main": "./commonjs/index.cjs"
}

来自 TS 4.7 log (opens in a new tab)

type

nodejs (opens in a new tab) 中使用 esm 作为 js 模块的时候(使用 import/export 语法)

此时 type 字段需要指定为 "module",否则就会认为 .js/.ts 文件默认是 CommonJS,需要用 require

但是如果不考虑用 type 这个字段,那就直接使用后缀 .mjs/.mts 表示 ES Module,用 .cjs 表示 CommonJS module

同样在 js modulewebpack 中提到过

name

和 version 一起组合成了这个包的唯一表示

一些规则:

  • 不能超过 214 个字符(包含 scope 名,一时想不起 scope 中文如何翻译)
  • . or _开头
  • 新的包不能有大写(?)
  • 这个名字会被用在 url 里、命令行里、文件名,所以不要有 url 中的奇怪字符(:.等)

关于作用域 scope

我们会看到 Vue 都是用@vue/xxx开始的

TODO

version

语义化版本命名嘛,看这个https://semver.org/ (opens in a new tab)

npm install semver

https://docs.npmjs.com/misc/semver官网讲了如何比较版本的方法 (opens in a new tab)

files

类型:数组

  • 当这个包作为其他包的 dependencies 的时候只会安装 files 中的这些文件。

  • 字符串的格式和.gitignore一样,但是是 include 这些文件,支持 glob 格式

  • 如果没有这个字段,默认的是["*"]

  • 同时可以提供.npmignore,作用和.gitignore一样,如果没有.npmignore,就会用.gitignore

  • Certain files are always included, regardless of settings:

    • package.json
    • README
    • CHANGES / CHANGELOG / HISTORY
    • LICENSE / LICENCE
    • NOTICE
    • The file in the “main” field
    • README, CHANGES, LICENSE & NOTICE可以有任意的后缀
  • Conversely, some files are always ignored:

    • .git
    • CVS
    • .svn
    • .hg
    • .lock-wscript
    • .wafpickle-N
    • .*.swp
    • .DS_Store
    • ._*
    • npm-debug.log
    • .npmrc
    • node_modules
    • config.gypi
    • *.orig
    • package-lock.json (use shrinkwrap instead)

main

导入该模块时的入口文件

const x = require('xxx')

bin

让你的包成为命令行指令的关键字段!

{
  "bin": {
    "cydir": "./index.js"
  }
}

npm install 之后就做了一个软连接(全局,或者本地在 ./node_modules/.bin/)index.js连接到/usr/local/bin/cydir.

记得在 bin 指向的文件开头加上#!/usr/bin/env node,不然就无法执行了!

script

https://docs.npmjs.com/misc/scripts (opens in a new tab)

npm run <script>

engines

{
  "engines": {
    "node": ">=0.10.3 <0.12"
  }
}

private

这个包 publish 的时候会被 npm 阻止!

scope

  • 用户/组织的作用域名,形如@myorg/package

  • 只有自己可以在 scope 下 add package,所以不用担心别人会用你的 scope

  • 当然,scoped 的包可以依赖 unscoped 包,反之亦然

  • 安装 scoped 包的时候会在node_modules目录下的@myorg目录下安装对应的子包

  • 引入的时候也需要带上域名require('@myorg/mypackage')

  • 可以发布在任何的 registry

其他的到真正用到再说吧。。。