如何读懂项目里面的package.json文件? | 客服服务营销数智化洞察_晓观点
       

如何读懂项目里面的package.json文件?

如何读懂项目里面的package.json文件?

package.json 是一个用于描述和配置项目的重要文件,其中包含了许多字段和选项,可以影响项目的构建、依赖管理、脚本执行等方面。

描述配置

name

定义项目的名称,不能以”.”和”_”开头,不能包含大写字母(这是因为当软件包在npm上发布时,会基于此属性获得自己的URL,所以不能包含非URL安全字符(non-url-safe)

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

version

如何读懂项目里面的package.json文件?

定义项目的版本号,格式为:大版本号.次版本号.修订号 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": "xxx",

另一种是对象形式:

"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 字段可以配置不同环境对应的模块入口文件,并且当它存在时,它的优先级最高

使用exports字段,您可以指定模块的不同导出路径,并控制在不同环境下(如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 项目可以设置 .npmrc enable-pre-post-scripts=true。

enable-pre-post-scripts=true

config

config字段用来配置scripts运行时的配置参数

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

// console.log(process.env.npm_package_config_port) // 3001

用户可以通过npm config set foo:port xxxx 命令来重写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",
  //   "packageManager": "pnpm@8.6.2",
  
  // npm: 使用 npm 作为包管理器。
// yarn: 使用 Yarn 作为包管理器。
// pnpm: 使用 pnpm 作为包管理器

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

也可以通过@ 来指定版本

发布配置

是和项目发布相关的配置

private

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

"private": 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: 发布包的访问级别。可能的值包括:
    1. public: 公开访问,所有人都可以访问。
    2. restricted: 限制访问,需要授权才能访问(通常需要设置特定的 npm 配置)。
    3. private: 私有包,不会发布到公共注册表(通常用于企业内部使用)。
  2. tag: 发布时的标签。默认情况下是 latest,表示推荐使用的稳定版本。您也可以指定其他标签,如 nextbeta,用于发布预览或测试版本。
  3. registry: 发布的注册表地址。默认情况下是 npm 的公共注册表 (https://registry.npmjs.org/),但您可以设置为其他私有注册表的地址。

使用场景

  • 私有包管理: 如果您在使用私有 npm 注册表或企业内部的包管理系统,可以通过 publishConfig 设置正确的注册表和访问级别。
  • 多版本控制: 对于具有复杂发布流程或多个稳定性级别的项目,使用不同的标签(如 nextbeta)可以帮助您管理不同版本的发布。

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"
     },
}

unpkg

unpkg 是一个用于提供 npm 包的 CDN(内容分发网络)服务,它允许您直接访问和使用 npm 上发布的包,无需安装到本地或者配置构建工具。

"unpkg": "dist/vue.js"

通过 unpkg,您可以直接在浏览器或 Node.js 中引入和使用 npm 包。假设您想要使用 lodash 这个包,可以通过以下方式在浏览器中引入:

<script src="https://unpkg.com/lodash"></script>

指定版本

也可以指定具体的版本号来加载包,例如:

<script src="https://unpkg.com/lodash@4.17.21"></script>

优势和适用场景

  • 无需安装依赖:直接通过 CDN 引入包,无需在本地安装 npm 包或配置构建工具。
  • 快速加载:利用 CDN 加速服务,包的加载速度通常很快。
  • 调试和学习:在浏览器中直接引入包,方便快速测试和学习新的库或工具。

jsdelivr

与 unpkg 类似

 "jsdelivr": "dist/index.min.js",

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% 的浏览器。

sideEffects

sideEffects 是一个用来告知 JavaScript 模块系统哪些模块是“有副作用”的标志。这个字段通常用于优化打包工具如 Webpack,在构建过程中决定是否可以安全地剔除未使用的模块。

sideEffects 字段可以是一个布尔值或者是一个字符串数组,用来指定哪些模块有副作用(即模块导入后会影响全局状态或执行代码),从而防止它们被打包工具过度优化(例如在生产环境下删除未使用的代码)。

false:表示所有模块都没有副作用,可以安全地进行无用代码删除优化。这在一些库和工具中很常见,因为它们的导入不会影响到全局状态。

true:表示所有模块都有副作用,无论是否使用。这在大多数应用程序中是默认的,因为它们的模块可能会动态导入或执行一些需要全局影响的操作。

字符串数组:列出具体有副作用的模块路径。例如:

{
  "sideEffects": [
    "./src/some-side-effectful-module.js",
    "./src/another-side-effectful-module.js"
  ]
}

使用场景

优化打包:在开发 JavaScript 应用程序或库时,使用 sideEffects 字段可以帮助打包工具更智能地处理模块的导入和优化,减少打包后的体积。

库和工具:对于一些导入但不直接使用的模块,可以显式地指定它们没有副作用,以帮助打包工具更有效地进行优化。

动态加载:当应用程序需要动态地加载模块时,sideEffects 字段可以帮助打包工具知道哪些模块可能被动态引入,以便进行适当的处理。

例子:

如果 Ant Design 的 package.json 里不设置 sideEffects,那么 webapck 构建打包时会认为这段代码只是引入了但并没有使用,可以 tree-shaking 剔除掉,最终导致产物缺少样式。

所以 Ant Design 在 package.json 里设置了如下的 sideEffects,来告知 webpack,这些文件具有副作用,引入后不能被删除。

"sideEffects": [
  "dist/*",
  "es/**/style/*",
  "lib/**/style/*",
  "*.less"
]

lint-staged

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

{
  "name": "my-package",
  "version": "1.0.0",
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "git add"
    ],
    "*.css": [
      "stylelint --fix",
      "git add"
    ],
    "*.json": [
      "prettier --write",
      "git add"
    ]
  },
  "scripts": {
    "lint-staged": "lint-staged"
  },
  "devDependencies": {
    "eslint": "^8.0.0",
    "stylelint": "^15.0.0",
    "prettier": "^2.0.0",
    "lint-staged": "^12.0.0"
  }
}

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能解决此类问题。

咨询方案 获取更多方案详情                        
(0)
研发专家-斑点狗研发专家-斑点狗
上一篇 2024年11月22日 上午10:20
下一篇 2024年12月4日

相关推荐