每个前端项目中都有一个 package.json 文件,你了解它吗?花几分钟再重新审视一下这个熟悉的陌生人。
在项目文件夹下执行npm init -y
快速生成。 -y
代表一路 yes
。打开文件我们看到以下信息。
{ "name": "package-json", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
逐个介绍下上述字段:
name
包名称,必填项version
包版本,必填项description
包描述信息,一句话介绍这个包的用途main
包入口文件。require('package-json')
,相当于使用了包的index.js。 该字段在开发 npm 包时较为常见,身为切图仔的我们接触的不多。scripts
包执行脚本,常用的npm start
、 npm run dev
、 npm run build
都是注册在这里的。keywords
关键词与 description 类似,用于介绍包的用途author
包创建者license
包协议,用于规定是否开源、是否付费大部分开发者是围绕 web 开发进行工作的。我们来看看 web 项目的 package.json 常见配置字段 dependencies
、devDependencies
、private
、scripts
…
面试官:请讲讲
dependencies
和devDependencies
的区别?
简单,dependencies是生产环境的依赖,安装包时执行npm install -S xxx
;devDependencies 是开发环境的依赖, 安装包需要执行 npm install -D xxx
生产环境和开发环境指什么?如果不小心将 react 或 vue 这种依赖安装到 devDependencies
列表中项目还能运行吗?
就 web 项目而言,笔者认为dependencies
和devDependencies
的本质差异并不大。包安装在哪,项目都能正常的构建、运行。差异主要在于语义表达。
dependencies
往往是指打包构建后依赖包的代码会被打进产物中,在生产环境运行中是不可缺少的。
devDependencies
是指那些开发、构建过程中那些工具,如构建使用的webpack、代码检查的 eslint、代码转义的 babel 等都属于开发环境依赖。他们存在的目的是:帮助我们将开发的代码安全、便捷的转换成用户浏览器可执行的代码。
还有一点差异, npm install --production=true 不会安装 devDependencies
下的依赖的,只会安装dependencies
的依赖。一般没人会控制这个变量。
若package.json中设置了 "private": true
,npm 将拒绝发布它。
web 项目大多不需要提交到 npm 仓库,建议将 private
设为 true。
顺便一提 monorepo 热潮下,大家会将 monorepo 项目根目录的 private
设为 true,来避免哪个小伙伴误将整个目录发包
scripts
控制项目生命周期的脚本。想一下天天用的 npm run dev、npm run build、npm run lint都做了哪些事情。看看scripts配置便知。
如果想了解团队项目工程化实现,那么也建议从 scripts 配置入手,一点点读懂命令对应的脚本文件,你就是工程大佬了。
scripts
需要着重介绍的一点是命令钩子pre
、post
。钩子可以注册某命令的前置命令和后置命令。
写个例子吧:
{ "scripts": { "prexxx": "echo 'start~'", "xxx": "echo 'xxx running'", "postxxx": "echo 'end!'" } }
当我们执行 npm run xxx时会看到下面结果。prexxx
、postxxx
被自动执行。
用途:在commit之前执行 lint ,npm run dev之前自动为用户安装包等等~
想想还可以做哪些事情,欢迎讨论。
我们很难保证同事间的开发环境统一,例如不同开发者的 node 版本是不一致的,有人是8.x, 有人是10.x 有人是14.x。来个新人问一下你们 node 用什么版本,累不累。配置下 engines
吧
"engines": { "node": ">=12.10.0 <15" }
上述版本是我乱写,如果开发者的版本不符合要求控制台会报错引导用户去改正,避免了口口相传
之前介绍的字段,同样适用。有几个属性是包项目常用且有用的。
如main
、files
、bin
前文已经介绍过, 包的入口文件。默认是项目根目录下的index.js。
"main":"./lib/index.js",
如果你的包名是package-json, 当用户代码require('package-json')
时,相当于require了你包目录下的 ./lib/index.js
文件。
files
用于决定哪些文件被发布到 npm 仓库去。不在files中的文件,包的使用者是无法访问的,main
指向的文件也必须存在于这个列表范围内。
"files": [ "src", "dist/*.js", "types/*.d.ts" ],
命令行工具入口。当你的包提供了一个命令行工具时,你需要为命令行工具指定一个入口。命令名称和本地可指定文件的对应关系。可以参考看看vue-cli-service的源码
"bin": { "vue-cli-service": "bin/vue-cli-service.js" }
如果你细心的话会发现咱们项目下的node_modules/bin文件夹里有好多可执行文件。
对使用者来说:本地安装包的bin
下的可执行文件会被链接到 ./node_modules/.bin/
;全局安装包的bin
将会被软链到 /usr/local/bin
下。
当我们的项目作为一个包提供给别人使用时,开发者执行npm install
我们需要注意只有dependencies
会作为包的依赖安装,devDependencies
则会被忽略掉,讲到这里相信大家终于能理解什么是开发环境、什么是生产环境了。
开发包是需要注意不要误将生产依赖安装到devDependencies
中去,会导致你的用户跑不起来。
大家有时间看看自己项目的 package.json 都配了啥,上面没提到的配置的作用是什么?这里暂时不展开了。
建议:有什么工程上的疑问,自己先看项目配置文件,还不懂再咨询同事。不然可能会被喷~