Package.json

关于Package.json的一点注意

1. 起因

现在基本上所有的前端组件代码仓库,无论是打包工具还是组件的依赖包都需要有package.json这个文件,虽然每天在接触的package.json,但是我猜能一口气把常见的配置说出来是个什么鬼的人并不是大部分,所以有机会都可以了解下。

很多人有时候会很偷懒,在新建一个工程的时候习惯把把前一个工程的的package.json直接拷贝过来,虽然很多时候并没有太大的影响,但这也太随意的。

  1. 很多npm包在使用的时候并不需要,额外包给项目初始化的时候耗费时间(大部分虽然影响只有一次)
  2. 有些组件包package.json错误的使用,会让其他引用它包可能都带来问题
  3. 有些字段类似name、version、publishConfig、homepage、bugs、repository对应那些要上传至npm的包则是需要严格要求的
  4. 组件的依赖关系在package.json中不能在dependencies、devDependencies、peerDependencies随便放

2. 几个字段的说明

2.1 version

版本号,对于那些发至npm的组件,要非常注意,一般都是使用语义化版本号来命名,

2.2 scripts

这里可以定义一些脚本的处理,比如本地启一个server的时候或者是使用一些打包,比如browserify的打包,有些人习惯用gulp或者是grunt来进行打包,但是还有一部分是是用npm-script进行打包的,这样适合那些对打包的配置想有跟多的掌控,但是代价就是会更复杂

npm官方关于npm-scripts一些描述,有一点就是除了那些特定的script可以直接npm ** 运行,其他的需要使用npm run ** ,比如我们对仓库代码要进行打包我们定义一个build,他默认会提供俩钩子,分别是pre & post

1
{
	"scripts":{
		"prebuild": "echo 'prebuild'",
    	"build": "echo 'build' ",
    	"postbuild": "echo 'afterbuild' "
	}
}

这样运行npm run build,就会同时跑以上的三个任务

2.3 main

main字段配置一个文件名指向模块的入口程序,比如你的入口文件是放在lib/index.js,有俩种做法,一种是在main中定义

1
{
	"main" : "lib/index.js"
}

方法二则是在根目录下建一个index.js里面则是

1
module.exports = require('lib/index.js');

2.4 dependencies、devDependencies、peerDependencies

2.4.1 dependencies

当前包强依赖的三方包

2.4.2 devDependencies

当前包开发或者测试依赖的三方包

在本地的开发使用过程中dependencies和devDependencies并没有太大的区别,但是一旦发布到npm包,这就会有差别,作为npm 的包在install的时候不会安装devDependencies的依赖

2.4.3 peerDependencies

举个列子,当包A和包B同时依赖了模块C,而且比较悲剧的事情俩C的版本却不一样,无论是npm3还是npm2都是会将俩版本的模块C都安装,这个时候可以在peerDependencies指定模块c的版本

注:在npm3版本之前定义在peerDependencies也会自动安装,但是在npm3中则不会,他仅仅只是有一个提示

3. 使用中注意的几点

3.1 react及react-dom

关于react以及react-dom在package.json中,应该如何放置呢?

3.1.1 从含义上来说

对应某个组件,react及react-dom确实是一个组件实际依赖的部分,按照这个逻辑是应该放到dependencies应该是更为合理,但是问题来了,如果包内外依赖的组件版本不一致的时候,会同时引入两份react,这个浏览器端会报错,,而且react本事并不小。虽然这个问题可以通过webpack中配置来解决,最终在页面中引入一份js即可,但是这样的话需要所有用你组件的同学用这样的打包方式,不太合适

1
{
 	externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    }
}

3.1.2 使用中

当初@何道同学提起了这个问题,我于是去喵了喵现在的组件包中对react及react-dom的引用。

  1. 比如react-component/slider的使用方式则是使用了devDependencies,尴尬的问题就是如果我外面没有引用react,在npm安装的时候并不会安装,(虽然在使用的场景中,外部引用组件的仓库肯定会用引用react),略尴尬
  2. 比如reactjs/react-redux,他的使用方式是在peerDependencies中定义了react及react-dom的引用,其实这个是个人觉得更加合理的方式,但是很不幸的问题是在npm3之前这个是完全没问题的,而在npm3中则不会自动安装,只是一个提示,在本地开发有点尴尬

纠结了很久,后来看到了这个文章,嗯脑补了下确实如此,感觉比较合理的方式是将react及react-dom的依赖同时定义在devDependencies、peerDependencies,这样貌似看起来本地开发,包发布俩不误,注意在peerDependencies中可以将依赖的组件版本定的更为宽泛点

1
{
	"peerDependencies": {
    	"react": "^0.14.0 || ^15.0.0",
    	"react-dom": "^0.14.0 || ^15.0.0"
  	},
  	"devDependencies": {
    	"react": "^0.14.0",
    	"react-dom": "^0.14.0"
  	}
}

3.2 版本号

一般不太建议将版本号写的太死,也不能太随性,关于~和^差别不一样,要注意区分

1
"async": "~0.9.0",
"async": "^0.9.0"

4. 其他

4.1 npm2 vs npm3

  1. 安装速度:npm3安装速度完虐npm2,一般安装npm3还是比较安静的,但是安装一个npm2基本上pro可以烧开一壶水了
  2. npm3在安装的时候会将你的所有依赖的一样的版本号的包进行抽离出来,打平到最外层,这个感觉对提示效率还是蛮明显的,但是想想对于一个包来说,更加对的方式应该还是安装到相应的组件包的folder下面,这样的做法有一个就是,有时候不小心require一个模块,但是package.json中没有定义,在npm3中还是会正常工作,因为有可能那个模块被他引的模块给引入,因为npm3的包打平放到了最外层

4.2 参考

  1. What’s the difference between dependencies, devDependencies and peerDependencies in npm package.json file?
  2. npm package.json