package.json
天天见,知道个scripts
、dependencies
,但真的还不算认识它!这两天因为想分享一些小工具,发个包啥的,所以就整理了关于package.json
的一些基础知识,现在我反正是正儿八经的认识package.json
了,如果像以前的我一样跟它不是很熟的朋友可以看下。
package.json字段
包的描述性配置
name(必须属性)
表示发布后的包名
至于以@xxx/
开头的name
字段,表示这是一个作用域包,原因是为了防止包名重复的一种解决方案,类似于创建了一个命名空间,不同的命名空间,可以使用相同的包名,作用域的命名不是随便起的,只有两种可以使用:自己的用户名、自己创建的组织名。举个具体的例子,@vue/cli
这个包说明使用了vue
这个npm
账号或者组织发布了该包。
version(必须属性)
表示包的版本号。
如果项目是为发布npm包,则必须包含此字段。如果是普通的项目,则此字段是可选的。
每次发布的version
,必须是唯一的,之前发布的时候没使用过的。
description
值即对此包的概述。
keywords
功能类似于description
,npm平台上展示的关于此包的一些关键词
"keywords": [
"vue",
"react",
"next"
]
homepage / repository
项目的官网主页地址 / 项目的源码地址。
也算是描述性信息罢了。
author
作者信息。
"author": {
"name": "leon",
"email": "582104384@qq.com",
"url": "https://wangxiaokai.vip"
}
contributors
协作者信息。
格式是一个对象数组。对象内容和author
一致。
"contributors": [{
"name": "hanmeimei",
"email": "hanmeimei@qq.com"
},{
"name": "lihua",
"email": "lihua@qq.com"
}]
license
这个表示此开源项目使用的开源协议。如:
"license": "MIT",
这里浅谈一下开源协议相关的内容,开源协议概括来说,开源协议本质就是:
- 法律合同
- 非签署的、使用即默认同意
- 开源=开放代码≠无版权≠免费
然后生活场景中来讲就是某个开源项目使用了某种开源协议,是针对以后使用这个项目的用户进行要求,比如GPL协议(linux,乌班图等开源项目使用),他就要求如果你用我的源代码,你的项目就必须遵守我的开源协议里的要求。
选择开源协议的依据(说白了就是你希望别人用的源代码时要满足的要求):
总结来说,就是MIT协议是对商业最友好的,直白点说就是限制最宽松的。
功能性配置
files
files是一个文件数组,描述了将软件包作为依赖项安装时要包括的条目。如果在数组里面声明了一个文件夹,那也会包含文件夹中的文件。某些特殊文件和目录也被包括或排除在外,无论它们是否存在于文件数组中。
简而言之,别人下载我们的包所包含的文件。
比如dance-ui
里只设置了dist
文件夹
"files": [ "dist" ],
main
别人使用npm包时,如果通过require()
的方式引入包。那么就会查看main
字段,作为包的主入口文件。
module
性质等同于main
字段。module
用于ES6规范的模块,只要支持ES6,会优先使用module
入口。换句话说别人通过import
的方式引入我们的包时,实际上寻找的模块就是module
字段指定的文件。
exports
用来指定脚本或子目录的别名。
概念比较抽象,来个例子就ok了:
首先package.json
中配置如下
"exports": {
"./submodule": "./src/submodule.js"
}
exports
里面的即为别名(供用户使用): 实际路径
的键值对,如下
import submodule from 'es-module-package/submodule';
// 等价于加载 ./node_modules/es-module-package/src/submodule.js
解释一下:exports
里面键值对里,不管是键还是值,都把.
视作包名,类似于一种参照,上面配置"./submodule": "./src/submodule.js"
的含义就是用户引入资源时如果路径写(包名)/submodule
那么就转换为(包名)/src/submodule.js
。
关于这个配置,还有很多更高级的用法,可以参考阮一峰老师的es6
bin
工具性质的npm包,一定有bin
字段,对外暴露脚本命令。
比如webpack-cli
为我们在命令行提供了webpack
命令进行打包,看了下它的package.json
:
"bin": {
"webpack-cli": "./bin/cli.js"
},
scripts
太熟了,就是配置一些项目操作的自动化脚本。
dependencies、devDependencies、peerDependencies
dependencies非常熟了,就是我们项目安装的直接依赖。
devDependencies与dependencies的区别就是dependencies里的依赖最终是作为项目代码的一部分(有助于功能的实现);而devDependencies里的依赖是参与项目代码实现的,比如webpack这种构建工具就属于项目的devDependencies,以为它的作用是对开发完成的项目代码进行后期处理。
peerDependencies感觉就是为了服务于发包的,就比如我们的这个库要发包,然后可以通过peerDependencies给安装我们包的用户一些提示,比如我们的包配置如下:
"peerDependencies": {
"react": ">=16.8.0"
}
那么安装我们包的用户的项目如果react的版本不满足要求,控制台就会给警告。这也就是我们安装一些依赖时控制台经常会报peerDependencies警告的原因,就是因为我们安装的这个包,他本身对一些依赖有版本要求,我们项目里的依赖版本不符合要求。
types
项目如果是用TypeScript
写的,则需要types
字段,对外暴露相关的类型定义。比如dance-ui(ts编写的react组件库)
项目:
"types": "./dist/index.d.ts",
猜测这就是某些开源库对类型支持友好的原因吧(因为导出了.d.ts
文件)
workspaces
对于monorepo架构的项目(现在的工具库主流架构,不知道的朋友建议去补补课,很有意思),有必要配置workspaces
指明所有子项目的工作目录(子项目根目录),这样应该才支持各个子项目之间作为依赖互相安装使用。这个配置毕竟不是个性化配置,子项目有啥配啥就完事了,反正肯定就能保证项目的正常工作了,比如packages
文件夹下的所有(直接)子文件夹都是子项目(支持使用通配符,*
表示直接文件夹,不包含嵌套文件夹):
"workspaces": [
"packages/*"
],
发布相关的配置
private
private
和发布npm包相关。
当private: true
时,npm会拒绝发布当前项目。这是防止意外发布个人仓库的一种保护方式。
看了下,公司里的业务项目都设置了这个字段为true
。(发布出去怕是会犯法😂)
我试了一下,private
设置为true
之后即使设置了publishConfig
字段是不生效的,一些文档(官方)与文章中写到publishConfig
可以搭配private:true
然后成功发包,我不理解啊!chatgpt很肯定的告诉我:private
设置为true
之后是铁定发不出去包的,他没摇摆,我很感动。
publishConfig
这个配置项是一个对象,里面有registry
、access
、tag
三个比较常用(我感觉够用)的字段
registry
:对应我们的包的下载地址(npm源),我们发包的时候就会把包发到这个源里,比如我们可能因为嫌npm慢然后把registry
设置为国内的一些镜像源,这个字段不设置的话应该默认就是https://registry.npmjs.org/
(不然怎么会发到npm上呢哈哈)access
:默认值就是public
,表示我们的包是开放的,大家都可以下载,然后还有个取值restricted
,我试着发布了一下,失败了,好像要求包必须是一个作用域包(作用域包相关看name字段),感觉这个access
和registry
一样,都用默认值就完事了(发包的初衷不就是发布到npm,并且让所有人都能用么😁)tag
:默认值是lastest
,表示最新,说白了这玩意有点像git commit
的-m
,登录到npm查看发包历史,每次发布都能看到有个tag
字段。
跟三方库相关的配置
sideEffects
sideEffects
格式:boolean | string[]
。
sideEffects: false
用于告知打包工具(webpack),当前项目无副作用
,可以使用tree shaking
优化。
sideEffects
的值,也可以是一个文件路径组成的数组。告知哪些文件有副作用
,不可以使用tree shaking
优化。
"sideEffects": [
"a.js",
"b.js"
]
并且,由于tree shaking
只在production
模式生效,所以本地开发会一切正常,生产环境很难及时发现这个问题。
当然, 样式文件使用"import xxx;"
的方式引入,会进行保留。
上面是这篇文章里的描述,但是原文有一定的错误,已经进行了修正,并且我谈下我对sideEffects
的理解:生产模式下,webpack
打包时会开启tree-shaking
,本质上就是webpack
对程序打包的一种优化手段,但是tree-shaking
要保证程序的正确运行为前提,所以一段代码该不该被tree-shaking
掉,本身有一定的判断逻辑,所以sideEffects
字段就是辅助webpack
去进行tree-shaking
的,如果设置为false
,就表示项目里没有那种一定存在副作用的代码文件,所以可以走webpack
本身的tree-shaking
逻辑,但是如果sideEffects
里面指定了一些存在副作用的代码文件,那么就说明这些文件如果被引用,即使webpack
本身的逻辑判断他们没有副作用,可以被删除掉,那么也会因为sideEffects
的配置而被保留,所以算是一个webpack
进行tree-shaking
的辅助配置。
其它
还有一些如babel、eslint、gitHooks等相关的配置,作者现在还没用到,感兴趣的参考这篇文章
发包
这就比较简单了,对于拥有package.json
文件的项目(或者不是项目...),npm login
登陆上我们的npm
账号后,执行npm publish
就完事了,完全依据我们配置的package.json
,就把代码上传到npm
上了,然后别人就可以安装使用了。