package.json持续解剖

175 阅读9分钟

这个文件用来描述项目及项目所依赖的模块信息,可以称得上是前端项目的大管家,从这个文件中,你可以看到很多有用的信息.可做到的事情如下

  • 版本控制
  • 依赖管理
  • 运行的任务
  • 等等

下面是一个字段信息比较全的package.json文件

{
    "name": "package-test-demo",
    "version":"0.0.1",
    "description": "this is a demo",
    "keywords":["node.js","vue", "js"],
    "homepage": "https://baidu.com",
    "bugs":{"url":"http://path/to/bug","email":"xx@xxxx.com"},
    "license": "ISC",
    "author": "zpp",
    "contributors":[{"name":"zpp","email":"xx@xxxx.com"}],
    "files": "",
    "main": "./dist/default.js",
    "bin": "",
    "man": "",
    "directories": "",
    "repository": {
    "type": "git",
    "url": "https://path/to/url"
  },
    "scripts": {
      "start": "webpack serve --config webpack.config.dev.js --progress"
    },
    "config": { "port" : "8080" },
    "dependencies": {},
    "devDependencies": {
        "@babel/core": "^7.14.3",
        "@babel/preset-env": "^7.14.4",
        "@babel/preset-react": "^7.13.13",
        "babel-loader": "^8.2.2",
        "babel-plugin-import": "^1.13.3",
        "glob": "^7.1.7",
        "less": "^3.9.0",
        "less-loader": "^9.0.0",
        "style-loader": "^2.0.0",
        "webpack": "^5.38.1",
        "webpack-cli": "^4.7.0",
        "webpack-dev-server": "^3.11.2"
    },
    "peerDependencies": {
        "tea": "2.x"
    },
    "bundledDependencies": [
        "renderized", "super-streams"
    ],
    "engines": {"node": "0.10.x"},
    "os" : [ "win32", "darwin", "linux" ],
    "cpu" : [ "x64", "ia32" ],
    "private": false,
    "publishConfig": {}
  }
 

配置说明脑图

配置解析

必须属性和描述信息

name

就是项目的名称

规则

  • name必须小于等于214个字符

  • 不能以._开头,不能有大写字母

  • 因为名称最终成为URL的一部分因此不能包含任何非URL安全字符

    不安全的URL字符

    • 空格" "
    • 大于小于号<>
    • 方括号[]
    • 花括号{}
    • 竖线|
    • 反斜杠``
    • 插入号^
    • 百分比%

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

version

version字段用于定义版本号。一般的格式是x.x.x, 并且需要遵循该规则

该标识符被认为是完全唯一的。每次发布时version不能与已存在的一致。

description

它是一个字符串, 用于描述当前项目的概况,方便用户直接了解包的功能。

keywords

keywords是标签,是一个字符串组成的数组, 用于标记当前项目的重点词汇。同时,可以作为搜索关键词,提供给资源平台使用,进行索引。

和description一样, 作用类似于做seo的时候增加权重,曝光率的

author

作者信息,支持两种形式,一种是字符串,一种是对象

"author": "you name"
// or
"author": {
  "name" : "you name",
  "email" : "xxxxx@xx.com",
  "url" : "xxxx"
}

contributors

表示该项目包的贡献者,是一个数组,数组字符串或者数据对象,描述贡献者信息

homepage

homepage就是项目的主页地址了,它是一个字符串。

bugs

bugs表示项目提交问题的地址,该字段是一个对象,可以添加一个提交问题的地址和反馈的邮箱:

"bugs": {

"url" : "[https://github.com/facebook/react/issues](https://github.com/facebook/react/issues)",

"email" : "[xxxxx@xx.com](mailto:xxxxx@xx.com)"

}

最常见的bugs就是Github中的issues页面,如上就是react的issues页面地址。

依赖配置

一般情况, 我们开发项目都会依赖多个外部依赖包,根据依赖包的不同用途,可以给他们配置到不同的属性下面,有五个相关属性, 它们的值都是一个对象。该对象的各个成员,分别由模块名和对应的版本要求组成,表示依赖的模块及其版本范围。

dependencies

声明的是项目的生产环境中所必须的依赖包

通常在安装依赖的时候 使用—save或者-S则表述将该依赖写入dependencies属性中

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

版本号再后面会说到,此处先不讲

devDependencies

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

使用—save--dev或者-D则表述将该依赖写入devDependencies属性中

peerDependencies

直观表述。如果你安装我,那么你最好也安装X,Y和Z.

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

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

例子:下方是一个myless库的package.json文件, 表示使用myless模块必须依赖less模块的3.9.x版本.


"name": "myless",
"peerDependencies": {
  "less": "3.9.x"

}

然后,你宿主环境的node_modules里面 其实是

YouProject
|- node_modules
   |- myless
   |- less

// 而不是这样
YouProject
|- node_modules
   |- myless
      |- node_modules
         |- less

