这么久了,突然发现一个问题,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上了,然后别人就可以安装使用了。