读懂项目中的 package.json 文件

357 阅读14分钟

image.png package.json  是⼀个⽤于描述和配置项⽬的重要⽂件,其中包含了许多字段和选项,可以影响项⽬的构建、依赖管理、脚本执⾏等⽅⾯。

描述配置

name

定义项⽬的名称,不能以"."和"_"开头,不能包含⼤写字⺟(这是因为当软件包在npm上发布时,会基于此属性获得⾃⼰的URL,所以不能包含⾮URL安全字符(non-url-safe)

Tip:  我们平时开发的很多项⽬并不会发布在npm上,所以这个名称是否标准可能就不是那么重要,它不会影响项⽬的正常运⾏。如果需要发布在npm上,name字段⼀定要符合要求

version

image.png 定义项⽬的版本号,格式为:⼤版本号.次版本号.修订号 1.x.x

如果某个版本的改动较⼤,并且不稳定,可能⽆法满⾜预期的兼容性需求,就需要发布先⾏版本,先

⾏版本通过会加在版本号的后⾯,通过“-”号连接以点分隔的标识符和版本编译信息:内部版本

(alpha)、公测版本(beta)和候选版本(rc,即release candiate)

// 查看最新版本
npm view antd version
// 查看所有版本
npm view antd versions

repository

项⽬代码仓库地址

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

keywords

⼀组项⽬的技术关键词,⽐如 Ant Design 组件库的 keywords 如下:

"keywords": [
    "ant",
    "component",
    "components",
    "design",
    "framework",
    "frontend",
    "react",
    "react-component",
    "ui
]

description

项⽬的描述,让别⼈能快速了解该项⽬。

author

author顾名思义就是作者,表⽰该项⽬包的作者。它有两种形式,⼀种是字符串格式:

{
    "author": "xxxx"
}

另⼀种是对象形式:

"author": {
    "name" : "xxx",
    "email" : "<xxxxx@xx.com>",
    "url" : "xxx"
}

⽂件配置项

main

main 字段⽤来指定加载的⼊⼝⽂件,在 browser 和 Node 环境中都可以使⽤。如果我们将项⽬发布为 npm包,那么当使⽤ require 导⼊npm包时,返回的就是main字段所列出的⽂件的module.exports 属性。如果不指定该字段,默认是项⽬根⽬录下的index.js。如果没找到,就会报错。

"main""./src/index.js"

browser

browser字段可以定义 npm 包在 browser 环境下的⼊⼝⽂件。如果 npm 包只在 web 端使⽤,并且严禁在 server 端使⽤,使⽤ browser 来定义⼊⼝⽂件。

module

module字段可以定义 npm 包的 ESM 规范的⼊⼝⽂件,browser 环境和 node 环境均可使⽤。如果 npm 包导出的是 ESM 规范的包,使⽤ module 来定义⼊⼝⽂件。

"module""./src/index.mjs",

当⼀个项⽬同时定义了 main,browser 和 module,像 webpack,rollup 等构建⼯具会感知这些字段,并会根据环境以及不同的模块规范来进⾏不同的⼊⼝⽂件查找。

    "main""./index.js",
    "browser""./browser/index.js",
    "module""./index.mjs"

files

files配置是⼀个数组,⽤来描述当把npm包作为依赖包安装时需要说明的⽂件列表。当npm包发布时,files指定的⽂件会被推送到npm服务器中,如果指定的是⽂件夹,那么该⽂件夹下⾯所有的⽂件都会被提交。避免安装时间太⻓。发布时默认会包括 package.json,license,README 和 main 字段⾥指定的⽂件。忽略 node_modules,lockfile 等⽂件。

"files": [
    "filename.js",
    "directory/",
    "glob/*.{js,json}"
]

type

在 node ⽀持 ES 模块后,要求 ES 模块采⽤ .mjs 后缀⽂件名。只要遇到 .mjs ⽂件,就认为它是 ES 模块。如果不想修改⽂件后缀,就可以在 package.json⽂件中,指定 type 字段为 module。

"type""module"

exports

node 在 14.13 ⽀持在 package.json ⾥定义 exports 字段,拥有了条件导出的功能。exports  字段可以配置不同环境对应的模块⼊⼝⽂件,并且当它存在时,它的优先级最⾼。使⽤ export 字段,您可以指定模块的不同导出路径,并控制在不同环境下(如ES模块和CommonJS模块)如何解析和导出模块。

"exports": {
    ".": {
    "require""./index.cjs",
    "import""./index.mjs"
    },
   "./feature": {
     "require""./feature.cjs",
     "import""./feature.mjs"
   }
}

这样的配置在使⽤ import 'xxx' 和 require('xxx')时会从不同的⼊⼝引⼊⽂件还可以为包中的特定⼦路径定义导出路径。例如,如果您有⼀个 lib ⽬录,并希望允许⽤⼾直接导⼊其中的模块,可以这样配置:

"exports": {"./lib/*""./lib/*.js"}

这允许⽤⼾使⽤以下⽅式导⼊模块:

import feature from 'my-package/lib/feature';

workspaces

项⽬的⼯作区配置,⽤于在本地的根⽬录下管理多个⼦项⽬。可以⾃动地在 npm install 时将 workspaces 下⾯的包,软链到根⽬录的 node_modules 中,不⽤⼿动执⾏ npm link 操作,workspaces  字段接收⼀个数组,数组⾥可以是⽂件夹名称或者通配符。⽐如:

"workspaces": [
    "workspace-a"
]

表⽰在 workspace-a ⽬录下还有⼀个项⽬,它也有⾃⼰的 package.json。通常⼦项⽬都会平铺管理在 packages ⽬录下,所以根⽬录下 workspaces 通常配置为:

"workspaces": [
    "packages/*"
]

// workspaces 配置指向 packages ⽬录中的所有⼦⽬录,这些⼦⽬录都将被视为独⽴的包。

⼯作空间的优点

• 依赖共享:所有⼯作空间包共享相同的 node_modules ⽬录,从⽽避免重复安装相同的依赖项,节省磁盘空间和安装时间。

• 简化管理:可以通过根 package.json ⽂件来管理所有⼯作空间包的依赖和脚本,简化版本控制和发布流程。

• 跨包开发:允许在⼯作空间包之间轻松链接和引⽤,促进跨包开发和集成。

脚本配置

scripts

指定项⽬的⼀些内置脚本命令,这些命令可以通过 npm run 来执⾏。通常包含项⽬开发,构建 等 CI命令,

除了运⾏基本的scripts命令,还可以结合pre和post完成前置和后续操作

"scripts": {
    "build""webpack",
    "prebuild": "xxx", // build 执⾏之前的钩⼦
    "postbuild": "xxx" // build 执⾏之后的钩⼦
}

当执⾏ npm run build 命令时,会按照 prebuild -> build -> postbuild 的顺序依次执⾏上⽅的命 令

但是这样的隐式逻辑很可能会造成执⾏⼯作流的混乱,所以pnpm 从 7.14.0 版本开始 和 yarn2 都已经废弃掉了这种 pre/post ⾃动执⾏的逻辑,如果需要⼿动开启,pnpm  项⽬可以设置 enable-pre-post-scripts=true。

enable-pre-post-scripts = true

config

config字段⽤来配置scripts运⾏时的配置参数

"config": {
    "port": "3001"
}

⽤⼾可以通过 npm config set foo: port xxx  命令来重写port的值。

依赖配置

dependencies

dependencies 字段中声明的是项⽬的⽣产环境中所必须的依赖包。使⽤ npm install xxx 或则 npm install xxx --save 时,会被⾃动插⼊到该字段中。

"dependencies": {
    "react""^17.0.2",
    "react-dom""^17.0.2",
    "react-scripts""4.0.3",
}

这⾥每⼀项配置都是⼀个键值对(key-value), key表⽰模块名称,value表⽰模块的版本号。版本号遵循主版本号.次版本号.修订号的格式规定:

• 固定版本:  上⾯的react-scripts的版本4.0.3就是固定版本,安装时只安装这个指定的版本;

• 波浪号: ⽐如~4.0.3,表⽰安装4.0.x的最新版本(不低于4.0.3),也就是说安装时不会改变主版本号和次版本号;

• 插⼊号: ⽐如上⾯ react 的版本^17.0.2,表⽰安装17.x.x的最新版本(不低于17.0.2),也就是说安装时不会改变主版本号。如果主版本号为0,那么插⼊号和波浪号的⾏为是⼀致的;

• latest:安装最新的版本。

需要注意,不要把测试或者过渡性的依赖放在dependencies,避免⽣产环境出现意外的问题。

devDependencies

devDependencies 中声明的是开发阶段需要的依赖包,如 Webpack、Eslint、Babel 等,⽤于辅助开发。它们不同于 dependencies,因为它们只需安装在开发设备上,⽽⽆需在⽣产环境中运⾏代码。当打包上线时并不需要这些包,所以可以把这些依赖添加到 devDependencies 中,这些依赖依然会在本地指定 npm install 时被安装和管理,但是不会被安装到⽣产环境中。

使⽤ npm install xxx -D 或者 npm install xxx --save-dev 时, 会被自动插入到该字段中。

peerDependencies

有些情况下,我们的项⽬和所依赖的模块,都会同时依赖另⼀个模块,但是所依赖的版本不⼀样。⽐如,我们的项⽬依赖A模块和B模块的1.0版,⽽A模块本⾝⼜依赖B模块的2.0版。⼤多数情况下,这不是问题,B模块的两个版本可以并存,同时运⾏。但是,有⼀种情况,会出现问题,就是这种依赖关系将暴露给⽤⼾。

最典型的场景就是插件,⽐如A模块是B模块的插件。⽤⼾安装的B模块是1.0版本,但是A插件只能和 2.0版本的B模块⼀起使⽤。这时,⽤⼾要是将1.0版本的B的实例传给A,就会出现问题。因此,需要⼀种机制,在模板安装的时候提醒⽤⼾,如果A和B⼀起安装,那么B必须是2.0模块。

peerDependencies字段就是⽤来供插件指定其所需要的主⼯具的版本。

"name""chai-as-promised",
peerDependencies": {
    chai""1.x"
}

