浅析nodejs中的package.json和package-lock.json作用

一、package.json与package-lock.json文件的作用

1、package.json文件记录了你项目中所依赖的所有模块(只记录主模块)。

  当你执行 npm install 的时候,nodeJS 会先从 package.json 文件中读取所有 dependencies 信息,然后根据 dependencies 中的信息与 node_modules 中的模块进行对比,没有的直接下载,已有的检查更新(新版的nodejs不会更新,因为有package-lock.json文件)。

  另外,package.json文件只记录你通过npm install方式安装的模块信息,而这些模块所依赖的其他子模块的信息不会记录。

2、package-lock.json文件锁定所有模块的版本号,包括主模块和所有依赖子模块。

  当你执行 npm install 的时候,nodeJS 从 package.json 文件读取模块名称,从 package-lock.json 文件中获取版本号,然后进行下载或者更新。

  因此,正因为有了package-lock.json文件锁定版本号,所以当你执行npm install的时候,node不会自动更新package.json文件中的模块,必须用npm install packagename(自动更新小版本号)或者npm install packagename@x.x.x(指定版本号)来进行安装才会更新,package-lock.json文件中的版本号也会随着更新。

  附:当 package.json 与 package-lock.json 都不存在时,执行 npm install,nodeJS 会重新生成 package-lock.json 文件,然后把 node_modules 中的模块信息全部记入 package-lock.json 文件,但不会生成 package.json 文件,此时,你可以通过 npm init --yes 来生成 package.json 文件。

二、使用package-lock.json的必要性

1、遇到问题

  之前,在项目开发过程中遇到一个问题,同一个项目第一次 cnpm install 的时候还可以启动,过一段时间,把node_modules删掉,重新cnpm install,发现项目启动报错了。奇怪,项目代码和之前一样,一点都没改动。

  查其原因,发现是package.json文件的依赖模块版本号没有固定,如 "roadhog": "^2.5.0-beta.4"。这里有个 ^,安装的时候会安装2.x.x的最新版本,因为这期间该模块有更新,导致两次install的版本不一样,所以项目报错了。

2、解决办法

  第一个想到的是我把该模块写死不就行了 "roadhog": "2.5.0-beta.4"。但是仔细一想,仍会有问题。npm最方便的地方,是它可以帮我们管理依赖,自动下载依赖。意思是假如我们依赖roadhog,roadhog又依赖模块A、B等,我们安装roadhog时,npm会自动帮我们安装好roadhog依赖的模块A、B等。我们把roadhog锁死了,但是其引用的A模块仍用的是^括号写法(即没有锁死版本),所以假如A模块更新了,仍可能会出现之前类似的问题。那么该怎么进行版本控制呢。

  所以我们要对整个依赖树做锁定,那前后编译出来的应用版本就不会存在两次安装版本不一的问题了。

  这就引出了我们的 package-lock.json 文件。它的产生就是来对整个依赖树进行版本固定的(锁死)

3、package-lock.json定义

  引用官方解释:package-lock.json 它会在 npm 更改 node_modules 目录树或者 package.json 时自动生成的,它准确的描述了当前项目 npm 包的依赖树,并且在随后的安装中会根据 package-lock.json 来安装,保证是相同的一个依赖树,不考虑这个过程中是否有某个依赖有小版本的更新。

4、package-lock.json生成

  默认,当我们在一个项目中npm install时候(前提该项目有package.json文件),安装完成后,会自动生成一个package-lock.json文件(位置和之前的package.json文件同级)。该文件里面记录了package.json依赖的模块,以及依赖的依赖。并且给每个依赖标明了版本, 获取地址和哈希值, 使得每次安装都会出现相同的结果,不管你在什么机器上面或什么时候安装。

  当我们下次再npm install时候,npm发现如果项目中有package-lock.json文件,会根据package-lock.json里的内容来处理和安装依赖而不再根据package.json。

  如果 package-lock.json 已经生成,我再次更新 package.json 某个模块版本(包括手动更改package.json某个版本号,然后重新npm install或者类似npm install antd@3.15.0来更新某个模块),package-lock.json都会自动更新到之前设置的版本,所以不用担心 package.json 更新了,package-lock.json 还是旧的问题。npm v5.1.0之前存在该问题,npm v5.1.0以后不存在该问题。此同步功能是作为npm v5.1.0的一部分发布的,该版本于2017年7月5日上线。