peerDependencies的目的是提示宿主环境去安装满足插件peerDependencies所指定依赖的包,然后在插件import或者require所依赖的包的时候,永远都是引用宿主环境统一安装的npm包,最终解决插件与所依赖包不一致的问题。

注意,从npm 3.0版开始,peerDependencies不再会默认安装了。就是初始化的时候不会默认带出。

比如,在npm3.0的时候,你安装myless, 宿主环境下他不会强制强制安装less, 而是会给你一个警告, 大致如下

less是一个需要的依赖,但是没有被安装。  

还有个问题, 就是如果myless的peerDependencies所依赖的less升级版本了, 你需要手动去更新, 这个时候 启动项目的时候在控制台会有警告, 大概说是

npm Error.  myless requires a peer xxx.@xxx. ...之类的

optionalDependencies

如果需要在找不到包或者安装包失败时,npm仍然能够继续运行,则可以将该包放在optionalDependencies对象中,optionalDependencies对象中的包会覆盖dependencies中同名的包,所以只需在一个地方进行设置即可。 需要注意,由于optionalDependencies中的依赖可能并为安装成功,所以一定要做异常处理,否则当获取这个依赖时,如果获取不到就会报错

bundledDependencies

上面的几个依赖相关的配置项都是一个对象,而bundledDependencies配置项是一个数组,数组里可以指定一些模块,这些模块将在这个包发布时被一起打包。

需要注意,这个字段数组中的值必须是在dependencies, devDependencies两个里面声明过的包才行。

engines

engines字段指明了该模块运行的平台,比如Node或者npm的某个版本或者浏览器。

{ "engines" : { "node" : ">=0.10.3 <0.12", "npm" : "~1.0.20" } }

脚本配置

scripts

是 package.json中内置的脚本入口,用来执行脚本命令,简化输入,提高开发效率

config

config字段用来配置scripts运行时的配置参数,如下所示:

"config": {
  "port": 3000
}

钩子

npm钩子

npm run 为每条命令提供了 pre- 和 post- 两个钩子(hook)。以 npm run test 为例,如果我们的 scripts 字段规定了 pretest 和 posttest,两个钩子的含义分别是预执行、后执行

 prepublish:在打包和发布包之前运行,在npm install没有任何参数的本地运行
 postpublish:发布包后运行
 preinstall:包安装之前运行
 postinstall:包安装后运行
 preuninstall:在包卸载之前运行
 postuninstall:在包卸载之后运行
 preversion:在升级包版本之前运行
 postversion:在升级包版本之后,提交之后运行
 pretest:单元测试之前
 posttest:测试之后
 prestop:项目停止前
 poststop:停止运行后
 prestart:启动前
 poststart:启动后
 prerestart:重启前
 postrestart:重启后

脚本执行顺序

 //并行执行 &
 npm run hello.js & npm run world.js
 //串行执行,前一个成功才能执行后一个 &&
 npm run hello.js && npm run world.js

通过npm_package_前缀,npm 脚本可以拿到package.json里面的字段

{
  "name": "package.json",
  "version": "1.0.0", 
  "repostitory":{
     "type":"git"
  }
   "script":{
       "view":"echo $npm_package_repository_type"//bash获得打印出来
    }
}
//通过环境变量procss.env对象,拿到package.json的字段值
console.log(process.env.npm_package_name) //packages.json
console.log(process.env.npm_package_version) //1.0.0
console.log(process.env.npm_package_repository_type) // git

文件&目录

main

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

值是一个字符串

browser

browser字段可以定义 npm 包在 browser 环境下的入口文件。如果 npm 包只在 web 端使用,并且严禁在 server 端使用,使用 browser 来定义入口文件。

"module": "./src/index.js"

module

module字段可以定义 npm 包的 ESM 规范的入口文件,browser 环境和 node 环境均可使用。如果 npm 包导出的是 ESM 规范的包,使用 module 来定义入口文件。

"module": "./src/index.mjs"

需要注意, .js 文件是使用 commonJS 规范的语法(require('xxx')), .mjs 是用 ESM 规范的语法(import 'xxx')。

上面三个的入口入口文件相关的配置是有差别的,特别是在不同的使用场景下。在Web环境中,如果使用loader加载ESM(ES module),那么这三个配置的加载顺序是browser→module→main,如果使用require加载CommonJS模块,则加载的顺序为main→module→browser。

Webpack在进行项目构建时,有一个target选项,默认为Web,即构建Web应用。如果需要编译一些同构项目,如node项目,则只需将webpack.config.js的target选项设置为node进行构建即可。如果在Node环境中加载CommonJS模块,或者ESM,则只有main字段有效。

bin

bin字段用来指定各个内部命令对应的可执行文件的位置:

"bin": {
  "someTool": "./bin/someTool.js"
}

主要适用于开发脚手架或者开发包的时候,用于命令指令的配置

files

files配置是一个数组,用来描述当把npm包作为依赖包安装时需要说明的文件列表。当npm包发布时,files指定的文件会被推送到npm服务器中,如果指定的是文件夹,那么该文件夹下面所有的文件都会被提交。