上⾯代码指定在安装chai-as-promised模块时,主程序chai必须⼀起安装,⽽且chai的版本必须是  1.x。如果项⽬指定的依赖是chai的2.0版本,就会报错。

需要注意,从npm  3.0版开始,peerDependencies不再会默认安装了。

optionalDependencies

可选依赖,顾名思义,表⽰依赖是可选的,它不会阻塞主功能的使⽤,安装或者引⼊失败也⽆妨。这类依赖如果安装失败,那么 npm 的整个安装过程也是成功的。

⽐如我们使⽤ colors 这个包来对 console.log 打印的信息进⾏着⾊来增强和区分提⽰,但它并不是必需的,所以可以将其加⼊到 optionalDependencies,并且在运⾏时处理引⼊失败的逻辑。

使⽤ npm install xxx -O 或者 npm install xxx --save-optional 时, 依赖会被自动插⼊到该字段中。

"optionalDependencies": {
    "colors""^1.4.0"
}

bundleDependencies

打包依赖。它的值是⼀个数组,在发布包时,bundleDependencies  ⾥⾯的依赖都会被⼀起打包。

⽐如指定 react 和 react-dom 为打包依赖:

"bundleDependencies": [
    "react",
    "react-dom"
]

在执⾏ npm pack 打包⽣成 tgz 压缩包中,将出现 node_modules 并包含 react 和 react-dom。需要注意的是,这个字段数组中的值必须是在 dependencies,devDependencies 两个⾥⾯声明过的依赖才⾏