5、cnpm不支持package-lock.json

  注意:使用cnpm install时候,并不会生成package-lock.json文件,网上搜cnpm维护者似乎并不打算支持该功能,具体大家可以去搜下。

  cnpm install 的时候,就算你项目中有 package-lock.json 文件,cnpm 也不会识别,仍会根据 package.json 来安装。所以这就是为什么之前你用 npm 安装产生了package-lock.json,后面的人用 cnpm 来安装,可能会跟你安装的依赖包不一致,这是因为 cnpm 不受 package-lock.json 影响,只会根据package.json进行下载。

6、package-lock.json 可能被意外更改的原因

(1)新增或者删除了一些包,但是没有及时 install

(2)挪动了包的位置:将部分包的位置从 dependencies 移动到 devDependencies这种操作,虽然包未变,但是也会影响 lockfiles,会将部分包的 dev 字段设置为 true

(3)registry 的影响:如果我们 node_modules 文件夹下的包中下载时的的 registry 与 lockfiles 中包即使 version 相同,但是registry是不同,执行 npm i 时也会修改。

  可能还存在其他的原因,但是 lockfiles 是不会无缘无故被更改的,一定是因为 package.json 或者 node_modules 被更改了,因为 正如上面提到的 lockfiles 为了能够精准的反映出我们 node_modules 的结构

三、package.json中 ^、~ 的区别

"dependencies": {
    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
},

  指定版本号:

1、指定版本。比如:"vue": "2.5.2",表示安装2.5.2的版本

2、波浪号 ~ + 指定版本。比如: "vue": "~2.5.2",表示安装2.5.x的最新版本(不低于2.5.2),但是不安装2.6.x,也就是说安装时不改变大版本号和次要版本号

3、^ + 指定版本。比如:"vue": "^2.5.2",表示安装2.5.2及以上的版本,但是不安装3.0.0,也就是说安装时不改变大版本号。

  简言之就是:什么都不加是指定版本;波浪号 ~ 是不改变次要版本,但升级小版本;^ 是不改变大版本,但升级次要版本。

四、package.json 文件

1、package.json 文件作用

  package.json 文件其实就是对项目或者模块包的描述,里面包含许多元信息。比如项目名称,项目版本,项目执行入口文件,项目贡献者等等。

  npm install 命令会根据这个文件下载所有依赖模块。

2、package.json 文件创建

  package.json 文件创建有两种方式,手动创建或者自动创建。

(1)手动创建:直接在项目根目录新建一个 package.json 文件,然后输入相关的内容。

(2)自动创建:也是在项目根目录下执行 npm init,然后根据提示一步步输入相应的内容完成后即可自动创建。

3、package.json 文件配置说明

name:项目/模块名称,长度必须小于等于214个字符,不能以"."(点)或者"_"(下划线)开头,不能包含大写字母。
version:项目版本。
author:项目开发者,它的值是你在https://npmjs.org网站的有效账户名,遵循“账户名<邮件>”的规则。
description:项目描述,是一个字符串。它可以帮助人们在使用npm search时找到这个包。
keywords:项目关键字,是一个字符串数组。它可以帮助人们在使用npm search时找到这个包。
private:是否私有,设置为 true 时,npm 拒绝发布。
license:软件授权条款,让用户知道他们的使用权利和限制。
bugs:bug 提交地址。
contributors:项目贡献者 。
repository:项目仓库地址。
homepage:项目包的官网 URL。
dependencies:生产环境下,项目运行所需依赖。
devDependencies:开发环境下,项目所需依赖。
scripts:执行 npm 脚本命令简写,比如 “start”: “react-scripts start”, 执行 npm start 就是运行 “react-scripts start”。
bin:内部命令对应的可执行文件的路径。
main:项目默认执行文件,比如 require(‘webpack’);就会默认加载 lib 目录下的 webpack.js 文件,如果没有设置,则默认加载项目跟目录下的 index.js 文件。
module:是以 ES Module(也就是 ES6)模块化方式进行加载,因为早期没有 ES6 模块化方案时,都是遵循 CommonJS 规范,而 CommonJS 规范的包是以 main 的方式表示入口文件的,为了区分就新增了 module 方式,但是 ES6 模块化方案效率更高,所以会优先查看是否有 module 字段,没有才使用 main 字段。
eslintConfig:EsLint 检查文件配置,自动读取验证。
engines:项目运行的平台。
browserslist:供浏览器使用的版本列表。
style:供浏览器使用时,样式文件所在的位置;样式文件打包工具parcelify,通过它知道样式文件的打包位置。
files:被项目包含的文件名数组。

posted @ 2021-03-31 17:37  古兰精  阅读(1093)  评论(0编辑  收藏  举报