初始化创建package.json文件

一般使用 npm init yarn init pnpm init 任一命令就可以初始化一个package.json文件,又或者你可以自己手动编写符合规范的文件并命名为package.json。此外,使用一些脚手架创建项目后也是能生成package.json文件,例如以下是使用 vite 的脚手架 create-vite 命令行 pnpm create vite 创建项目的初始package.json如下:

// package.json
  "name": "vite-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview"
  "dependencies": {
    "vue": "^3.2.37"
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.1.0",
    "typescript": "^4.6.4",
    "vite": "^3.1.0",
    "vue-tsc": "^0.40.4"

由上,我们可以看到,package.json文件里包含了项目的名称,版本号,描述,执行脚本等,但其实package.json文件包含的信息远远不止这些,那接下来就一起看看吧。

文档描述 Description 本文档是您需要了解的全部关于package.json文件引用情况的信息。文档中所描述的很多概念都受到config设置里的描述的影响。

name(名称)

如果你计划发包,那么最重要的就是在package.json文件里必须要有name和version这两个字段,name和version这两个字段结合在一起将会被构成包的唯一标识符。包更改时也需要同步修改version字段。如果你不计划发包,那么name和version这两个字段都是可选的。

name字段的意思是:“你写的这个包的简述”

name规则

以下是name字段的一些规则:

  • 名称必须少于或等于214个字符,这包括用于描述scope package(域级包)的scope(@与/之间的字符)
  • tips: 例,@username/project-name 每一个npm用户有它自己的scope,scope package包又叫作用域包或者域级包或域包,在这个例子中的解释就是,project-name这个包是在username命名空间下的project-name包,这里的scope就是username,而package是指project-name@username/project-name这个整体就称为scope package(域级包)

  • scope package的名称不可以以点或下划线开头。没有scope是不允许的。
  • 官网上说可以,其实实际上是不可以的(我测试过),以下是官网原文,大家可以比较 name规则中写的 "The names of scoped packages can begin with a dot or an underscore. This is not permitted without a scope",

    scope描述中写的"A scope follows the usual rules for package names (URL-safe characters, no leading dots or underscores)"

    以下写法 "name": ".viteproject","name": "_viteproject","name":".@gxn/viteproject","name": "@.gxn/viteproject", 都会导致警告:The name of the package. String does not match the pattern of "^(?:@[a-z0-9-*~][a-z0-9-*._~]*/)?[a-z0-9-~][a-z0-9-._~]*$".

  • 新包的name字段的值是不能含有大写字母的
  • 这个name字段值 最终成为URL的一部分、命令行上的参数和文件夹名称(文件夹名称可重新命名)。因此,name字段值里不能包含任何非URL安全的字符
  • 不要与核心的node 模块使用相同的名字
  • 不要在name字段的值中添加“js”或“node”。假设name字段的值是js,因为您正在编写这个包的文件,您可以使用“engines”字段来指定引擎。(见下文)
  • name这个字段可能会作为参数传递给require(),因此它应该是简短的,但也可以是合理的描述
  • 一个包的名称可以选择性地使用scope作为前缀,例如@myorg/mypackage。有关更多详细信息,请参见scope

    version(版本)

    如果你计划发包,那么最重要的就是在package.json文件里必须要有name和version这两个字段,name和version这两个字段结合在一起将会被构成包的唯一标识符。包更改时也需要同步修改version字段。如果你不计划发包,那么name和version这两个字段都是可选的。

    Version必须由node-semver解析, node-semver(也叫作semver)已经作为npm的依赖项与npm捆绑在一起。(使用命令行 npm install semver安装 semver ,自行使用semver)

    description (描述)

    在description字段值中添加描述,description 字段值必须是string字符串类型,这有利于让大家发现您的包,因为它会在 npm search 结果列表中列出。

    您可以进入 https://www.npmjs.com/里搜索 pnpm,然后拿这个搜索结果中出现的描述与 pnpm 包里的 description 值进行对比。

    pnpm的description字段的值和keywords值中都包含有:package manager,当我们直接输入命令行 npm search package manager查找,会发现搜索结果列表项里展示以下属性 DESCRIPTION ,AUTHOR, DATE, VERSION ,KEYWORDS。 所以根据description字段能搜索出我们的包。

    keywords (关键字)

    在 keywords 字段值中添加描述,keywords 字段值必须是 Array <string> 字符串数组,这有利于让大家发现您的包,因为它会在 npm search 结果列表中列出。

    格式示例如下: (pnpm包里的package.json中的keywords字段值示例)

        // package.json (for pnpm)
        "keywords": [
        "pnpm7",
        "dependency manager",
        "install",
        "installer",
        "uninstall",
        "remove",
        "link",
        "prune",
        "shrinkwrap",
        "lockfile",
        "fast",
        "rapid",
        "efficient",
        "package.json",
        "packages",
        "dependencies",
        "symlinks",
        "hardlinks",
        "modules",
        "npm",
        "package manager",
        "monorepo",
        "multi-package",
        "workspace:*"
    

    例如 pnpm 的 keywords 字段值中有 lockfile, 输入命令行 npm search lockfile,结果如下(能搜索出pnpm):

    homepage

    根据 homepage 字段值去到项目主页

    例如 pnpm 里package.json中homepage字段如下

    // package.json (for pnpm)
    "homepage": "https://pnpm.io",
    

    我们根据homepage值(此处为 pnpm.io )可以直接去到 pnpm 官网

    项目问题追踪(跟进)的url和/或者接收问题报告的email邮箱。当使用者在使用你的程序包时遇到问题或程序bug时,bugs字段值对于这些情况来说是非常有用的。

    bugs字段值示例如下:

    "url" : "https://github.com/owner/project/issues", "email" : "project@hostname.com"

    例如 pnpm 里package.json中bugs字段如下 :

      "bugs": {
        "url": "https://github.com/pnpm/pnpm/issues"
    

    这样我们在遇到pnpm包相关的问题或程序bug时,就可以到 bugs里的url ( github.com/pnpm/pnpm/i… ) 留言或寻找帮助。

    bugs字段值可以是一个或两个值。如果只想提供一个url,可以将“bug”的值指定为简单字符串而不是对象。 例如,以上的pnpm的bugs字段值可以改为如下所示:

    // 原值
    "bugs": { "url": "https://github.com/pnpm/pnpm/issues" },
    
    // 修改后的值
    "bugs": "https://github.com/pnpm/pnpm/issues", 
    // 或者
    "bug": "https://github.com/pnpm/pnpm/issues",
    

    如果提供了一个url,它将由 npm bugs 命令使用。 例如,想去到 pnpm 的bug issue,可以输入npm bugs pnpm ,电脑就会使用默认浏览器自动打开pnpm 的 issue 地址:Issues · pnpm/pnpm · GitHub: github.com/pnpm/pnpm/i…

    license

    你应该给软件包指定一个许可证,这样使用者才能知道这个软件包是怎么才能被准许使用的,以及你给软件包加了哪些限制条件。

    许可证添加SPDX许可证标识符

    如果你的软件包使用的是常见许可证,如 BSD-2-Clause 或 MIT ,那么请为你使用的许可证添加当前SPDX许可证标识符,如下所示:

    "license" : "BSD-3-Clause"

    您可以查看 SPDX许可证ID的完整列表 。理想情况下,您应该选择一个OSI批准的。

    部分常用的SPDX许可证标识符

    以下列出小部分常用的SPDX许可证标识符

    全名SPDX标识符OSI 批准
    GNU General Public License v2.0 only(不推荐)GPL-2.0Y
    GNU General Public License v2.0 or later(不推荐)GPL-2.0+Y
    GNU Lesser General Public License v2.1 or laterLGPL-2.1-or-laterY
    BSD 2-Clause "Simplified" LicenseBSD-2-ClauseY
    BSD 3-Clause "New" or "Revised" LicenseBSD-3-ClauseY
    MIT LicenseMITY
    Mozilla Public License 1.1MPL-1.1Y
    Mozilla Public License 2.0MPL-2.1Y
    Apache License 1.1Apache-1.1Y
    Apache License 2.0Apache-2.0Y
    ISC LicenseISCY

    GPL、 BSD、 MIT、 Mozilla、 Apache、 LGPL 流行许可证最大的区别

    归纳起来,开源许可证最流行的就是以下六种:

    GPLBSDMITMozillaApache

    使用一张图来快速了解他们之间最大的区别(图来源于:阮一峰:如何选择开源许可证?

    pnpm 使用MIT许可证

    例如, pnpm的许可证就是使用 MIT、在pnpm包里你可以找到如下(MIT 许可说明文件):

    // package.json (for pnpm)
    "license": "MIT",
    

    多个许可证

    如果您的软件包是在多个通用许可证下许可的,请使用SPDX许可证表达式语法2.0版本的字符串,例如:

    "license" : "(ISC OR GPL-3.0)"

    你也可以去阅读 《SPDX说明文档》 了解更多细节,而如果你想了解ANDORWITH 或 +这些符号的含义,你可以到 《附录D: SPDX许可证表述》 了解更多信息

    自定义许可证

    如果您使用的许可证没有指定 SPDX 标识符,或者您使用的是自定义许可证,那么请使用如下字符串值:

    "license" : "SEE LICENSE IN <filename>"

    然后在包的顶层包含一个名为<filename>的文件。

    一些旧软件包的 license 字段值是一个对象或者 把license字段名改为licenses,然后licenses字段值是一个对象数组

    // Not valid metadata
      "license" : {
        "type" : "ISC",
        "url" : "https://opensource.org/licenses/ISC"
    // Not valid metadata
      "licenses" : [
          "type": "MIT",
          "url": "https://www.opensource.org/licenses/mit-license.php"
          "type": "Apache-2.0",
          "url": "https://opensource.org/licenses/apache2.0.php"
    

    这些样式现在已弃用。请使用 SPDX表达式 ( license: SPDX标识符 ) ,如下所示:

    "license": "ISC" "license": "(MIT OR Apache-2.0)"

    以上的"ISC"就是 全名为ISC License的SPDX标识符ISC

    而 "MIT OR Apache-2.0" 指的是 MIT LicenseApache License 2.0

    《附录D: SPDX许可证表述》 了解更多关于 许可证表述连接词(操作符)的信息吧。

    UNLICENSED(未经许可的)

    最后,如果您不希望根据任何条款授予他人使用私人或未发布软件包的权利,你可以把license字段值设为UNLICENSED(未经许可的)

    "license": "UNLICENSED"

    你还可以考虑设置“private”:true 以防止意外发布。private我们在后续会提及。

    人员字段: author, contributors

    “author” 是指一个人。“contributors” 是指一组人。“author”字段 是一个具有 “name” 字段和可选的 “url” 和 “email” 的对象,如下所示:

    "author": {
      "name" : "Barney Rubble",
      "email" : "b@rubble.com",
      "url" : "http://barnyrubble.tumblr.com/"
    

    或者您可以将 "author" 字段全部缩短为单个字符串,npm将为您解析它:

    "author": "Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"

    "email"和"url"这两个都是可选字段。 npm 甚至还设置一个顶级字段"maintainers",用以描述你的npm包的用户信息。

    funding (基金)

    您可以给 "funding" 指定一个对象,该对象包含一个URL,该URL提供有关帮助开发软件包的方法的最新信息,或者给 "funding" 指定一个字符串URL或者数组(包含对象或字符串)。例如:

    // 对象 "funding": { "type" : "individual", "url" : "http://example.com/donate" "funding": { "type" : "patreon", "url" : "https://www.patreon.com/my-account" // 字符串 "funding": "http://example.com/donate", // 数组 "funding": [ "type" : "individual", "url" : "http://example.com/donate" "http://example.com/donateAlso", "type" : "patreon", "url" : "https://www.patreon.com/my-account"

    "funding"它的作用是让维护 npm 的开发人员(为Node.js 创建包)声明元数据,为有意愿的捐赠者指明捐赠平台,包使用者可以使用 npm fund 的子命令列出其项目所有依赖项的直接和间接的 funding URL。当提供项目名称时,也可以使用快捷方式访问每个 funding URL,例如:npm fund <projectname>(当有多个url时,将访问第一个url),而使用该命令访问的时候,该命令会使用用户的默认浏览器打开指定的捐赠服务链接。

    例如:以下是使用 npm fund 子命令查看 core-js 的捐赠网站(core-js开发资金支持网站

    npm fund core-js
    

    files (文件)

    "files" 是一个可选的字段,它的值是一组文件通配符。它可以用来描述 当你的包被使用者作为依赖安装时,你的包里所包含的那些文件或文件夹。

    例如,pinia作为项目的依赖包时,pinia包里的package.json文件的"files"字段值是

    // package.json (for pinia)
    "files": [
        "dist/*.js",
        "dist/*.mjs",
        "dist/*.cjs",
        "dist/pinia.d.ts",
        "index.js",
        "index.cjs",
        "LICENSE",
        "README.md"
    

    那么,作为依赖包的pinia的包文件里就必须包含上述其package.json文件的"files"字段值所描述的文件。

    文件通配符(files字段的值)遵循与 .gitignore类似的语法,了解 .gitignore语法。但不同的是,files字段的值也可以是:文件、目录或者glob通配符(例如***/*等,你可以通过 阮一峰:命令行通配符教程来了解 globbing patterns),这样的话,当你的包执行打包时,files字段值里描述的文件(或文件夹)就会被包含(引入)到 tarball中(简单来说就是files字段值里的文件或文件夹是会打包到tar 包里的)。

    忽略files字段则表示默认值 为 ["*"],意思就是,默认包含所有文件。

    有些特殊文件和目录也会被包括或排除,而不管它们是否存在于文件数组(files字段值)中(请参见下文)。你还可以在项目(包)的根目录或者子目录中提供一个.npmignore文件,这样就可以把你不想打包的文件排除在外。

    在包的根目录下的.npmignore文件,它不会覆盖package.json文件里的“files” 字段,但在子目录中的.npmignore文件则会覆盖。.npmignore文件和 .gitignore文件有一样的效果。如果项目(包)存在.gitignore文件没有 .npmignore 文件,则将使用 .gitignore 文件的内容。

    不能通过 .npmignore.gitignore 排除“package.json#Files”字段中所包含的文件。

    不管设置如何,始终包括以下这些文件:

  • package.json
  • README (包自述文件)
  • LICENSE / LICENCE (许可)
  • package.json中 "main" 字段值所描述的文件
  • README(自述文件)和 LICENSE(许可证)可以有任何案例和扩展。 例如:pinia作为项目的依赖包时,pinia包里的文件也是必须要包含上述提及的文件

    相反,有些文件总是会被忽略:

  • .lock-wscript
  • .wafpickle-N
  • .*.swp
  • .DS_Store
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • *.orig
  • package-lock.json (如果你想发布的话,请使用npm-shrinkwrap.json)
  • main (入口)

    "main" 字段值是模块ID,它也是项目的主要入口点,习惯性称之为"项目入口文件" 也就是说,如果你的包名为foo,并且用户安装了它,然后用户确实执行了 require("foo"),那么就会返回你的主模块所导出的对象。

    "main" 字段值这应该是相对于包文件夹根目录的模块。

    对于大多数模块来说,拥有一个主脚本(main script)是非常有意义的,而其他脚本的通常来说意义不大。 如果未设置 main字段,则 "main" 字段值默认为位于包(项目)的根文件夹中的 index.js

    browser (浏览器)

    如果你的模块是用在客户端(CS)的,那么请使用 "browser" 字段替代 "main" 字段。 这有助于提示用户 包可能依赖于浏览器中自带的模块而node.js模块中不可用的模块。(例如 window)

    bin (启动脚本)

    很多包都有一个或者多个可执行文件,它们期望被添加到 PATH 环境变量中,npm使这变得非常简单(事实上,npm使用这个特性来安装“npm”可执行文件。)

    要使用此功能,请在package.json文件中中提供 "bin" 字段,"bin" 字段值是命令名到本地文件名的映射,当全局安装一个包时,"bin" 字段值里的文件将链接到全局存储箱所在的位置,以便可以按"bin" 字段值里的名称运行。

    初始化的时候npm会将他链接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)

    例如,myapp包中package.json文件有以下内容:

    "bin": { "myapp": "./cli.js"

    所以,当你 install myapp(安装myapp包)后,会创建一个从 cli.js脚本的软链接(符号链接)到 /usr/local/bin/myapp

    例如,vite中的package.json文件有以下内容:

      "bin": {
        "vite": "bin/vite.js"
    

    当使用 npm install -g vitenpm install -g vite 全局安装 "vite" 后,在npm全局安装包位置,(我电脑是win10,且修改过npm全局安装包的位置到 D:\nvm\node_global, 你可以使用 npm prefix -g查看你的npm全局安装包的安装位置),你会看到,vitevite.cmd文件内容里也描述了之后运行的是vite全局包里的vite.js (\node_modules\vite\bin\vite.js)。初始化的时候npm会将 vite.js 文件链接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)

    如果您只要一个可执行文件,并且 “bin” 字段值与包的名称(包的name属性值)一样,那么你可以把 “bin” 字段值 设置为字符串类型。例如:

    "name": "my-program", "version": "1.2.5", "bin": "./path/to/program"

    可以写成下面这样:

    "name": "my-program", "version": "1.2.5", "bin": { "my-program": "./path/to/program"

    拿示例来演示:

    vite包的可执行文件只要一个,bin值中为这个可执行文件命名为 “vite”,而这个名称与包名“vite”,那么此时,"bin"字段可以这样设置:

    // package.json (for vite)
    "name": "vite",
    // ......
    "bin": "bin/vite.js"
    

    请确保bin中引用的文件以 #!/usr/bin/env node, 否则 bin 脚本将不会作为 node 可执行文件来启动, 例如, “vite”的bin文件“vite.js”, “vite.js”文件就是以#!/usr/bin/env node作为文件内容的开头。

    #!/usr/bin/env node
    import { performance } from 'node:perf_hooks'
    if (!import.meta.url.includes('node_modules')) {
      try {
        // only available as dev dependency
        await import('source-map-support').then((r) => r.default.install())
      } catch (e) {}
    global.__vite_start_time = performance.now()
    // ......
    

    请注意,您还可以设置可执行文件使用 directories.bin.

    查看 folders 以了解更多关于可执行文件 Executables的信息。

    指定要放置的单个文件或文件名数组以供man程序使用。

    如果只提供一个单一的文件,那么它初始化后就是man <pkgname>的结果,而不管实际的文件名是什么,例如:

    "name": "foo", "version": "1.2.3", "description": "A packaged foo fooer for fooing foos", "main": "foo.js", "man": "./man/doc.1"

    这样使用man foo命令就可以用到./man/doc.1文件了 ,

    如果文件名不是以包名开头,那么它会被冠以前缀。所以,如下代码:

    "name": "foo", "version": "1.2.3", "description": "A packaged foo fooer for fooing foos", "main": "foo.js", "man": [ "./man/foo.1", "./man/bar.1"

    会为man fooman foo-bar创建文件。

    Man文件必须以数值结尾,如果文件被压缩,还可以选择以 .gz 后缀结尾。该数值型的man文件表示将文件安装到哪个man 部分中。

    如下代码:

    { "name" : "foo"
    , "version" : "1.2.3"
    , "description" : "A packaged foo fooer for fooing foos"
    , "main" : "foo.js"
    , "man" : [ "./man/foo.1", "./man/foo.2" ]
    

    将会为man fooman 2 foo命令创建入口。

    directories (目录)

    CommonJS Packages规范详细介绍了几种使用目录对象指示包结构的方法,在npm's package.json里,你会看到 "directories"字段里包含了 “doc”, “lib”, “man”这些属性。

    // package.json (for npm)
    "directories": {
        "bin": "./bin",
        "doc": "./doc",
        "lib": "./lib",
        "man": "./man"
    

    未来,directories里的信息可能会以其他写法存在来使用。

    directories.bin

    如果在 directories.bin 中指定bin目录,则会添加该文件夹(bin目录)中的所有文件。 由于 bin 指令的工作方式,指定bin路径和设置directories.bin都是错误的。如果要指定单个文件,请使用bin,而对于现有 bin 目录中的所有文件,则使用 directories.bin

    directories.man

    directories.man里指定的目录里的文件全部都是man页面。

    repository (仓库)

    “repository”字段值是指定你代码存放的位置,有助于人们进行代码贡献。 如果git代码仓库是在GitHub, 那么使用npm docs命令就可以让使用者找到你的包。字段描述如下:

    "repository": { "type": "git", // 仓库网站简写 "url": "https://github.com/npm/cli.git" // git仓库地址

    指定“repository”字段值像这样:

    "repository": { "type": "git", "url": "https://github.com/npm/cli.git"

    例如:pnpm中指定的“repository”字段值如下,

    // package.json (for pnpm)
      "repository": {
        "type": "git",
        "url": "git+https://github.com/pnpm/pnpm.git"
    

    当我使用 npm doc pnpm命令行时,就会使用默认浏览器打开 pnpm 的文档地址(也是其官网地址)

    repository中定义的 "url" 属性值应该是一个公开可用的(可能是只读的)URL,这个URL无需任何修改就可以直接传递给VCS程序运行。

    对于GitHub、GitHub-gist、Bitbucket 或 GitLab存储库,可以使用相同意思的简短词用于 npm install 命令来安装你的包。

    "repository": "npm/npm", "repository": "github:user/repo", "repository": "gist:11081aaa281", "repository": "bitbucket:user/repo", "repository": "gitlab:user/repo"

    如果你的包里的 package.json 文件没有在项目(包)的根目录(例如,它是monorepo项目的),那你可以指定它所在的目录,例如:

    "repository": { "type": "git", "url": "https://github.com/facebook/react.git", "directory": "packages/react-dom"

    例如,“vue-tsc”就是存在monorepo项目 volar 中的,所以,当你查看“vue-tsc”的package.json 时,你会发现,最新版的vue-tsc指明的repository字段值中的 directory 属性是"vue-language-tools/vue-tsc",意思就是说 vue-tsc 的主要的package.json 文件是monorepo包vue-language-tools里,(也说明了vue-tsc包是vue-language-tools的子包)。

    // package.json (for vue-tsc)
    "repository": {
    	"type": "git",
    	"url": "https://github.com/johnsoncodehk/volar.git",
    	"directory": "vue-language-tools/vue-tsc"
    

    scripts(脚本)

    “scripts”是一个由脚本命令组成的字典值对象,这些脚本会在包不同的生命周期中被执行。key是生命周期事件,value是要运行的命令。

    在项目中,团队成员都有自己想用的包管理工具,但为了更好的规范,比如项目中指定使用pnpm,如果你不希望其他成员使用 npm 或 yarn ,就可以在 package.json 配置文件中添加预安装 preinstall 配置项,从而规范使用统一的包管理器

    // package.json
        "scripts": {
            "preinstall": "npx only-allow pnpm"
    

    查看 scripts 文章找到更多关于编写包脚本的详情吧.(如果有时间的话,我后续会专门出package.json 的script命令行的知识,让大家更加了解npm script的操作)

    config

    "config"对象可以被用作 跨升级持久化的包脚本(package script)配置项的参数 例如,如果包的package.json的设置具有以下内容:

    "name": "foo", "config": { "port": "8080"

    那么文件配置中也会有 "start" 命令行脚本引用到npm_package_config_port这个环境变量。这样配置之后可以在项目中使用这个环境变量,例如:

    // js 文件
    const port = process.env.npm_package_config_port; // 值为:"8080"
    

    这个非常在一些配置文件中非常有用。查看 npm-pkg 了解相关的pkg设置吧

    dependencies

    Dependencies 字段值是指明了映射到版本范围的依赖包的简单对象。版本范围是一个字符串形式,它包含一个或多个空格分隔的描述符。Dependencies 字段值也可以是 tar包(tarball)或者git链接(git URL)。

    请不要将测试或过渡性的依赖包放在dependencies对象中,详见下文的devDependencies

    有关指定版本范围的详细信息,请参阅 semver

  • version 必须 version 完全匹配, 固定具体的版本。
  • >version 大于
  • >=version 大于或等于
  • <version 小于
  • <=version 小于或等于
  • ~version 约等于,详见 semver
  • ^version "与version兼容 " 详见 semver
  • 1.2.x 1.2.0, 1.2.1, 等., 但不包括 1.3.0
  • http://... 见下文的 “URL链接作为依赖项”
  • * 匹配任意版本
  • "" (仅仅是一个空字符串) 与 *一样
  • version1 - version2 相当于 >=version1 <=version2.
  • range1 || range2 满足range1或range2。
  • git... 见下文的“Git URL链接作为依赖项”See 'Git URLs as Dependencies' below
  • user/repo 见下文的 'GitHub URLs(链接)'
  • tag 指定版本标记且作为tag发版的版本,详见 npm dist-tag
  • path/path/path 见下文的 Local Paths 
  • 常见版本范围示例

    常见版本范围我做了一个图例举出来:其中的

    [1.2.7]

    [major, minor, patch]

    [大版本,小版本,补丁版本]。其中补丁版本也叫fix版本或patch版本

    1: 表示 >=1.0.0 <2.0.0-0 (匹配大版本),等同于 1.x 等同于 ~1

    1.2: 表示 >= 1.2.0 < 1.3.0-0。等同于 1.2.x 等同于 ~1.2 匹配大版本和小版本,

    1.2.7: 固定1.2.7版本(大、小、补丁版本都必须一致)

    >1.2.7: 大于1.2.7版本,如1.2.8、1.3.6、3.5.0。不能是1.2.7、1.2.6 或 1.1.0

    >=1.2.7: 大于或等于1.2.7版本,如1.2.7、1.2.8、1.3.6、3.5.0。不能是1.2.6 或 1.1.0。

    <1.2.7: 小于1.2.7版本,如1.2.6、0.3.8.

    <=1.2.7: 小于或等于1.2.7版本

    ~1: 表示 >=1.0.0 <2.0.0-0,等同于 1.x 等同于 1

    ~1.2: 表示 >= 1.2.0 < 1.3.0-0,等同于 1.2.x 等同于 1.2

    ~1.2.7: 表示 >= 1.2.7 < 1.3.0-0

    ^1.x : 表示 >=1.0.0 <2.0.0-0

    ^1.2.x : 表示 >=1.2.0 <2.0.0-0

    ^1.2.7: 表示 >=1.2.7 <2.0.0-0

    例如,以下依赖版本的写法都是正确的:

    "dependencies": { "foo": "1.0.0 - 2.9999.9999", "bar": ">=1.0.2 <2.1.2", "baz": ">1.0.2 <=2.3.4", "boo": "2.0.1", "qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0", "asd": "http://asdf.com/asdf.tar.gz", "til": "~1.2", "elf": "~1.2.3", "two": "2.x", "thr": "3.3.x", "lat": "latest", "dyl": "file:../dyl"

    URLs as Dependencies

    您可以指定tarball(tar包) URL来代替版本范围,此tarball将会在安装时下载并在本地安装到您的软件包中。

    Git URLs as Dependencies

    Git URL的格式为:

    <protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
    

    我将它分明标出来:

    <protocol> 可选值有: gitgit+sshgit+httpgit+https, or git+file

    如果提供了 #<commit-ish> , 那么#<commit-ish>的值将会被用于 clone(克隆)该提交。 如果 commit-ish 的格式为#semver:<semver><semvers>可以是任意有效的semver范围或精确(固定)版本,npm将在远程存储库中查找与该范围匹配的任何tags或引用,就像查找注册表依赖项一样。如果#<commit-ish>#semver:<semver>任意一个已经被指定,那么就会使用默认分支。

    git+ssh://git@github.com:npm/cli.git#v1.0.27
    git+ssh://git@github.com:npm/cli#semver:^5.0
    git+https://isaacs@github.com/npm/cli.git
    git://github.com/npm/cli.git#v1.0.27
    

    当从git存储库安装依赖项时,package.json中存在某些字段将会导致npm认为这些依赖项是需要执行构建的。为此,您的存储库将被克隆到一个临时目录中,安装其所有dep,运行相关脚本,打包,并安装结果目录。如果您的git依赖项使用工作区,或者存在以下任何脚本,则会发生上述情况:

  • build
  • prepare
  • prepack
  • preinstall
  • install
  • postinstall
  • 如果您的git存储库包含预构建,那么您可能更想确保没有定义上述脚本,否则你的依赖将会在每次安装时重新构建(将为每次安装重建依赖关系)。

    例如typescript4.8.4 中的script脚本就有prepare,

    "scripts": {
       "prepare": "gulp build-eslint-rules",
       // ...
    

    prepare脚本会在执行npm install之后自动执行。也就是说当我们执行npm install安装完项目依赖项后会执行 prepare脚本(此处是gulp build-eslint-rules)。

    与script脚本与依赖项的关系,可以查看 script了解.

    GitHub URLs

    在1.1.65版后,你可以仅仅用“user/foo-project”引用GitHub urls,比如

    从版本1.1.65开始,您可以将GitHub url描述为 “foo”:“user/fooproject”。与git URL一样,GitHub url将包括一个commit-ish后缀。例如:

    "name": "foo", "version": "0.0.0", "dependencies": { "express": "expressjs/express", "mocha": "mochajs/mocha#4727d357ea", "module": "user/repo#feature\/branch"

    Local Paths

    从2.0.0版开始,您可以提供包的本地目录的路径。然后可以使用npm install-S或npm install--save保存本地路径, 以下任一格式都可以如下:

    ../foo/bar
    ~/foo/bar
    ./foo/bar
    /foo/bar
    

    在这种情况下,它们将被规范化为相对路径,并添加到package.json中。例如:

    "name": "baz", "dependencies": { "bar": "file:../foo/bar"

    此功能有助于本地脱机模式下的开发和创建需要npm安装但又不想使用其他的服务器的测试,这些测试需要安装在您不希望触及外部服务器的位置,但这不能用于发包到公共存储库上。

    注意:当运行“npm-install”时,在这种情况下,由本地路径链接的包将不会安装这些包自己的依赖项。必须从本地路径本身内部运行“npm install”。

    devDependencies

    如果有人计划在他们的程序中下载并使用您的模块,那么他们可能不想或不需要下载并构建您的模块中使用的外部测试或文档架构。

    在这种情况下,最好在devDependencies对象中映射这些附加项。

    当在包(项目)根目录中运行 npm linknpm install 命令时,devDependencies字段值里描述的依赖项将会被安装,并且可以像任何其他 npm 配置参数一样对 "devDependencies" 中描述的依赖项进行管理。

    查看 config 以了解更多相关主题的信息。

    对于非特定平台的构建步骤而言,例如将CoffeeScript或其他语言编译为JavaScript,请使用prepare脚本来执行此操作,并使所需的依赖包成为写入到devDependency字段对象中。

    "name": "ethopia-waza", "description": "a delightfully fruity coffee varietal", "version": "1.2.3", "devDependencies": { "coffee-script": "~1.6.3" "scripts": { "prepare": "coffee -o lib/ -c src/waza.coffee" "main": "lib/waza.js"

    "prepare" 脚本(此处为"coffee -o lib/ -c src/waza.coffee")将在发布前运行,这样用户就可以使用该功能,而无需自己编译它。在dev模式下(即本地运行npm install),它也会运行此"prepare"脚本,这样你就可以很轻松地测试它。

    peerDependencies(兼容性依赖项)

    peerDependencies 在我们进行一些插件开发的时候会经常用到。“peerDependencies”的目的就是提示宿主环境安装满足插件 peerDependencies所指定依赖的包,然后在当插件import或require所依赖的包的时候,永远都是引用宿主环境统一安装的npm包,解决插件与所依赖包不一致的问题。

    在有些情况下, 您想标明软件包与宿主工具或依赖库的兼容性,而不必对该宿主工具包执行“require”操作。 这就是我们通常所说的 “plugin”(插件). 尤其是你的模块可能要暴露一个特定的接口,并由host文档来规范和指定。

    "name": "tea-latte", "version": "1.3.5", "peerDependencies": { "tea": "2.x"

    这确保了你的tea-latte插件包依赖的tea仅是2.x版本的。当tea-latte包的使用者运行npm install tea-latte来安装tea-latte作为依赖项时,就会生成关于 tea-latte包与tea包的依赖关系:

    ├── tea-latte@1.3.5
    └── tea@2.2.0
    

    在npm v3到v6中,peerDependencies 中指定的依赖并没有被自动安装,如果在依赖树中发现无效版本的peerDepndencies中指定的依赖包时,则会发出警告。从npm v7开始,默认安装peerDependencies里的依赖包。

    如果依赖树关系无法被正确的解决,那么,当你尝试安装另一个具有冲突需求的插件可能会导致错误。因此,请确保您的插件所依赖的包的版本尽可能广,不要将其限制在特定的补丁版本,例如,以下是“peer”不推荐的:

    "name": "tea-latte", "version": "1.3.5", "peerDependencies": { "tea": "2.7.x" // 请不要限制在指定补丁版本,这是不推荐的

    假设你的主包符合 semver 语义化版本的规范,即使只改变主包的大版本号,也会导致你的插件被损坏。 因此,如果您使用过主包的每个1.x版本,请使用“^1.0”或“1.x”来表示这一点。如果您依赖1.5.2中介绍的功能,请使用“^1.5.2”。

    peerDependenciesMeta

    当用户安装您的包时,如果他的项目中没有安装你的包里peerDependencies中指定的兼容性依赖包,npm将会发出警告。

    peerDependenciesMeta字段就是用于为npm提供有关如何使用 peerDependencies 兼容性依赖项的更多信息。具体来说,peerDependenciesMeta 允许将 peerDependencies 兼容性依赖项 标记为可选。

    "name": "tea-latte", "version": "1.3.5", "peerDependencies": { "tea": "2.x", "soy-milk": "1.2" "peerDependenciesMeta": { "soy-milk": { "optional": true

    标记兼容性依赖项 "soy-milk"为可选项,以确保即使在主机中未安装 "soy-milk" 包时,npm也不会警告提示。 这允许您集成各种主包并使其互相作用,而无需引入那些需要被安装的全部依赖包。

    bundleDependencies

    bundleDependencies定义在发包时捆绑在一起的一组包名,如果您需要在本地保留npm包或通过单个文件下载使其可用,您可以通过在“bundleDependencies”数组中指定包名称并执行“npm pack”命令,将包绑定到tarball文件中。

    我们定义一个package.json文件如下:

    "name": "awesome-web-framework", "version": "1.0.0", "bundleDependencies": [ "renderized", "super-streams"

    我们可以通过运行“npm pack”命令来获得“awesome-web-framework-1.0.0.tgz”文件。该文件包含“renderized”和“superstreams”这两个依赖项,我们可以通过执行“npm install awesome-web-framework-1.0.0.tgz”命令将其安装到新项目中。请注意,包名称不包含任何版本,因为包的版本信息已经在 “dependencies” 字段值对应的包中指定。

    现在也比较流行把“bundleDependencies”拼写为“bundledDependencies”。

    或者,“bundleDependencies”可以定义为布尔值。值为“true”将绑定所有依赖项,值为“false”将不绑定任何依赖项。

    optionalDependencies

    如果项目中使用到一个依赖,而这个依赖没有被安装或者安装失败,但你又想让npm继续执行操作,那么你可以把这个依赖项放到optionalDependencies对象里。这是包名到版本或url的映射,就像“dependencies”对象一样。但不同的是,构建失败不会导致安装失败。运行“npm install --omit=optional”将阻止安装这些依赖项。处理缺少的依赖项仍然是你的程序的责任。例如,如下所示:

    try {
      var foo = require('foo')
      var fooVersion = require('foo/package.json').version
    } catch (er) {
      foo = null
    if ( notGoodFooVersion(fooVersion) ) {
      foo = null
    // .. then later in your program ..
    if (foo) {
      foo.doFooThings()
    

    optionalDependencies 中罗列的依赖项将覆盖 dependencies中同名的条目,因此同样的一个依赖项通常最好只放在一个位置。

    overrides

    如果您需要对依赖项的依赖项进行特定更改,例如用已知的安全解决问题的方案替换依赖项的版本,用fork替换现有的依赖项,或者确保代码的各处都使用相同版本的包,那么您可以添加 “overrides”表示覆盖。

    “overrides”提供了一种将依赖关系树中的包替换为其他版本或完全替换为其他包的方法。这些更改的范围可以根据需要确定为特定或模糊。

    要确保foo包始终安装为1.0.0版本,不管你依赖项依赖于foo包的哪个版本:

    "overrides": { "foo": "1.0.0"

    上述是一个简单的处理标记,完整的对象形式可以允许用来覆盖包本身及其子包,例如下面的代码,这将导致foo包版本始终为1.0.0,同时也使“bar”包不管距离 "foo"包以外的(依赖树的)任何深度,“bar”包都为1.0.0版本:

    "overrides": { "foo": { ".": "1.0.0", "bar": "1.0.0"

    当 foo 包作为 bar 包的子包(孙子或曾孙等)时,如果仅仅想改变foo包版本为1.0.0时,参照如下写法:

    "overrides": { "bar": { "foo": "1.0.0"

    key键可以嵌套为任意长度。要仅在foo是bar的子级且bar是baz的子级时重写foo,请执行以下操作:

    "overrides": { "baz": { "bar": { "foo": "1.0.0"

    override(覆盖)的键还可以包括版本或版本范围。仅当 foo 包作为是bar@2.0.0 子包时,将 foo 包的版本覆盖为1.0.0:

    "overrides": { "bar@2.0.0": { "foo": "1.0.0"

    除非依赖项"dependencies"和覆盖本身"overrides"共享完全相同的版本规范,否则您不能为直接依赖的包设置"overrides"覆盖。例如"dependencies"中的依赖项"foo"包的版本指定了"^1.0.0","overrides"中重写的"foo"包的版本指定为"^2.0.0",那这就会引发eoverride错误。但是如果"overrides"中重写的"foo"包的版本指定为"^1.0.0"(与"dependencies"中的“bar”共享完全相同的版本规范),那就是允许的:

    "dependencies": { "foo": "^1.0.0" "overrides": { // bad(坏),将引发eoverride错误 // "foo": "^2.0.0" // good(好),匹配规范,因此允许重写 "foo": "^1.0.0"

    为了更容易处理此限制,还可以通过在您希望版本与$匹配的包的名称前面加前缀,将覆盖定义为对直接依赖项的规范的引用。 为了使这个限制更容易处理,"overrides"还可以定义为对直接依赖项的规范的引用,方法是在您希望版本匹配的包的名称前加上一个$,下述中,$foo代指"dependencies"中指定的(版本的)"foo"包,即$foo代指 "foo": "^2.0.0"

    "dependencies": { "foo": "^1.0.0" "overrides": { // bad(坏),将引发eoverride错误 // "foo": "^2.0.0" // good(好),匹配规范,因此允许重写 // "foo": "^1.0.0" // best(最佳), 覆盖被定义为对依赖项的引用。 "foo": "$foo", // 引用的包不需要与重写的包匹配 "bar": "$foo"

    engines

    engines就是为了指定运行环境所需要的引擎或指定引擎。这对于项目的流程规范来说非常有用,希望各位架构师尽可能的好好利用这个字段。

    你可以给你的代码正常运行时所依赖的node版本进行指定:

    "engines": { "node": ">=0.10.3 <15"

    而且,像 "dependencies"字段值一样,如果不给node指定版本(或者指定node版本为“*”),则表示任何版本的“node”都可以,但是请不要这样做,你最好指定node版本

    您还可以使用“engines”字段指定哪些版本的npm能够正确安装您的程序。例如:

    "engines": { "npm": "~1.0.20"

    除了可以指定npm,当然也可以指定pnpm:

    "engines": { "pnpm": "~7.13.4"

    除非用户设置了“engine-strictconfig配置标志,否则"engines"字段仅作为一个建议而存在的字段,仅当您的包作为依赖项安装时才会产生警告。

    engine-strict如果设置为true,那么npm将强烈拒绝安装(也或许会考虑安装)任何声称与当前不兼容的Node.js版本。这可以通过设置--force 标志来覆盖。

    您可以指定模块将在哪些操作系统上运行:

    "os": [ "darwin", "linux"

    您还可以设置阻止而非允许的操作系统,只需在被阻止的操作系统前面加上一个“!”,以下代码表示,(项目或)模块不能运行在32位的window系统上:

    "os": [ "!win32"

    主机操作系统由“process.platform”确定,例如,我们一般判断linux或MacOs系统:

    var isLinuxOrMacOs = process.platform === "linux" || process.platform === "darwin";
    

    os它可以同时阻止和允许某一项,尽管没有任何好的理由这样做 (好倔强啊,哈哈哈)

    如果你的代码只运行在特定的cpu体系结构上,那么你可以指定哪些体系结构,例如下面的代码:

    表示代码运行在英特尔32位系统 或 AMD64位系统

    释:Intel Architecture, 32-bit,缩写为 IA-32

    x86-64有时会简称为“x64”,是64位微处理器架构及其相应指令集的一种,也是Intel x86架构的延伸产品。“x86-64”1999由AMD设计,AMD 首次公开 64 位集以扩充给 IA-32,称为 x86-64(后来改名为 AMD64)

    "cpu": [ "x64", "ia32"

    像“os”选项一样,您也可以使用"!"标记来阻止cpu体系,像这样:

    "cpu": [ "!arm", "!mips"

    代码中可以使用 process.arch 代表主机体系结构。 arch可以是下列值之一:IA32,X64,IPF,EBC,ARM,common。common表示对所有体系结构有效。

    例如,我们一般会收集输出platformInfo平台信息如下:

    const platformInfo = `${process.platform}-${process.arch} node-${process.version}`;
    

    private

    如果你在 package.json 中设置了“private”:true,那么npm将会不会发布它。这是一种防止意外发布私有存储库的方法。如果你想要确定给定的包是只发布在特定存储库(如内部存储库)里,那么请使用下面描述的 publishConfig 字典在发布时覆盖 registry 配置参数。一般情况下,公司有自己的私有存储库用于存放公司项目,此时,我们就必须要设置“private”:true以防止意外发布。

    publishConfig

    这是一组在发布时使用的配置值。当你想设置tag(打标签)或者registry(存储库地址)或者access(访问权限)的时候publishConfig就变得非常方便,这样您就可以确保给定的包没有标记为“latest”(最新)、没有发布到全局公共存储库,或者默认情况下作用域模块是私有的。

    参阅 config 以查看可重写的配置选项列表。

    workspaces

    可选项workspaces字段的值是文件表达式数组,其中描述了安装客户端应查找的每一处存在本地文件系统中位置的工作区workspace,以找到需要符号链接到顶层node_modules文件夹的每个“工作区”

    描述了本地文件系统中的位置,而这些位置正是安装客户端需要查找的每个“工作区”,这些 “工作区” 需要被符号链接到顶层node_modules文件夹的。(符号链接又称为软链接)。

    workspaces字段值可以描述 作为工作区的文件夹的直接路径,也可以定义将解析到这些相同文件夹的全局变量。

    在下面的示例中,所有位于“./packages”中的文件夹,只要这些文件夹中有有效的 package.json 文件,那么这些存在有效package.json 文件的文件夹都将被视为工作区:

    "name": "workspace-example", "workspaces": [ "./packages/*"

    查看workspaces 章节看更多示例。

    DEFAULT VALUES(默认值)

    npm将会根据包内容给package.json文件内容设置一些默认值:

    "scripts": {"start": "node server.js"}

    如果包的根目录有`server.js`文件,npm会默认将`start`命令设置为`node server.js`

    "scripts":{"install": "node-gyp rebuild"}

    如果包的根目录有`binding.gyp`文件并且你没有定义`install` 或 `preinstall`脚本,
    那么npm会默认将`install`命令值设置为 使用`node-gyp`编译 
    

    "contributors": [...]

    如果包的根目录有 `AUTHORS`文件, npm会将每一行视为`Name<email>(url)`格式,其中email和url是可选的。以“#”或空格来开头的行将会被忽略。
    

    其他相关阅读

  • semver
  • workspaces
  • npm init
  • npm version
  • npm config
  • npm help
  • npm install
  • npm publish
  • npm uninstall
  • francecil Node.js
    私信