普通依赖通常从 npm registry 安装,但当你想⽤⼀个不在 npm registry ⾥的包,或者⼀个被修改过的第三⽅包时,打包依赖会⽐普通依赖更好⽤。

overrides

overrides 可以重写项⽬依赖的依赖,及其依赖树下某个依赖的版本号,进⾏包的替换。 overrides ⽀持任意深度的嵌套。

⽐如某个依赖 A,由于⼀些原因它依赖的包 foo@1.0.0 需要替换,我们可以使⽤ overrides 修改 foo 的版本号:

"overrides": {
    "foo""1.1.0-patch"
}

当然这样会更改整个依赖树⾥的 foo,我们可以只对 A 下的 foo 进⾏版本号重写:

"overrides": {
    "A": {
        "foo": "1.1.0-patch"
    }
}

engines

可能对npm包的版本或者Node版本有特殊要求,如果不满⾜条件就可能⽆法将项⽬跑起来。为了让项

⽬开箱即⽤,可以在engines字段中说明具体的版本号:

"engines": {
    "node"">=8.10.3 <12.13.0",
    "npm"">=6.9.0"
}

packageManager

packageManager 是⼀个配置选项,⽤于指定项⽬使⽤的包管理器。

"packageManager": "pnpm"

如果您的项⽬在不同的开发者或团队之间共享,并且有些开发者使⽤ Yarn,⽽有些开发者使⽤ npm, 您可以通过指定 packageManager 来确保所有开发者在依赖管理和脚本执行时的一致性,也可以通过@ 来指定版本

