代码共享方案
- 方案一:上传到GitHub上,其他程序员通过GitHub下载我们的代码手动的引用
- 缺点是大家必须知道你的代码GitHub地址,并且从GitHub上手动下载
- 需要在自己的项目中手动的引用,并且管理相关的依赖
- 不需要使用的时候,需要手动删除相关的依赖
- 当遇到版本升级或者切换时,需要重复上面的操作
- 方案二:使用一个专业的工具来管理我们的代码
- 我们通过工具将代码发布到特定的位置
- 其他程序员通过工具来安装,升级,删除我们的工具代码
npm
- 包管理工具npm
- Node Package Manager,也就是Node包管理器
- 如何下载和安装npm工具呢?
- npm属于node的一个管理工具,所以我们需要先安装Node
- node管理工具:https://nodejs.org/en/,安装Node的过程会自动安装npm工具
- npm管理的包可以在哪里查看、搜索呢?
- npm管理的包放在哪里?
- 我们发布自己的包是发布到registry上的
- 安装一个包也是从registry上面下载的包
npm的配置文件
- 对于一个项目来说,如何使用npm来管理这么多包呢?
- 每一个项目都会有一个对应的配置文件
- 这个配置文件会记录着你项目的名称、版本号、项目描述等
- 还记录着你项目所依赖的其他库的信息和依赖库的版本号
- 这个配置文件就是package.json
- 如何得到这个配置文件?
- 方式一:手动从零创建项目,npm init -y
- 方式二:通过脚手架创建项目,脚手架会帮助我们生成package.json,并且里面有相关的配置
常见的属性:
- 必须填写的属性:name、version
- name:项目的名称
- version:当前项目的版本号
- description:描述信息,很多时候作为项目的基本描述
- author:作者相关信息
- license:开源协议
- private属性:
- private属性记录当前的项目是否是私有的
- 当值为true时,npm是不能发布它的,这是防止私有项目或模块发布出去的方式
- main属性:
- 设置程序的入口
- 比如我们使用axios模块 cosnt axios = require(“axios”)
- 如果有main属性,实际上是找到对应的main属性查找文件的
- 设置程序的入口
- scripts属性
- scripts属性用于配置一些脚本命令,以键值对的形式存在
- 配置后可以通过npm run命令的key来执行这个命令
- npm start和npm run start是等价的
- dependencies属性
- dependencies属性指定无论开发环境还是生成环境都需要依赖的包
- 通常是我们项目实际开发用到的一些库模块
- 与之对应的是devDependencies
- 执行 npm install 会按照该属性自动下载一份依赖包
- devDependencies属性
- 一些包在生成环境是不需要的,只在开发环境需要,比如webpack、babel等
- 这个时候我们会通过 npm install webpack --save-dev,将它安装到devDependencies中
- peerDependencies属性
- 还有一种项目依赖关系是对等依赖,也就是你依赖的一个包,它必须是以另外一个宿主包为前提的
- 比如element-plus是依赖vue3的,ant-design是依赖于react、react-dom
npm依赖的版本控制
- npm依赖版本的管理都是通过package.json文件实现的
- 当你使用npm安装一个包或者更新一个包时,package.json就会自动添加一条信息,包括包名和版本号
- 版本号通常由三个部分组成:主版本号、次版本号和补丁号,例如1.2.3中的1是主版本号,2是次版本号,3是补丁号
- 次版本号:是软件的次要更新,意味着软件添加了新的功能,一般保持向后兼容
- 主版本号:当你做了不兼容的API修改(大版本更新)
- 补丁号:当你做了向下兼容的问题修正(没有新功能,修复了之前版本的bug)
- 插入号(^):表示主版本固定的情况下,更新到最新版本
- 波浪号(~):表示主版本和次版本固定的情况下,更新到最新版本
- 无符号:表示固定版本
- npm默认安装最新版本,并在其版本号之前添加^符号,因为使用任何相同大版本的更高级版本都很安全
npm常用命令参数
- 全局安装 -g
- 生产依赖 -s:该参数可以省略
- 开发依赖 -D
- 可选依赖 -O
- 精确版本 -E
npm的问题
嵌套问题(至今仍存在)
- npm发布最初(v1),采用的是嵌套结构,即项目依赖的依赖包又依赖其他依赖包,导致整个依赖树的层级过深
- 早期的npm是嵌套部署依赖的dependencies的,这将造成依赖重复下载和嵌套层次过深的问题
- npm在v3版本(此时yarn发布了),采用扁平化结构,一定程度上解决了嵌套问题
- 至今为止npm(v9),npm仍然没有彻底解决嵌套问题,
下载速度慢
- npm发布最初(v1),采用的是同步下载,下载速度慢
- v3启用多线程并行下载
- v5 借助lock文件缓存依赖信息实现缓存加载而非重新下载,但在速度上,还是有点慢
lock文件
-
早期的npm没有lock文件,导致依赖结构不确定,给程序带来不可预知的问题
-
package-lock.json用于记录当前安装的每个包的确切版本号以及其依赖关系的锁定状态
-
为什么需要package-lock.json?
- 我们通过package.json来管理项目的依赖,默认情况下主版本号不变升级到最新版本,这样会导致如果长时间不执行npm install,不同团队成员将使用不同版本的依赖
- 锁定依赖关系:确保每次安装相同的依赖包时会得到相同的版本,否则可能存在兼容性问题
- 更快速的安装:当package-lock.json存在时,npm会使用其中记录的下载地址直接从缓存中获取软件包,无需重新下载
- 精确控制:package-lock.json文件中包含软件包所需的所有子依赖项以及版本号,可以确保项目在复制或部署到其他环境时能够精确
所以,package-lock.json 文件应该被纳入源代码管理工具(如Git)进行版本控制,从而确保团队成员、构建服务器或其他人在构建和部署项目时都使用相同的软件包版本。
-
package.json 和 package-lock.json 之间的相互关系?
-
在构建依赖树时,会先检查下项目中是否有package-lock.json文件
-
存在lock文件的话,会判断lock文件和package.json中使用的依赖版本是否一致,如果一致就使用lock中的信息,反之就是使用package.json中的信息
-
如果没有lock文件的话,就会直接使用package.json中的信息生成依赖树
相同依赖下载多次
- 如果A、B两个依赖包都依赖于最新的C,此时A、B中的node_modules中都会下载一份C的最新版本依赖
- 如果我们项目中100个依赖都使用C同一版本,这将极大的占用我们的内存
yarn
为了解决npm的问题,Facebook发布了yarn,具有以下优点(npm借鉴了yarn的lock,缓存)
- 缓存,yarn会缓存所有安装的包
- 并行下载,有效的提升下载速度
- 锁定依赖版本,package.json配合yarn.lock文件确保不同机器安装相同的依赖
- 扁平化结构
现如今,yarn相比于npm最大的优点可能是安装快一点
pnpm
pnpm解决了npm、yarn的扁平化结构问题,高性能npm具有如下优点:
- 节省磁盘空间:相同版本的包不再重复安装
- 安装速度快:安装过的依赖会复用缓存,甚至包版本升级带来的变化都只 diff;同时相同版本的包不再重复安装
- 权限严格:非扁平结构,因此代码无法对任意软件包进行访问
- pnpm store:内置了仓库,包含多个软件包的支持