明知不可为而为之
大家好,我是柒八九 。一个专注于前端开发技术/Rust
及AI
应用知识分享 的Coder
。
前言
最近不是发了几篇关于用Rust
构建前端脚手架的文章吗?
- Rust 赋能前端-开发一款属于你的前端脚手架我们介绍了如何用
Rust
来写一个前端脚手架,主要的精力放在了Rust
方面。 - 前端项目里都有啥?我们讲主要的精力放在如何配置一个功能全备的前端项目。
- 如何在 npm 上发布二进制文件? 主要介绍如何将二进制文件发布到npm上。
然后,在写这系列文章时,发现有些操作需要用到package.json
中的属性。然后,有些属性看起来人畜无害,但是用起来却需要查很多的资料。所以,就想着。写一篇或者两篇关于package.json
的文章。
所以,今天我们就来讲讲package.json。
还有很多同学说,f_cli啥时候开源。这里简单说一嘴,因为
f_cli
现在只适配了针对vite+react
的模板,然后我想着想把vite+vue
/webpack+react/vue
/rsPack+vue/react
最起码再适配1-2个后,才有开源计划。
好了,天不早了,干点正事哇。
我们能所学到的知识点
- 什么是package.json
- package.json 中关键字段
- 总结
1. 什么是package.json
package.json
是JS/TS
项目的说明书和指导手册
按照功能来分类,package.json
具有如下的功能:(有些功能是可以相互配合使用的)
依赖管理
一个成熟的语言,不仅仅需要在语言层面功能完备,还体现在构建大型项目时是否具有低成本的依赖管理能力。
现在有许多用于依赖管理的工具,比如 Java
的 Maven
,Python
的 pip
,JavaScript
的 npm
/pnpm
/yarn
,以及 Rust
的 Cargo
。
每个包管理器
都需要一种方式来跟踪在当前项目中应该使用哪些版本的哪些软件包 。通常,会创建一个文件,将这些依赖关系映射到它们对应的版本上。比如,
JS
项目开发时,在根目录上会存在package.json
- 在
Rust
项目开发时,根目录下有Cargo.toml
我们今天的主角 -package.json
的主要作用是跟踪项目中所需的所有依赖关系 。当运行 JS 包管理器上的 install
命令时,它将安装在 package.json
文件中提到的软件包的相应版本。
定义命令&执行任务
这点大家都很熟,在现在前端开发中,尤其在SPA
模式开发下,我们通常会使用打包工具Vite/Webpack/rsPack
分别对开发模式
和生产模式
进行区分。要想实现上述操作。我们就需要在一个地方定义一些操作:执行命令
,并且能够在通过npm cli
命令行执行这些操作。
而这就是package.json
中scripts
的用途。我们可以定义很多操作然后执行诸如dev/build/prepare/postinstall
等命令。
这个是利用npm
的生命周期做一些资源整合的事情。这个我们会另写一篇文章。这里也不再多讲。
存储元数据
在如何在 npm 上发布二进制文件?中,我们同样有package.json
,它既不是用于依赖管理也不是用于定义项目命令,而是通过一些字段的配置来说明包的名称和版本信息,以及该包被用于那些操作系统和系统架构。
也就是说,
package.json
还可以存储必要的包的元数据。
2. package.json 中关键字段
创建package.json
我们可以使用 npm init
命令在任意我们想创建前端项目的文件夹中创建一个 package.json
文件。当我们运行该命令时,它会询问我们一系列的问题,我们输入的所有答案都会显示在我们的 package.json
文件中。
当我们填入我们想要的信息后,就会在项目的根目录下创建一个package.json
文件。
json
{
"name": "front789",
"version": "1.0.0",
"description": "专注于前端开发技术Rust及AI应用知识分享的Coder",
"main": "index.js",
"scripts": {
"test": "vitest"
},
"repository": {
"type": "git",
"url": "https://xxx/xxx"
},
"keywords": ["前端开发", "rust", "ai"],
"author": "front789 (https://xxx/xx)",
"license": "MIT"
}
当然我们也可以采用手动方式在项目根目录下创建一个
package.json
并填入必要的信息
如果大家看过package.json的官网的话,会发现有很多属性,并用它使用场景五花八门。
而今天我们也不打算把这些属性都过一遍,我会有选择的挑选一些对我们平时开发有用的属性来讲。
name
name
字段用于标识软件包。
json
{
"name": "my-project"
}
在 package.json
文件中,name
和version
是强制 的,它们一起被认为是唯一的。例如,如果name
是 f_cli
,version
是 0.1.0
,那么就假定f_cli@0.1.0
是唯一的,不指代任何其他软件包。
软件包name
也是有一定的限制的。
它需要符合
^(?:(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)?/[a-z0-9-._~])|[a-z0-9-~])[a-z0-9-._~]*$
正则规则
- 它不能超过 214 个字符,并且只能包含小写字母。
- 名称不能以点(
.
)或下划线(_
)开头。 - 此外,名称通常是
URL
的一部分,因此必须是URL
安全的。
软件包名称也可以是作用域(scope
)的。例如,软件包的名称可以是@front/f_cli
。这是@organization/package
的形式。但是这种形式时候需要花钱的。
如果将包发布到 npmjs
,则 name
属性是必需的并且必须是唯一的。如果使用和 npmjs
已经存在的名称发布包,将收到错误。
如果不将包发布到npmjs
,那么项目的name
字段就没有那么多要求。
version
json
{
"version": "1.1.0",
}
version
字段也是用于标识软件包的键。通常,此版本号必须是可由 node-semver 解析的。
语义化版本控制 (Semantic Versioning
,SemVer
)是一组用于版本控制的规则,以便版本号的更改表明软件包中的变化类型。
版本号以
MAJOR.MINOR.PATCH
的形式编写
- 如果新版本中有
错误修复
,则增加PATCH
。- 如果有
新功能
,则增加版本的MINOR
部分。- 如果新版本有
破坏性变化
或与旧版本不兼容
,则增加版本的MAJOR
部分。
例如,如果软件包的当前版本为 1.0.9
:
- 如果下一个发布仅包含
错误修复
,则新版本应为1.0.10
。 - 如果下一个发布包含
新功能
,则新版本应为1.1.0
。 - 如果下一个发布有
破坏性变化
,则新版本应为2.0.0
。
description
description
字段简要描述了软件包的功能 。它对于 SEO
也很有用,因为它帮助其他人可以在npmjs.com
网站上找到我们的软件包。当用户在npmjs.com
搜索包时,此字符串用于帮助显示包。
就像我们f_li_darwin_arm64
的包有如下的配置信息。
当我们在npmjs
中按照description
搜索时也会返回对应的结果。
即使我们没有将其发布到npmjs
,它也可以用作项目的说明书,来说明该项目的性质和功能。起到一个高屋建瓴的作用。
keywords
json
{
"keywords": ["f_cli", "MACOS_Intel64"]
}
keywords
字段是一个字符串数组 ,与 description
类似,keywords
字段也用于 SEO
。该字段由 npmjs
编制索引,用于帮助在有人搜索包时找到包。数组中的每个值都是与我们的包关联的一个关键字。
如果我们不发布到npmjs
,则此字段没有多大用处,可以随意省略它。
homepage
json
{
"homepage": "https://github.com/owner/project#readme"
}
通常,我们会在此字段中链接到项目的网站地址。或者,我们还可以指向项目的 README
或文档。
bugs
json
{
"bugs": {
"url": "https://github.com/owner/project/issues",
"email": "project@hostname.com"
}
}
当别人使用了我们的包,在遇到问题后可以依据这个字段提供的url
和email
来提出问题,并尝试在需要的地方寻找解决方案。
如果我们不想提供支持电子邮件,我们可以直接将 URL
分配给 bugs
属性。
json
{
"bugs": "https://github.com/owner/project/issues",
}
license
json
{
"license":"MIT"
}
license
是一个重要的字段,因为它向使用包的用户描述了我们在使用此软件包时设置的权限 和限制 。理想情况下,对于开源软件包,许可证应该是 OSI 批准的许可证之一。
下面是我们常见的OSI
软件开源协议。
许可证 | 版本 | 主要特点 |
---|---|---|
GNU通用公共许可证(GPL) | 2.0 | 允许使用、修改、复制和分发软件,要求在修改后的软件中保持相同的GPL许可协议。 |
3.0 | 强调数字版权管理(DRM)和专利许可,以保障开源软件的自由性和用户权益。 | |
MIT许可证 | - | 允许几乎所有情况下自由使用、修改、复制和分发软件,只要在软件和相关文档中包含原许可协议和版权声明。 |
Apache许可证 2.0 | - | 允许使用、修改、复制和分发软件,要求在分发时保留原始许可协议和版权声明,修改后的代码必须以某种形式标明更改。 |
BSD许可证 | 2-Clause | 允许自由使用、修改、复制和分发软件,要求在分发时保留原始许可协议和版权声明。 |
3-Clause | 在2-Clause BSD License的基础上增加了对使用软件名称、作者名称或衍生品的宣传中的责任免除条款。 | |
GNU宽通用公共许可证(LGPL) | 2.1 | 允许在自由和开源项目中使用该软件,并在修改后的库中使用不同的许可协议。 |
3.0 | 强调数字版权管理(DRM)和专利许可,适用于开源项目,并在修改后的库中使用不同的许可协议。 |
如果我们不希望在任何条件下向软件包的用户授予任何权限,可以将此字段设置为 UNLICENSED
。
如果这个项目是我们公司的项目,并且也不准备开源,应该将 package.json
文件中的 private
字段设置为 true
,以防止意外发布软件包。
author
author
字段用于提供有关软件包开发者的信息。它包括一个name
,以及一个可选的email
和 url
字段。
以下是一个示例:
json
{
"name": "front789",
"email": "xx@gmial.com",
"url": "https://xx.io"
}
所有这些信息也可以缩小成以下格式的单个字符串:
json
{
"author": "Name <Email> (Site)"
}
例如,我们可以使用此格式指定与上述相同的作者:
json
{
"author": "front789 <xx@gmial.com> (https://xx.io)"
}
contributors
与 author
字段类似,contributors
字段提供有关软件包开发者的信息。它包含一个作者数组。
files
files
字段是一个文件模式数组 ,描述当我们的包作为依赖项安装时要包含的文件。
文件模式遵循与.gitignore
类似的语法。唯一的区别是在.gitignore
中指定的文件被排除在外,而这些文件被包括在内。我们还可以使用像*
和**/*
这样的 glob
模式,就像在.gitignore
文件中一样。
如果未特别指定,则
files
字段默认为["*"]
。
我们可以在包的根目录或子目录中提供 .npmignore
文件,这将防止包含文件。 .npmignore
文件的工作方式与 .gitignore
类似。
一些特殊的文件和目录也会被包含,无论它们是否存在于 files
数组中。
- package.json
- README
- LICENSE / LICENCE
- 在
main
字段指定的文件 - 在
bin
字段指定的文件
其中README
和 LICENSE/LICENCE
文件可以具有任何扩展名。
main
json
{
"main": "src/index.js",
}
main
字段是 package.json
的功能属性。这定义了项目的入口点,通常也是用于启动项目的文件。
如果我们的软件包(假设其名称为 front789
)由用户安装,那么当用户执行 require('front789')
时,则将返回主模块的导出对象。
这通常是项目根目录中的 index.js
文件,但它可以是我们选择用作包的主入口
的任何文件。
如果未设置
main
,则默认为包根文件夹中的index.js
该字段在Node12+
有另外的替代方案 - exports
。
exports
我们可以使用 exports
字段定义软件包的入口点,作为 main
字段的替代方案。与 main
不同,exports
允许我们定义子路径导出
和条件导出
。
例如,我们可以使用以下 exports
属性导出项目的 submodule.js
文件:
json
{
"exports": {
".": "./index.js",
"./submodule.js": "./src/submodule.js"
}
}
还可以条件导出
- 具体取决于软件包的使用者是使用 require
还是 import
。
json
{
"exports": {
"import": "./index-module.js",
"require": "./index-require.cjs"
},
"type": "module"
}
条件导出
通常用于 ESM
软件包,以确保向后兼容性,因为 import
关键字只能在 ESM
中使用。
type
此字段描述了当前软件包中的.js
文件应该被视为 ESM
还是 commonjs
。我们可以为 ESM
设置module
类型,并为非ESM
软件包设置 commonjs
。
此外,我们还可以明确指定文件是否应该解释为 ESM
或 commonjs
,使用.mjs
扩展名表示 ESM
,.cjs
扩展名表示 commonjs
文件。
json
{
"type": "module"
}
browser
此字段用于表示软件包是否应在浏览器中使用,而不是在 Node.js
项目中使用,以取代 main
。当我们的软件包使用像 window
这样的浏览器API,在 Node.js
环境中不可用时,就会使用它。
bin
这个我们很熟,在如何在 npm 上发布二进制文件?中,我们在定义主包时,就使用了bin
字段。
bin
字段,该字段是命令名 到本地文件名的映射。
在某些情况下,npm
软件包需要安装到 PATH
中,以便它们可以在任何目录中直接由操作系统运行。bin
字段指定这些类似可执行文件的文件。
当此软件包全局安装 时,该文件将链接到全局 bins
目录内,或者将创建一个 cmd
(Windows
命令文件)来执行 bin
字段中的指定文件,因此可用于由 name
或 name.cmd
(在 Windows PowerShell
上)运行。
当我们在 bin
属性中有以下配置。
json
{
"bin": {
"c1": "./r1.js",
"c2": "./r2.js"
}
}
在全局安装此软件包(使用 npm install -g
)后,我们将能够直接从终端运行 c1
和 c2
等命令。
- 这在
unix-like
操作系统上内部创建了r1.js
文件到/usr/local/bin/c1
的符号链接,以及r2.js
到/usr/local/bin/c2
的符号链接。 - 在
Windows
上,会创建一个C:\\Users\\{Username}\\AppData\\Roaming\\npm\\c1.cmd
文件,该文件运行r1
脚本。
bin
属性提到的文件,都以shebang
语法#!/usr/bin/env node
开头,否则我们的操作系统将不会意识到该文件应在Node.js
环境中运行。
shebang
shebang
是一种在Unix/Linux
系统中用于指定脚本解释器的约定 。在Node.js
中,也可以使用shebang
来指定Node.js
作为脚本的解释器。在脚本文件的开头,添加类似于#!/usr/bin/env node
的行,告诉操作系统使用Node.js
来解释执行该脚本。
-
#!
:这是shebang
的起始标志,告诉操作系统下面的路径是解释器的路径。 -
/usr/bin/env
:这是一个用于在环境变量中查找解释器的工具。它允许你在不同系统上使用不同的解释器路径,而不是硬编码一个固定的路径。 -
node
:这是指定的解释器的名称。在这里,它告诉操作系统使用Node.js来解释执行脚本。
Node.js
的shebang行
告诉操作系统找到Node.js解释器
并使用它来执行脚本。这使得脚本可以作为可执行文件直接运行,而不必在命令行中显式调用Node.js
。
案例分析
还记得f_cli
的npm
版本吗。
我们在package.json
中的bin
字段定义f_cli_f
和bin/cli
直接的关系
并且在bin/cli
中使用shebang
指定node.js
作为脚本解释器。
repository
该字段来记录项目代码所在的地址。该字段是一个对象,它定义了源代码所在的 url
,以及它使用的版本控制系统类型。对于开源项目,大部分都是GitHub
,以 Git
作为版本控制系统。
json
{
"repository": {
"type": "git",
"url": "https://github.com/xxx/docs.git"
}
}
scripts
script
字段是package.json
中另一个功能性元数据
scripts
属性是一个包含我们可以使用 npm CLI
运行的脚本命令的字典 。其键是我们可以使用 npm run <scriptName>
运行的脚本,值是实际运行的命令。这些通常是终端命令,我们将其放入脚本字段中,以便我们可以记录它们并轻松地重用它们。
我们还可以指定在软件包生命周期的不同时间运行的脚本。例如,我们可以添加一个 prepublish
脚本,在软件包发布之前运行(当我们运行 npm publish
时)。
这是一个比较大的主题,我们打算另起一篇,详细介绍一下
dependencies
json
{
"dependencies": {
"A": "^4.16.4",
"B": "~1.7.4"
}
}
此处列出了我们的项目使用的所有依赖项。使用 npm cli
安装软件包时(npm install xxx@1.0.1
),会将其下载到我们的 node_modules/
文件夹中,并将添加到我们的依赖项属性中,并注明软件包的名称(xxx
)和安装的版本(1.0.1
)。
dependencies
字段是一个对象,以包名称作为键,以版本或版本范围作为值。从这个列表中,npm
知道当 npm install
在目录中运行时要获取和安装哪些包(以及什么版本)。 package.json
的 dependency
字段是项目的核心,它定义了项目所需的外部包。
我们在dependencies
中看到的脱字号 (^
) 和波形符 (~
) 是 SemVer 中定义的版本范围的表示法。
在语义版本控制中,版本号由三个数字组成,格式如下:
go
`主版本号.次版本号.修订号`
-
脱字符号(
^
)表示允许更新到最新的次版本号:^1.2.3
表示>=1.2.3
并且<2.0.0
的最新版本
-
波形符(
~
)表示允许更新到最新的修订号:~1.2.3
表示>=1.2.3
并且<1.3.0
的最新版本
所以简单来说:
^
用于锁定主版本号和次版本号~
用于锁定主版本号和次版本号及修订号
devDependencies
与
dependencies
字段类似,但适用于仅在开发期间需要而在生产中不需要的包。
例如,在前端项目中我们使用eslint/oxlint
进行代码规范处理,一旦应用程序部署并投入生产,我们就不再使用它。devDependencies
属性让我们明确指出生产中不需要哪些依赖项。
我们可以使用npm install --save-dev <package>
安装指定的包,并且将相关的包信息记录到dependencies
中。
但是呢,由于我们项目开发时,可以随意引入外部包,有的同学也会将在开会环境中起作用的包安装到dependencies
中。这样,无形中增加我们生产环境的外部资源容量。
为了解决这个问题,我们可以在生产环境中安装应用程序时,我们可以使用 npm install --production
仅安装 package.json
的 dependency
字段中列出的内容。
peerDependencies
peerDependencies
字段用于指定一个包依赖于其他包的特定版本。这是为了解决一种情况:当一个包(插件或库)希望与另一个包协同工作,但不希望将其作为直接依赖项安装。
当某个包 A 声明了它的 peerDependencies
,它实际上是在声明:"我期望运行时环境中会有某个包 B 的特定版本,但我不会直接将 B 包添加为我的依赖项,而是期望它由运行时环境或其他上层的包提供。"
以下是一个简单的示例,展示了 peerDependencies
的用法:
json
{
"name": "my-package",
"version": "1.0.0",
"peerDependencies": {
"some-other-package": "^2.0.0"
}
}
在这个例子中,my-package
依赖于 some-other-package
的版本,但它并没有将其添加到 dependencies
中。相反,它期望运行时环境或上层的包会提供符合 ^2.0.0
版本要求的 some-other-package
。
使用 peerDependencies
的主要目的是确保在整个项目中使用相同版本的某个包,以防止出现不一致的依赖关系导致的问题。这有助于确保包之间的协同工作,并降低由于版本不一致而引起的潜在问题。
peerDependenciesMeta
peerDependenciesMeta
字段用于提供 peerDependencies
的额外元数据信息,以帮助管理 peerDependencies
。
它是一个对象,key
是 peerDependencies
的名字,value
是关于这个依赖的额外信息。
比如:
json
{
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
}
}
这里对 react
这个 peerDependency
提供了额外的元数据:optional: true
。
这个 optional
键指明这个 peerDependency
是可选的,如果使用者没有显式安装它,也不会触发警告。
这比直接把依赖设置为 optionalDependencies
要好,因为这样所有的 peerDependency
都聚集在 peerDependencies
字段中,而不会分散在两个地方。
peerDependenciesMeta
还可以用于提供其他元数据,比如说明、地位等,以便更好地帮助使用者理解和管理 peerDependencies
。
bundleDependencies
bundleDependencies
字段用于指定将哪些依赖包打包到最终的发布包中。
比如:
json
{
"name": "example-package",
"version": "1.0.0",
"bundledDependencies": [
"lodash",
"moment"
]
}
这意味着当这个包被发布时,lodash
和moment
这两个依赖会被打包到发布包中,而不是作为外部依赖被安装。
bundleDependencies
的常见使用场景包括:
- 将核心业务逻辑相关的依赖打包起来,以控制版本和优化性能
- 将大体积的依赖打包,以减少安装时间
- 将易受破坏的依赖打包,以增强稳定性
使用bundleDependencies
需要注意:
- 打包的依赖无法被使用者覆盖更新
- 会增加发布包的体积
- 需要同步维护依赖版本
所以需要根据实际情况权衡利弊来决定哪些依赖适合打包。
optionalDependencies
当找不到或无法安装依赖项时,npm install
命令会退出并显示错误。如果特定软件包存在于 optionalDependencies
而不是其他任何依赖项列表/字典中,则可以阻止出现此情况。
在 package.json
中,optionalDependencies
字段用于指定哪些依赖可以被视为可选的。
例如:
json
{
"optionalDependencies": {
"xx": "^1.0.0"
}
}
这表示 xx
这个依赖是可选的,如果安装过程中无法满足,npm
会继续正常安装,只是发出警告。
optionalDependencies
和 dependencies
的区别在于:
dependencies
是必需的,如果安装失败会导致整个安装过程终止。optionalDependencies
是可选的,如果安装失败会发出警告但不影响整体安装。
optionalDependencies
的常见使用场景:
- 对某些特定平台的依赖,如
fsevents
主要用于 MacOS。 - 一些可提升性能但不是必须的依赖。
- 一些实验性特性相关的依赖。
使用 optionalDependencies
表示可选依赖,可以很好地提升使用者的安装体验,避免因为某些非核心依赖而导致整个安装失败。
还记得我们在发布f_cli
时候,通过optionalDependencies
来指定相关工作环境的二进制包吗。
publishConfig
我们可以使用此选项指定软件包是否应该是公开可访问的,以及软件包使用哪个标签发布。默认情况下,软件包是私有的,并且默认标签是 latest
。使用不同的标签,例如 beta
,允许用户使用npm install <package-name>@beta
安装软件包的特定版本。
在 package.json
中,publishConfig
用于配置发布这个包时的一些设置。
其中常见的配置有:
-
registry
: 发布到哪个注册表,默认是https://registry.npmjs.org/
-
tag
: 发布时添加的 tag,默认是latest
例如:
json
{
"publishConfig": {
"registry": "https://私有注册表网址",
"tag": "internal"
}
}
这意味着发布这个包时会发布到私有注册表,并打上 internal
的 tag。
publishConfig
的常见使用场景:
- 指定私有注册表,用于企业内部发布包
- 为预发布的版本添加特殊 tag,如
next
- 发布到不同注册表的同名包,用 tag 进行区分
所以 publishConfig
可以很好地自定义包的发布过程,将其发布到特定的注册表或添加自定义标签。
另外,发布过程还可以通过 npm publish
命令的 --tag
参数动态配置。
workspaces
workspaces
字段用于定义 monorepo
结构中的多个 package
。
例如:
json
{
"name": "monorepo",
"workspaces": [
"packages/*"
]
}
这表示packages
目录下的所有子目录都会被当作独立的 package,可以相互依赖和发布。
启用
workspaces
后,在根目录运行类似npm install
、npm run build
等命令,会自动在所有workspace
包中生效。
workspaces
的常见使用场景:
- 管理多个相关的包,让它们使用同一个git仓库和配置
- 共享依赖以优化安装大小
- 统一管理命令和脚本配置
与普通的多包管理相比,workspaces
可以减少重复工作,大幅简化 monorepo
开发。
需要注意的是,所有 workspace
需要遵循相同的npm
包规则,如版本控制、发布模式等,以减少管理负担。
这个选项在单体仓库中非常有用。我们可以以以下方式指定工作空间的列表:
json
{
"workspaces": [
"./packages/client",
"./packages/server"
]
}
我们可以在 client
和 server
目录中有单独的 package.json
文件,其中包含单独的脚本。运行 npm install --workspaces
将在两个目录中运行 npm install
。
实际上,我们可以使用--workspaces
命令在指定的所有工作空间中运行任何脚本。
例如,如果在 packages/client
和 packages/server
中有单独的 lint
脚本,在根 package.json
中,我们可以有一个 lint
脚本。现在,如果在根目录中运行 npm run lint --workspaces --if-present
,它将在所有具有 lint
脚本的工作空间中运行 lint
脚本。
--if-present
保证即使有些包没有 lint
脚本,也不会影响其它包的执行。
lock文件
在我们的 npm
项目中安装软件包时,通常会出现一个神秘的 package-lock.json
文件。
正如名称所示,package-lock.json
是一个锁定文件,即一个存储了使用的软件包及其所有依赖软件包的确切版本号的文件 。这包括在我们的 node_modules
目录中存在的所有软件包。
该文件的目的是确保所有依赖项在不同的机器上以相同的方式安装,从而保证项目在不同环境中能够一致工作。
package-lock.json
文件还包括每个软件包内容的加密哈希,这确保安装的软件包未被篡改,并且与软件包作者发布的确切相同的软件包。
当我们运行 npm install
时,npm
使用 package-lock.json
中的信息确定要安装的软件包的确切版本,并以与原始安装相同的顺序和相同的依赖项安装它们。
其他包管理器
尽管 npm
是最流行的包管理器之一,但很多人也使用其他包管理器,如 yarn
、pnpm
或 turbo
。这些包管理器中仍然存在 package.json
文件,但不同的包管理器可能使用不同的名称来命名锁文件
。例如,yarn
创建的 锁文件
称为 yarn.lock
,看起来类似于以下内容:
yaml
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
package-1@^1.0.0:
version "1.0.3"
resolved "https://registry.npmjs.org/package-1/-/package-1-1.0.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
package-2@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/package-2/-/package-2-2.0.1.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
dependencies:
package-4 "^4.0.0"
package-3@^3.0.0:
version "3.1.9"
resolved "https://registry.npmjs.org/package-3/-/package-3-3.1.9.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
dependencies:
package-4 "^4.5.0"
package-4@^4.0.0, package-4@^4.5.0:
version "4.6.3"
resolved "https://registry.npmjs.org/package-4/-/package-4-2.6.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
类似地,pnpm
生成一个称为 pnpm-lock.yaml
的 锁文件
。然而,所有这些 lockfile
的目的与 npm
生成的 package-lock.json
文件相同。
3. 总结
总的来说,package.json
是 Node.js
开发中使用的重要元数据文件。它有助于管理依赖关系
、自动化任务
并配置项目。该文件包含了项目名称、版本号、作者、许可证、依赖关系等基本信息。
通过使用 package.json
,我们可以轻松管理项目所需的依赖项,确保安装每个软件包的正确版本。这使得更容易维护项目并在必要时更新依赖项。
此外,它还可以用于自动化任务,如构建项目、运行测试和启动应用程序。这可以为我们节省时间和精力,使他们能够专注于项目的更重要方面。
最后,它允许我们将其项目发布到 npmjs
,使其他用户能够轻松安装和在自己的项目中使用该项目。
后记
分享是一种态度。
全文完,既然看到这里了,如果觉得不错,随手点个赞和"在看"吧。