发布配置

是和项⽬发布相关的配置

private

如果是私有项⽬,不希望发布到公共 npm 仓库上,可以将 private 设为 true。

"privite": true

publishConfig

publishConfig 就是 npm 包发布时使⽤的配置。

⽐如在安装依赖时指定了 registry 为 taobao 镜像源,但发布时希望在公⽹发布,就可以指定 publishConfig.registry。

"publishConfig": {
    "registry""https://registry.npmjs.org/"
}

通常情况下,publishConfig会配合private来使⽤,如果只想让模块发布到特定npm仓库,就可以这样来配置:

"private"true,
"publishConfig": {
     "tag""1.1.0",
    "registry""https://registry.npmjs.org/",
    "access""public"
}

配置项说明

1. access: 发布包的访问级别。可能的值包括:

  • public: 公开访问,所有⼈都可以访问。
  • restricted: 限制访问,需要授权才能访问(通常需要设置特定的 npm 配置)。
  • private: 私有包,不会发布到公共注册表(通常⽤于企业内部使⽤)。

2. tag: 发布时的标签。默认情况下是 latest,表⽰推荐使⽤的稳定版本。您也可以指定其他标签,如 next 或 beta,⽤于发布预览或测试版本。

3. registry: 发布的注册表地址。默认情况下是 npm 的公共注册表(  registry.npmjs.org/ ),但可以设置为其他私有注册表的地址。

使⽤场景

• 私有包管理: 如果您在使⽤私有 npm 注册表或企业内部的包管理系统,可以通过 publishConfig 设置正确的注册表和访问级别。

• 多版本控制:  对于具有复杂发布流程或多个稳定性级别的项⽬,使⽤不同的标签(如 next、beta)可以帮助您管理不同版本的发布。

os

os字段可以让我们设置该npm包可以在什么操作系统使⽤,不能再什么操作系统使⽤。如果我们希望开发的npm包只运⾏在linux,为了避免出现不必要的异常,建议使⽤Windows系统的⽤⼾不要安装它,这时就可以使⽤os配置:

"os" ["linux"] // 适⽤的操作系统
"os" ["!win32"] // 禁⽤的操作系统

cpu

指定项⽬只能在特定的 CPU 体系上运⾏。

"cpu" ["x64", "AMD64"] // 适⽤的cpu
"cpu" ["!arm", "!mips"] // 禁⽤的cpu

第三⽅配置

⼀些第三⽅库或应⽤在进⾏某些内部处理时会依赖这些字段,使⽤它们时需要安装对应的第三⽅库。

types 或者 typings

⽤于指定 TypeScript 项⽬中的类型定义⽂件。它通常指向⼀个 TypeScript 类型定义⽂件或模块⼊⼝⽂件。

"typings": "types/index.d.ts",

eslintConfig

eslint的配置可以写在单独的配置⽂件.eslintrc.json  中,也可以写在package.json⽂件的eslintConfig配置项中。

"eslintConfig": {
    "root": true,
    "env": {
        "node": true
    },
    "extends": [
        "plugin:vue/essential",
        "eslint:recommended"
    ],
    "rules": {},
    "parserOptions": {
        "parser": "babel-eslint"
    },
}

browserslist

设置项⽬的浏览器兼容情况。babel 和 autoprefixer 等⼯具会使⽤该配置对代码进⾏转换通常情况下, browserslist 的配置信息可以放在项⽬的根⽬录下的 .browserslistrc ⽂件中,或者直接写在 package.json ⽂件的 browserslist 字段中。

"browserslist": [
    "> 1%",
    "last 2 versions"
]

常⻅的配置选项包括:

  • 最近版本:例如 last 2 versions 表⽰⽀持最近两个主流浏览器版本。

  • 全球使⽤率:例如 1% 表⽰⽀持全球使⽤量超过 1% 的浏览器。

  • 特定浏览器版本:例如 Firefox >= 60 表⽰⽀持 Firefox 浏览器的版本⼤于或等于 60。

  • 排除特定浏览器:例如 not IE 11 表⽰不⽀持 IE 11 浏览器。

  • 特定地区覆盖率:例如 cover 99.5% in CN 表⽰在中国市场上⽀持覆盖率达到 99.5% 的浏览器。

lint-staged

lint-staged 是⽤于对 git 的暂存区的⽂件进⾏操作的⼯具,它允许您定义在提交代码前应该运⾏的脚本。这些脚本通常⽤于执⾏代码⻛格检查、格式化、单元测试等任务

"lint-staged": {
    "*.js": [
        "eslint --fix",
        "git add"
    ],
    "*.css": [
        "stylelint --fix",
        "git add"
    ],
    "*.json": [
        "prettier --write",
        "git add"
    ]
},

lint-staged 通常配合 husky 这样的 git-hooks ⼯具⼀起使⽤。git-hooks ⽤来定义⼀个钩⼦,这些钩⼦⽅法会在 git ⼯作流程中⽐如 pre-commit,commit-msg 时触发,可以把 lint-staged 放到这些钩⼦⽅法中。

其他npm相关

npm link

npm link 是 Node.js 包管理⼯具 npm 提供的⼀个命令,⽤于在本地开发中将⼀个本地模块链接到

全局安装的 npm 模块⽬录中。这个命令在开发和测试⾃⼰的 npm 包或在不同项⽬之间共享本地模块

时特别有⽤。

使用场景和功能

  1. 本地开发模块:当您正在开发⼀个 npm 包,并且希望在其他项⽬中测试它时,可以使⽤ npm link 将该模块链接到全局安装,以便在其他项⽬中像使⽤正常 npm 包⼀样使⽤它。

  2. 共享本地模块:如果有多个项⽬需要使⽤同⼀个本地模块,⽽不想每次都⼿动复制和粘贴⽂件,可以使⽤ npm link 来建⽴⼀个链接,从⽽在多个项⽬中共享这个模块的最新版本。当完成本地npm包调试后,记得将链接断开。

另外⼀种⽅法 yalc使用方法

建议优先使用 Yalc, yalc 的⽅案是在本地模拟⼀个 npm 仓库,使⽤真实的 npm package 代替各种link ,除了不会发布到真实远端仓库外,都和真实发包⽆异。

但⽤npm link引⼊的依赖由于资源⽂件不在项⽬下,webpack不会对其做预编译,导致实际构建或者运⾏时会报错,此时如果直接将⽂件复制进依赖⽬录则能正常运⾏,yalc能解决此类问题。

参考地址: (docs.npmjs.com/cli/v10/con…